From cdfdffc274fb0c09c5df3a0410a239770527890c Mon Sep 17 00:00:00 2001 From: Sascha Date: Wed, 11 Dec 2024 13:41:55 +0100 Subject: [PATCH] configure docker --- psets/9/finance/.idea/dataSources.xml | 12 + psets/9/finance/.idea/misc.xml | 6 + psets/9/finance/.idea/vcs.xml | 6 + psets/9/finance/Dockerfile | 10 + .../9/finance/__pycache__/app.cpython-312.pyc | Bin 0 -> 11942 bytes .../__pycache__/helpers.cpython-312.pyc | Bin 0 -> 2698 bytes psets/9/finance/app.py | 19 +- psets/9/finance/docker-compose.yml | 25 + psets/9/finance/env/bin/Activate.ps1 | 247 + psets/9/finance/env/bin/activate | 70 + psets/9/finance/env/bin/activate.csh | 27 + psets/9/finance/env/bin/activate.fish | 69 + psets/9/finance/env/bin/automat-visualize | 8 + psets/9/finance/env/bin/flask | 8 + psets/9/finance/env/bin/normalizer | 8 + psets/9/finance/env/bin/pip | 8 + psets/9/finance/env/bin/pip3 | 8 + psets/9/finance/env/bin/pip3.12 | 8 + psets/9/finance/env/bin/python | 1 + psets/9/finance/env/bin/python3 | 1 + psets/9/finance/env/bin/python3.12 | 1 + psets/9/finance/env/bin/sqlformat | 8 + psets/9/finance/env/bin/wheel | 8 + .../site/python3.12/greenlet/greenlet.h | 164 + .../Automat-24.8.1.dist-info/INSTALLER | 1 + .../Automat-24.8.1.dist-info/LICENSE | 21 + .../Automat-24.8.1.dist-info/METADATA | 199 + .../Automat-24.8.1.dist-info/RECORD | 40 + .../Automat-24.8.1.dist-info/REQUESTED | 0 .../Automat-24.8.1.dist-info/WHEEL | 5 + .../Automat-24.8.1.dist-info/entry_points.txt | 2 + .../Automat-24.8.1.dist-info/top_level.txt | 1 + .../MarkupSafe-3.0.2.dist-info/INSTALLER | 1 + .../MarkupSafe-3.0.2.dist-info/LICENSE.txt | 28 + .../MarkupSafe-3.0.2.dist-info/METADATA | 92 + .../MarkupSafe-3.0.2.dist-info/RECORD | 14 + .../MarkupSafe-3.0.2.dist-info/WHEEL | 6 + .../MarkupSafe-3.0.2.dist-info/top_level.txt | 1 + .../SQLAlchemy-2.0.36.dist-info/INSTALLER | 1 + .../SQLAlchemy-2.0.36.dist-info/LICENSE | 19 + .../SQLAlchemy-2.0.36.dist-info/METADATA | 243 + .../SQLAlchemy-2.0.36.dist-info/RECORD | 530 + .../SQLAlchemy-2.0.36.dist-info/REQUESTED | 0 .../SQLAlchemy-2.0.36.dist-info/WHEEL | 6 + .../SQLAlchemy-2.0.36.dist-info/top_level.txt | 1 + .../typing_extensions.cpython-312.pyc | Bin 0 -> 139400 bytes .../site-packages/automat/__init__.py | 16 + .../__pycache__/__init__.cpython-312.pyc | Bin 0 -> 503 bytes .../automat/__pycache__/_core.cpython-312.pyc | Bin 0 -> 8963 bytes .../__pycache__/_discover.cpython-312.pyc | Bin 0 -> 6805 bytes .../_introspection.cpython-312.pyc | Bin 0 -> 2364 bytes .../__pycache__/_methodical.cpython-312.pyc | Bin 0 -> 22687 bytes .../__pycache__/_runtimeproto.cpython-312.pyc | Bin 0 -> 2844 bytes .../__pycache__/_typed.cpython-312.pyc | Bin 0 -> 29471 bytes .../__pycache__/_visualize.cpython-312.pyc | Bin 0 -> 8919 bytes .../python3.12/site-packages/automat/_core.py | 203 + .../site-packages/automat/_discover.py | 168 + .../site-packages/automat/_introspection.py | 57 + .../site-packages/automat/_methodical.py | 545 ++ .../site-packages/automat/_runtimeproto.py | 62 + .../site-packages/automat/_test/__init__.py | 0 .../__pycache__/__init__.cpython-312.pyc | Bin 0 -> 194 bytes .../__pycache__/test_core.cpython-312.pyc | Bin 0 -> 5391 bytes .../__pycache__/test_discover.cpython-312.pyc | Bin 0 -> 30409 bytes .../test_methodical.cpython-312.pyc | Bin 0 -> 39708 bytes .../__pycache__/test_trace.cpython-312.pyc | Bin 0 -> 4612 bytes .../test_type_based.cpython-312.pyc | Bin 0 -> 34948 bytes .../test_visualize.cpython-312.pyc | Bin 0 -> 26271 bytes .../site-packages/automat/_test/test_core.py | 97 + .../automat/_test/test_discover.py | 638 ++ .../automat/_test/test_methodical.py | 717 ++ .../site-packages/automat/_test/test_trace.py | 142 + .../automat/_test/test_type_based.py | 534 + .../automat/_test/test_visualize.py | 478 + .../site-packages/automat/_typed.py | 736 ++ .../site-packages/automat/_visualize.py | 230 + .../python3.12/site-packages/automat/py.typed | 0 .../blinker-1.9.0.dist-info/INSTALLER | 1 + .../blinker-1.9.0.dist-info/LICENSE.txt | 20 + .../blinker-1.9.0.dist-info/METADATA | 60 + .../blinker-1.9.0.dist-info/RECORD | 12 + .../blinker-1.9.0.dist-info/WHEEL | 4 + .../site-packages/blinker/__init__.py | 17 + .../__pycache__/__init__.cpython-312.pyc | Bin 0 -> 500 bytes .../__pycache__/_utilities.cpython-312.pyc | Bin 0 -> 2727 bytes .../blinker/__pycache__/base.cpython-312.pyc | Bin 0 -> 21970 bytes .../site-packages/blinker/_utilities.py | 64 + .../python3.12/site-packages/blinker/base.py | 512 + .../python3.12/site-packages/blinker/py.typed | 0 .../cachelib-0.13.0.dist-info/INSTALLER | 1 + .../cachelib-0.13.0.dist-info/LICENSE.rst | 28 + .../cachelib-0.13.0.dist-info/METADATA | 64 + .../cachelib-0.13.0.dist-info/RECORD | 27 + .../cachelib-0.13.0.dist-info/WHEEL | 5 + .../cachelib-0.13.0.dist-info/top_level.txt | 1 + .../site-packages/cachelib/__init__.py | 22 + .../__pycache__/__init__.cpython-312.pyc | Bin 0 -> 749 bytes .../cachelib/__pycache__/base.cpython-312.pyc | Bin 0 -> 9190 bytes .../__pycache__/dynamodb.cpython-312.pyc | Bin 0 -> 11693 bytes .../cachelib/__pycache__/file.cpython-312.pyc | Bin 0 -> 17550 bytes .../__pycache__/memcached.cpython-312.pyc | Bin 0 -> 10540 bytes .../__pycache__/mongodb.cpython-312.pyc | Bin 0 -> 11470 bytes .../__pycache__/redis.cpython-312.pyc | Bin 0 -> 10514 bytes .../__pycache__/serializers.cpython-312.pyc | Bin 0 -> 5593 bytes .../__pycache__/simple.cpython-312.pyc | Bin 0 -> 6442 bytes .../__pycache__/uwsgi.cpython-312.pyc | Bin 0 -> 4374 bytes .../python3.12/site-packages/cachelib/base.py | 185 + .../site-packages/cachelib/dynamodb.py | 226 + .../python3.12/site-packages/cachelib/file.py | 348 + .../site-packages/cachelib/memcached.py | 196 + .../site-packages/cachelib/mongodb.py | 202 + .../site-packages/cachelib/py.typed | 0 .../site-packages/cachelib/redis.py | 159 + .../site-packages/cachelib/serializers.py | 112 + .../site-packages/cachelib/simple.py | 100 + .../site-packages/cachelib/uwsgi.py | 83 + .../certifi-2024.8.30.dist-info/INSTALLER | 1 + .../certifi-2024.8.30.dist-info/LICENSE | 20 + .../certifi-2024.8.30.dist-info/METADATA | 67 + .../certifi-2024.8.30.dist-info/RECORD | 14 + .../certifi-2024.8.30.dist-info/WHEEL | 5 + .../certifi-2024.8.30.dist-info/top_level.txt | 1 + .../site-packages/certifi/__init__.py | 4 + .../site-packages/certifi/__main__.py | 12 + .../__pycache__/__init__.cpython-312.pyc | Bin 0 -> 315 bytes .../__pycache__/__main__.cpython-312.pyc | Bin 0 -> 630 bytes .../certifi/__pycache__/core.cpython-312.pyc | Bin 0 -> 3191 bytes .../site-packages/certifi/cacert.pem | 4929 ++++++++++ .../python3.12/site-packages/certifi/core.py | 114 + .../python3.12/site-packages/certifi/py.typed | 0 .../INSTALLER | 1 + .../LICENSE | 21 + .../METADATA | 695 ++ .../charset_normalizer-3.4.0.dist-info/RECORD | 35 + .../charset_normalizer-3.4.0.dist-info/WHEEL | 6 + .../entry_points.txt | 2 + .../top_level.txt | 1 + .../charset_normalizer/__init__.py | 46 + .../charset_normalizer/__main__.py | 4 + .../__pycache__/__init__.cpython-312.pyc | Bin 0 -> 1734 bytes .../__pycache__/__main__.cpython-312.pyc | Bin 0 -> 304 bytes .../__pycache__/api.cpython-312.pyc | Bin 0 -> 17987 bytes .../__pycache__/cd.cpython-312.pyc | Bin 0 -> 13443 bytes .../__pycache__/constant.cpython-312.pyc | Bin 0 -> 38767 bytes .../__pycache__/legacy.cpython-312.pyc | Bin 0 -> 2848 bytes .../__pycache__/md.cpython-312.pyc | Bin 0 -> 24916 bytes .../__pycache__/models.cpython-312.pyc | Bin 0 -> 17451 bytes .../__pycache__/utils.cpython-312.pyc | Bin 0 -> 14321 bytes .../__pycache__/version.cpython-312.pyc | Bin 0 -> 331 bytes .../site-packages/charset_normalizer/api.py | 668 ++ .../site-packages/charset_normalizer/cd.py | 395 + .../charset_normalizer/cli/__init__.py | 6 + .../charset_normalizer/cli/__main__.py | 320 + .../cli/__pycache__/__init__.cpython-312.pyc | Bin 0 -> 292 bytes .../cli/__pycache__/__main__.cpython-312.pyc | Bin 0 -> 11016 bytes .../charset_normalizer/constant.py | 1997 ++++ .../charset_normalizer/legacy.py | 65 + .../md.cpython-312-x86_64-linux-gnu.so | Bin 0 -> 16064 bytes .../site-packages/charset_normalizer/md.py | 628 ++ .../md__mypyc.cpython-312-x86_64-linux-gnu.so | Bin 0 -> 276848 bytes .../charset_normalizer/models.py | 359 + .../site-packages/charset_normalizer/py.typed | 0 .../site-packages/charset_normalizer/utils.py | 421 + .../charset_normalizer/version.py | 6 + .../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-312.pyc | Bin 0 -> 2705 bytes .../click/__pycache__/_compat.cpython-312.pyc | Bin 0 -> 27450 bytes .../__pycache__/_termui_impl.cpython-312.pyc | Bin 0 -> 30528 bytes .../__pycache__/_textwrap.cpython-312.pyc | Bin 0 -> 2446 bytes .../__pycache__/_winconsole.cpython-312.pyc | Bin 0 -> 11985 bytes .../click/__pycache__/core.cpython-312.pyc | Bin 0 -> 135506 bytes .../__pycache__/decorators.cpython-312.pyc | Bin 0 -> 23978 bytes .../__pycache__/exceptions.cpython-312.pyc | Bin 0 -> 14741 bytes .../__pycache__/formatting.cpython-312.pyc | Bin 0 -> 14060 bytes .../click/__pycache__/globals.cpython-312.pyc | Bin 0 -> 3125 bytes .../click/__pycache__/parser.cpython-312.pyc | Bin 0 -> 21490 bytes .../shell_completion.cpython-312.pyc | Bin 0 -> 22762 bytes .../click/__pycache__/termui.cpython-312.pyc | Bin 0 -> 32795 bytes .../click/__pycache__/testing.cpython-312.pyc | Bin 0 -> 24567 bytes .../click/__pycache__/types.cpython-312.pyc | Bin 0 -> 49447 bytes .../click/__pycache__/utils.cpython-312.pyc | Bin 0 -> 26297 bytes .../python3.12/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.12/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.12/site-packages/click/globals.py | 68 + .../python3.12/site-packages/click/parser.py | 529 + .../python3.12/site-packages/click/py.typed | 0 .../site-packages/click/shell_completion.py | 596 ++ .../python3.12/site-packages/click/termui.py | 784 ++ .../python3.12/site-packages/click/testing.py | 479 + .../python3.12/site-packages/click/types.py | 1089 +++ .../python3.12/site-packages/click/utils.py | 624 ++ .../cs50-9.4.0.dist-info/INSTALLER | 1 + .../cs50-9.4.0.dist-info/LICENSE | 674 ++ .../cs50-9.4.0.dist-info/METADATA | 22 + .../site-packages/cs50-9.4.0.dist-info/RECORD | 15 + .../cs50-9.4.0.dist-info/REQUESTED | 0 .../site-packages/cs50-9.4.0.dist-info/WHEEL | 5 + .../cs50-9.4.0.dist-info/top_level.txt | 1 + .../python3.12/site-packages/cs50/__init__.py | 21 + .../cs50/__pycache__/__init__.cpython-312.pyc | Bin 0 -> 620 bytes .../cs50/__pycache__/cs50.cpython-312.pyc | Bin 0 -> 7143 bytes .../cs50/__pycache__/flask.cpython-312.pyc | Bin 0 -> 1880 bytes .../cs50/__pycache__/sql.cpython-312.pyc | Bin 0 -> 24345 bytes .../lib/python3.12/site-packages/cs50/cs50.py | 159 + .../python3.12/site-packages/cs50/flask.py | 47 + .../lib/python3.12/site-packages/cs50/sql.py | 656 ++ .../flask-3.1.0.dist-info/INSTALLER | 1 + .../flask-3.1.0.dist-info/LICENSE.txt | 28 + .../flask-3.1.0.dist-info/METADATA | 81 + .../flask-3.1.0.dist-info/RECORD | 57 + .../site-packages/flask-3.1.0.dist-info/WHEEL | 4 + .../flask-3.1.0.dist-info/entry_points.txt | 3 + .../site-packages/flask/__init__.py | 60 + .../site-packages/flask/__main__.py | 3 + .../__pycache__/__init__.cpython-312.pyc | Bin 0 -> 2479 bytes .../__pycache__/__main__.cpython-312.pyc | Bin 0 -> 240 bytes .../flask/__pycache__/app.cpython-312.pyc | Bin 0 -> 62417 bytes .../__pycache__/blueprints.cpython-312.pyc | Bin 0 -> 4999 bytes .../flask/__pycache__/cli.cpython-312.pyc | Bin 0 -> 43378 bytes .../flask/__pycache__/config.cpython-312.pyc | Bin 0 -> 16208 bytes .../flask/__pycache__/ctx.cpython-312.pyc | Bin 0 -> 19826 bytes .../__pycache__/debughelpers.cpython-312.pyc | Bin 0 -> 9131 bytes .../flask/__pycache__/globals.cpython-312.pyc | Bin 0 -> 1864 bytes .../flask/__pycache__/helpers.cpython-312.pyc | Bin 0 -> 25435 bytes .../flask/__pycache__/logging.cpython-312.pyc | Bin 0 -> 3269 bytes .../__pycache__/sessions.cpython-312.pyc | Bin 0 -> 17132 bytes .../flask/__pycache__/signals.cpython-312.pyc | Bin 0 -> 1221 bytes .../__pycache__/templating.cpython-312.pyc | Bin 0 -> 9906 bytes .../flask/__pycache__/testing.cpython-312.pyc | Bin 0 -> 13575 bytes .../flask/__pycache__/typing.cpython-312.pyc | Bin 0 -> 3987 bytes .../flask/__pycache__/views.cpython-312.pyc | Bin 0 -> 7005 bytes .../__pycache__/wrappers.cpython-312.pyc | Bin 0 -> 10052 bytes .../lib/python3.12/site-packages/flask/app.py | 1536 +++ .../site-packages/flask/blueprints.py | 128 + .../lib/python3.12/site-packages/flask/cli.py | 1133 +++ .../python3.12/site-packages/flask/config.py | 367 + .../lib/python3.12/site-packages/flask/ctx.py | 449 + .../site-packages/flask/debughelpers.py | 178 + .../python3.12/site-packages/flask/globals.py | 51 + .../python3.12/site-packages/flask/helpers.py | 634 ++ .../site-packages/flask/json/__init__.py | 170 + .../json/__pycache__/__init__.cpython-312.pyc | Bin 0 -> 6692 bytes .../json/__pycache__/provider.cpython-312.pyc | Bin 0 -> 9259 bytes .../json/__pycache__/tag.cpython-312.pyc | Bin 0 -> 13954 bytes .../site-packages/flask/json/provider.py | 215 + .../site-packages/flask/json/tag.py | 327 + .../python3.12/site-packages/flask/logging.py | 79 + .../python3.12/site-packages/flask/py.typed | 0 .../site-packages/flask/sansio/README.md | 6 + .../sansio/__pycache__/app.cpython-312.pyc | Bin 0 -> 33686 bytes .../__pycache__/blueprints.cpython-312.pyc | Bin 0 -> 31183 bytes .../__pycache__/scaffold.cpython-312.pyc | Bin 0 -> 30223 bytes .../site-packages/flask/sansio/app.py | 964 ++ .../site-packages/flask/sansio/blueprints.py | 632 ++ .../site-packages/flask/sansio/scaffold.py | 792 ++ .../site-packages/flask/sessions.py | 398 + .../python3.12/site-packages/flask/signals.py | 17 + .../site-packages/flask/templating.py | 219 + .../python3.12/site-packages/flask/testing.py | 297 + .../python3.12/site-packages/flask/typing.py | 90 + .../python3.12/site-packages/flask/views.py | 191 + .../site-packages/flask/wrappers.py | 257 + .../flask_session-0.8.0.dist-info/INSTALLER | 1 + .../flask_session-0.8.0.dist-info/LICENSE.rst | 28 + .../flask_session-0.8.0.dist-info/METADATA | 149 + .../flask_session-0.8.0.dist-info/RECORD | 42 + .../flask_session-0.8.0.dist-info/REQUESTED | 0 .../flask_session-0.8.0.dist-info/WHEEL | 4 + .../site-packages/flask_session/__init__.py | 186 + .../__pycache__/__init__.cpython-312.pyc | Bin 0 -> 6293 bytes .../__pycache__/_utils.cpython-312.pyc | Bin 0 -> 3417 bytes .../__pycache__/base.cpython-312.pyc | Bin 0 -> 19016 bytes .../__pycache__/defaults.cpython-312.pyc | Bin 0 -> 1329 bytes .../site-packages/flask_session/_utils.py | 67 + .../site-packages/flask_session/base.py | 385 + .../flask_session/cachelib/__init__.py | 1 + .../__pycache__/__init__.cpython-312.pyc | Bin 0 -> 292 bytes .../__pycache__/cachelib.cpython-312.pyc | Bin 0 -> 3727 bytes .../flask_session/cachelib/cachelib.py | 76 + .../site-packages/flask_session/defaults.py | 45 + .../flask_session/dynamodb/__init__.py | 1 + .../__pycache__/__init__.cpython-312.pyc | Bin 0 -> 292 bytes .../__pycache__/dynamodb.cpython-312.pyc | Bin 0 -> 5876 bytes .../flask_session/dynamodb/dynamodb.py | 126 + .../flask_session/filesystem/__init__.py | 1 + .../__pycache__/__init__.cpython-312.pyc | Bin 0 -> 300 bytes .../__pycache__/filesystem.cpython-312.pyc | Bin 0 -> 5217 bytes .../flask_session/filesystem/filesystem.py | 109 + .../flask_session/memcached/__init__.py | 1 + .../__pycache__/__init__.cpython-312.pyc | Bin 0 -> 296 bytes .../__pycache__/memcached.cpython-312.pyc | Bin 0 -> 6466 bytes .../flask_session/memcached/memcached.py | 122 + .../flask_session/mongodb/__init__.py | 1 + .../__pycache__/__init__.cpython-312.pyc | Bin 0 -> 288 bytes .../__pycache__/mongodb.cpython-312.pyc | Bin 0 -> 5292 bytes .../flask_session/mongodb/mongodb.py | 119 + .../flask_session/redis/__init__.py | 1 + .../__pycache__/__init__.cpython-312.pyc | Bin 0 -> 280 bytes .../redis/__pycache__/redis.cpython-312.pyc | Bin 0 -> 4115 bytes .../flask_session/redis/redis.py | 85 + .../flask_session/sqlalchemy/__init__.py | 1 + .../__pycache__/__init__.cpython-312.pyc | Bin 0 -> 300 bytes .../__pycache__/sqlalchemy.cpython-312.pyc | Bin 0 -> 9936 bytes .../flask_session/sqlalchemy/sqlalchemy.py | 189 + .../greenlet-3.1.1.dist-info/AUTHORS | 51 + .../greenlet-3.1.1.dist-info/INSTALLER | 1 + .../greenlet-3.1.1.dist-info/LICENSE | 30 + .../greenlet-3.1.1.dist-info/LICENSE.PSF | 47 + .../greenlet-3.1.1.dist-info/METADATA | 103 + .../greenlet-3.1.1.dist-info/RECORD | 122 + .../greenlet-3.1.1.dist-info/WHEEL | 6 + .../greenlet-3.1.1.dist-info/top_level.txt | 1 + .../site-packages/greenlet/CObjects.cpp | 157 + .../site-packages/greenlet/PyGreenlet.cpp | 738 ++ .../site-packages/greenlet/PyGreenlet.hpp | 35 + .../greenlet/PyGreenletUnswitchable.cpp | 147 + .../site-packages/greenlet/PyModule.cpp | 292 + .../greenlet/TBrokenGreenlet.cpp | 45 + .../greenlet/TExceptionState.cpp | 62 + .../site-packages/greenlet/TGreenlet.cpp | 718 ++ .../site-packages/greenlet/TGreenlet.hpp | 813 ++ .../greenlet/TGreenletGlobals.cpp | 94 + .../site-packages/greenlet/TMainGreenlet.cpp | 153 + .../site-packages/greenlet/TPythonState.cpp | 393 + .../site-packages/greenlet/TStackState.cpp | 265 + .../site-packages/greenlet/TThreadState.hpp | 497 + .../greenlet/TThreadStateCreator.hpp | 102 + .../greenlet/TThreadStateDestroy.cpp | 258 + .../site-packages/greenlet/TUserGreenlet.cpp | 662 ++ .../site-packages/greenlet/__init__.py | 71 + .../__pycache__/__init__.cpython-312.pyc | Bin 0 -> 1075 bytes .../_greenlet.cpython-312-x86_64-linux-gnu.so | Bin 0 -> 1429296 bytes .../site-packages/greenlet/greenlet.cpp | 320 + .../site-packages/greenlet/greenlet.h | 164 + .../greenlet/greenlet_allocator.hpp | 63 + .../greenlet/greenlet_compiler_compat.hpp | 98 + .../greenlet/greenlet_cpython_add_pending.hpp | 172 + .../greenlet/greenlet_cpython_compat.hpp | 142 + .../greenlet/greenlet_exceptions.hpp | 171 + .../greenlet/greenlet_internal.hpp | 107 + .../site-packages/greenlet/greenlet_refs.hpp | 1118 +++ .../greenlet/greenlet_slp_switch.hpp | 99 + .../greenlet/greenlet_thread_support.hpp | 31 + .../greenlet/platform/__init__.py | 0 .../__pycache__/__init__.cpython-312.pyc | Bin 0 -> 198 bytes .../platform/setup_switch_x64_masm.cmd | 2 + .../greenlet/platform/switch_aarch64_gcc.h | 124 + .../greenlet/platform/switch_alpha_unix.h | 30 + .../greenlet/platform/switch_amd64_unix.h | 87 + .../greenlet/platform/switch_arm32_gcc.h | 79 + .../greenlet/platform/switch_arm32_ios.h | 67 + .../greenlet/platform/switch_arm64_masm.asm | 53 + .../greenlet/platform/switch_arm64_masm.obj | Bin 0 -> 746 bytes .../greenlet/platform/switch_arm64_msvc.h | 17 + .../greenlet/platform/switch_csky_gcc.h | 48 + .../platform/switch_loongarch64_linux.h | 31 + .../greenlet/platform/switch_m68k_gcc.h | 38 + .../greenlet/platform/switch_mips_unix.h | 64 + .../greenlet/platform/switch_ppc64_aix.h | 103 + .../greenlet/platform/switch_ppc64_linux.h | 105 + .../greenlet/platform/switch_ppc_aix.h | 87 + .../greenlet/platform/switch_ppc_linux.h | 84 + .../greenlet/platform/switch_ppc_macosx.h | 82 + .../greenlet/platform/switch_ppc_unix.h | 82 + .../greenlet/platform/switch_riscv_unix.h | 36 + .../greenlet/platform/switch_s390_unix.h | 87 + .../greenlet/platform/switch_sh_gcc.h | 36 + .../greenlet/platform/switch_sparc_sun_gcc.h | 92 + .../greenlet/platform/switch_x32_unix.h | 63 + .../greenlet/platform/switch_x64_masm.asm | 111 + .../greenlet/platform/switch_x64_masm.obj | Bin 0 -> 1078 bytes .../greenlet/platform/switch_x64_msvc.h | 60 + .../greenlet/platform/switch_x86_msvc.h | 326 + .../greenlet/platform/switch_x86_unix.h | 105 + .../greenlet/slp_platformselect.h | 75 + .../site-packages/greenlet/tests/__init__.py | 240 + .../__pycache__/__init__.cpython-312.pyc | Bin 0 -> 9015 bytes ...fail_clearing_run_switches.cpython-312.pyc | Bin 0 -> 2083 bytes .../fail_cpp_exception.cpython-312.pyc | Bin 0 -> 1618 bytes ...nitialstub_already_started.cpython-312.pyc | Bin 0 -> 3486 bytes .../fail_slp_switch.cpython-312.pyc | Bin 0 -> 1311 bytes ...ail_switch_three_greenlets.cpython-312.pyc | Bin 0 -> 1727 bytes ...il_switch_three_greenlets2.cpython-312.pyc | Bin 0 -> 2581 bytes .../fail_switch_two_greenlets.cpython-312.pyc | Bin 0 -> 1698 bytes .../__pycache__/leakcheck.cpython-312.pyc | Bin 0 -> 11563 bytes .../test_contextvars.cpython-312.pyc | Bin 0 -> 15317 bytes .../__pycache__/test_cpp.cpython-312.pyc | Bin 0 -> 4095 bytes .../test_extension_interface.cpython-312.pyc | Bin 0 -> 7455 bytes .../tests/__pycache__/test_gc.cpython-312.pyc | Bin 0 -> 4933 bytes .../test_generator.cpython-312.pyc | Bin 0 -> 3071 bytes .../test_generator_nested.cpython-312.pyc | Bin 0 -> 7765 bytes .../__pycache__/test_greenlet.cpython-312.pyc | Bin 0 -> 74876 bytes .../test_greenlet_trash.cpython-312.pyc | Bin 0 -> 6778 bytes .../__pycache__/test_leaks.cpython-312.pyc | Bin 0 -> 19454 bytes .../test_stack_saved.cpython-312.pyc | Bin 0 -> 1350 bytes .../__pycache__/test_throw.cpython-312.pyc | Bin 0 -> 7358 bytes .../__pycache__/test_tracing.cpython-312.pyc | Bin 0 -> 13609 bytes .../__pycache__/test_version.cpython-312.pyc | Bin 0 -> 2557 bytes .../__pycache__/test_weakref.cpython-312.pyc | Bin 0 -> 2741 bytes .../greenlet/tests/_test_extension.c | 231 + ..._extension.cpython-312-x86_64-linux-gnu.so | Bin 0 -> 37168 bytes .../greenlet/tests/_test_extension_cpp.cpp | 226 + ...ension_cpp.cpython-312-x86_64-linux-gnu.so | Bin 0 -> 57800 bytes .../tests/fail_clearing_run_switches.py | 47 + .../greenlet/tests/fail_cpp_exception.py | 33 + .../tests/fail_initialstub_already_started.py | 78 + .../greenlet/tests/fail_slp_switch.py | 29 + .../tests/fail_switch_three_greenlets.py | 44 + .../tests/fail_switch_three_greenlets2.py | 55 + .../tests/fail_switch_two_greenlets.py | 41 + .../site-packages/greenlet/tests/leakcheck.py | 319 + .../greenlet/tests/test_contextvars.py | 310 + .../site-packages/greenlet/tests/test_cpp.py | 73 + .../tests/test_extension_interface.py | 115 + .../site-packages/greenlet/tests/test_gc.py | 86 + .../greenlet/tests/test_generator.py | 59 + .../greenlet/tests/test_generator_nested.py | 168 + .../greenlet/tests/test_greenlet.py | 1324 +++ .../greenlet/tests/test_greenlet_trash.py | 187 + .../greenlet/tests/test_leaks.py | 443 + .../greenlet/tests/test_stack_saved.py | 19 + .../greenlet/tests/test_throw.py | 128 + .../greenlet/tests/test_tracing.py | 291 + .../greenlet/tests/test_version.py | 41 + .../greenlet/tests/test_weakref.py | 35 + .../idna-3.10.dist-info/INSTALLER | 1 + .../idna-3.10.dist-info/LICENSE.md | 31 + .../idna-3.10.dist-info/METADATA | 250 + .../site-packages/idna-3.10.dist-info/RECORD | 22 + .../site-packages/idna-3.10.dist-info/WHEEL | 4 + .../python3.12/site-packages/idna/__init__.py | 45 + .../idna/__pycache__/__init__.cpython-312.pyc | Bin 0 -> 883 bytes .../idna/__pycache__/codec.cpython-312.pyc | Bin 0 -> 4973 bytes .../idna/__pycache__/compat.cpython-312.pyc | Bin 0 -> 887 bytes .../idna/__pycache__/core.cpython-312.pyc | Bin 0 -> 16118 bytes .../idna/__pycache__/idnadata.cpython-312.pyc | Bin 0 -> 99473 bytes .../__pycache__/intranges.cpython-312.pyc | Bin 0 -> 2630 bytes .../__pycache__/package_data.cpython-312.pyc | Bin 0 -> 214 bytes .../__pycache__/uts46data.cpython-312.pyc | Bin 0 -> 158843 bytes .../python3.12/site-packages/idna/codec.py | 122 + .../python3.12/site-packages/idna/compat.py | 15 + .../lib/python3.12/site-packages/idna/core.py | 437 + .../python3.12/site-packages/idna/idnadata.py | 4243 ++++++++ .../site-packages/idna/intranges.py | 57 + .../site-packages/idna/package_data.py | 1 + .../python3.12/site-packages/idna/py.typed | 0 .../site-packages/idna/uts46data.py | 8681 +++++++++++++++++ .../itsdangerous-2.2.0.dist-info/INSTALLER | 1 + .../itsdangerous-2.2.0.dist-info/LICENSE.txt | 28 + .../itsdangerous-2.2.0.dist-info/METADATA | 60 + .../itsdangerous-2.2.0.dist-info/RECORD | 22 + .../itsdangerous-2.2.0.dist-info/WHEEL | 4 + .../site-packages/itsdangerous/__init__.py | 38 + .../__pycache__/__init__.cpython-312.pyc | Bin 0 -> 1631 bytes .../__pycache__/_json.cpython-312.pyc | Bin 0 -> 1185 bytes .../__pycache__/encoding.cpython-312.pyc | Bin 0 -> 2685 bytes .../__pycache__/exc.cpython-312.pyc | Bin 0 -> 3945 bytes .../__pycache__/serializer.cpython-312.pyc | Bin 0 -> 15413 bytes .../__pycache__/signer.cpython-312.pyc | Bin 0 -> 11290 bytes .../__pycache__/timed.cpython-312.pyc | Bin 0 -> 8734 bytes .../__pycache__/url_safe.cpython-312.pyc | Bin 0 -> 3535 bytes .../site-packages/itsdangerous/_json.py | 18 + .../site-packages/itsdangerous/encoding.py | 54 + .../site-packages/itsdangerous/exc.py | 106 + .../site-packages/itsdangerous/py.typed | 0 .../site-packages/itsdangerous/serializer.py | 406 + .../site-packages/itsdangerous/signer.py | 266 + .../site-packages/itsdangerous/timed.py | 228 + .../site-packages/itsdangerous/url_safe.py | 83 + .../jinja2-3.1.4.dist-info/INSTALLER | 1 + .../jinja2-3.1.4.dist-info/LICENSE.txt | 28 + .../jinja2-3.1.4.dist-info/METADATA | 76 + .../jinja2-3.1.4.dist-info/RECORD | 57 + .../jinja2-3.1.4.dist-info/WHEEL | 4 + .../jinja2-3.1.4.dist-info/entry_points.txt | 3 + .../site-packages/jinja2/__init__.py | 38 + .../__pycache__/__init__.cpython-312.pyc | Bin 0 -> 1656 bytes .../__pycache__/_identifier.cpython-312.pyc | Bin 0 -> 2137 bytes .../__pycache__/async_utils.cpython-312.pyc | Bin 0 -> 4081 bytes .../__pycache__/bccache.cpython-312.pyc | Bin 0 -> 19328 bytes .../__pycache__/compiler.cpython-312.pyc | Bin 0 -> 102261 bytes .../__pycache__/constants.cpython-312.pyc | Bin 0 -> 1559 bytes .../jinja2/__pycache__/debug.cpython-312.pyc | Bin 0 -> 6569 bytes .../__pycache__/defaults.cpython-312.pyc | Bin 0 -> 1609 bytes .../__pycache__/environment.cpython-312.pyc | Bin 0 -> 76705 bytes .../__pycache__/exceptions.cpython-312.pyc | Bin 0 -> 7718 bytes .../jinja2/__pycache__/ext.cpython-312.pyc | Bin 0 -> 41871 bytes .../__pycache__/filters.cpython-312.pyc | Bin 0 -> 72023 bytes .../__pycache__/idtracking.cpython-312.pyc | Bin 0 -> 19152 bytes .../jinja2/__pycache__/lexer.cpython-312.pyc | Bin 0 -> 32040 bytes .../__pycache__/loaders.cpython-312.pyc | Bin 0 -> 30966 bytes .../jinja2/__pycache__/meta.cpython-312.pyc | Bin 0 -> 5473 bytes .../__pycache__/nativetypes.cpython-312.pyc | Bin 0 -> 7022 bytes .../jinja2/__pycache__/nodes.cpython-312.pyc | Bin 0 -> 58222 bytes .../__pycache__/optimizer.cpython-312.pyc | Bin 0 -> 2692 bytes .../jinja2/__pycache__/parser.cpython-312.pyc | Bin 0 -> 60814 bytes .../__pycache__/runtime.cpython-312.pyc | Bin 0 -> 48495 bytes .../__pycache__/sandbox.cpython-312.pyc | Bin 0 -> 17893 bytes .../jinja2/__pycache__/tests.cpython-312.pyc | Bin 0 -> 9053 bytes .../jinja2/__pycache__/utils.cpython-312.pyc | Bin 0 -> 34471 bytes .../__pycache__/visitor.cpython-312.pyc | Bin 0 -> 5356 bytes .../site-packages/jinja2/_identifier.py | 6 + .../site-packages/jinja2/async_utils.py | 84 + .../site-packages/jinja2/bccache.py | 408 + .../site-packages/jinja2/compiler.py | 1960 ++++ .../site-packages/jinja2/constants.py | 20 + .../python3.12/site-packages/jinja2/debug.py | 191 + .../site-packages/jinja2/defaults.py | 48 + .../site-packages/jinja2/environment.py | 1675 ++++ .../site-packages/jinja2/exceptions.py | 166 + .../python3.12/site-packages/jinja2/ext.py | 870 ++ .../site-packages/jinja2/filters.py | 1866 ++++ .../site-packages/jinja2/idtracking.py | 318 + .../python3.12/site-packages/jinja2/lexer.py | 868 ++ .../site-packages/jinja2/loaders.py | 667 ++ .../python3.12/site-packages/jinja2/meta.py | 112 + .../site-packages/jinja2/nativetypes.py | 130 + .../python3.12/site-packages/jinja2/nodes.py | 1206 +++ .../site-packages/jinja2/optimizer.py | 48 + .../python3.12/site-packages/jinja2/parser.py | 1041 ++ .../python3.12/site-packages/jinja2/py.typed | 0 .../site-packages/jinja2/runtime.py | 1056 ++ .../site-packages/jinja2/sandbox.py | 429 + .../python3.12/site-packages/jinja2/tests.py | 256 + .../python3.12/site-packages/jinja2/utils.py | 755 ++ .../site-packages/jinja2/visitor.py | 92 + .../site-packages/markupsafe/__init__.py | 395 + .../__pycache__/__init__.cpython-312.pyc | Bin 0 -> 20956 bytes .../__pycache__/_native.cpython-312.pyc | Bin 0 -> 618 bytes .../site-packages/markupsafe/_native.py | 8 + .../site-packages/markupsafe/_speedups.c | 204 + .../_speedups.cpython-312-x86_64-linux-gnu.so | Bin 0 -> 43432 bytes .../site-packages/markupsafe/_speedups.pyi | 1 + .../site-packages/markupsafe/py.typed | 0 .../msgspec-0.18.6.dist-info/INSTALLER | 1 + .../msgspec-0.18.6.dist-info/LICENSE | 27 + .../msgspec-0.18.6.dist-info/METADATA | 181 + .../msgspec-0.18.6.dist-info/RECORD | 32 + .../msgspec-0.18.6.dist-info/WHEEL | 6 + .../msgspec-0.18.6.dist-info/top_level.txt | 1 + .../site-packages/msgspec/__init__.py | 61 + .../site-packages/msgspec/__init__.pyi | 207 + .../__pycache__/__init__.cpython-312.pyc | Bin 0 -> 1603 bytes .../__pycache__/_json_schema.cpython-312.pyc | Bin 0 -> 22130 bytes .../__pycache__/_utils.cpython-312.pyc | Bin 0 -> 11304 bytes .../__pycache__/_version.cpython-312.pyc | Bin 0 -> 577 bytes .../__pycache__/inspect.cpython-312.pyc | Bin 0 -> 35654 bytes .../msgspec/__pycache__/json.cpython-312.pyc | Bin 0 -> 442 bytes .../__pycache__/msgpack.cpython-312.pyc | Bin 0 -> 364 bytes .../__pycache__/structs.cpython-312.pyc | Bin 0 -> 3995 bytes .../msgspec/__pycache__/toml.cpython-312.pyc | Bin 0 -> 6727 bytes .../msgspec/__pycache__/yaml.cpython-312.pyc | Bin 0 -> 6404 bytes .../_core.cpython-312-x86_64-linux-gnu.so | Bin 0 -> 414104 bytes .../site-packages/msgspec/_json_schema.py | 439 + .../site-packages/msgspec/_utils.py | 289 + .../site-packages/msgspec/_version.py | 21 + .../site-packages/msgspec/inspect.py | 1005 ++ .../python3.12/site-packages/msgspec/json.py | 8 + .../python3.12/site-packages/msgspec/json.pyi | 113 + .../site-packages/msgspec/msgpack.py | 7 + .../site-packages/msgspec/msgpack.pyi | 103 + .../python3.12/site-packages/msgspec/py.typed | 0 .../site-packages/msgspec/structs.py | 106 + .../site-packages/msgspec/structs.pyi | 37 + .../python3.12/site-packages/msgspec/toml.py | 190 + .../python3.12/site-packages/msgspec/yaml.py | 185 + .../packaging-24.2.dist-info/INSTALLER | 1 + .../packaging-24.2.dist-info/LICENSE | 3 + .../packaging-24.2.dist-info/LICENSE.APACHE | 177 + .../packaging-24.2.dist-info/LICENSE.BSD | 23 + .../packaging-24.2.dist-info/METADATA | 102 + .../packaging-24.2.dist-info/RECORD | 40 + .../packaging-24.2.dist-info/WHEEL | 4 + .../site-packages/packaging/__init__.py | 15 + .../__pycache__/__init__.cpython-312.pyc | Bin 0 -> 555 bytes .../__pycache__/_elffile.cpython-312.pyc | Bin 0 -> 5020 bytes .../__pycache__/_manylinux.cpython-312.pyc | Bin 0 -> 9708 bytes .../__pycache__/_musllinux.cpython-312.pyc | Bin 0 -> 4551 bytes .../__pycache__/_parser.cpython-312.pyc | Bin 0 -> 13982 bytes .../__pycache__/_structures.cpython-312.pyc | Bin 0 -> 3238 bytes .../__pycache__/_tokenizer.cpython-312.pyc | Bin 0 -> 7912 bytes .../__pycache__/markers.cpython-312.pyc | Bin 0 -> 11371 bytes .../__pycache__/metadata.cpython-312.pyc | Bin 0 -> 27209 bytes .../__pycache__/requirements.cpython-312.pyc | Bin 0 -> 4407 bytes .../__pycache__/specifiers.cpython-312.pyc | Bin 0 -> 39015 bytes .../__pycache__/tags.cpython-312.pyc | Bin 0 -> 23002 bytes .../__pycache__/utils.cpython-312.pyc | Bin 0 -> 6632 bytes .../__pycache__/version.cpython-312.pyc | Bin 0 -> 20471 bytes .../site-packages/packaging/_elffile.py | 110 + .../site-packages/packaging/_manylinux.py | 263 + .../site-packages/packaging/_musllinux.py | 85 + .../site-packages/packaging/_parser.py | 354 + .../site-packages/packaging/_structures.py | 61 + .../site-packages/packaging/_tokenizer.py | 194 + .../packaging/licenses/__init__.py | 145 + .../__pycache__/__init__.cpython-312.pyc | Bin 0 -> 4105 bytes .../__pycache__/_spdx.cpython-312.pyc | Bin 0 -> 47361 bytes .../site-packages/packaging/licenses/_spdx.py | 759 ++ .../site-packages/packaging/markers.py | 331 + .../site-packages/packaging/metadata.py | 863 ++ .../site-packages/packaging/py.typed | 0 .../site-packages/packaging/requirements.py | 91 + .../site-packages/packaging/specifiers.py | 1020 ++ .../site-packages/packaging/tags.py | 617 ++ .../site-packages/packaging/utils.py | 163 + .../site-packages/packaging/version.py | 582 ++ .../pip-24.3.1.dist-info/AUTHORS.txt | 799 ++ .../pip-24.3.1.dist-info/INSTALLER | 1 + .../pip-24.3.1.dist-info/LICENSE.txt | 20 + .../pip-24.3.1.dist-info/METADATA | 90 + .../site-packages/pip-24.3.1.dist-info/RECORD | 853 ++ .../pip-24.3.1.dist-info/REQUESTED | 0 .../site-packages/pip-24.3.1.dist-info/WHEEL | 5 + .../pip-24.3.1.dist-info/entry_points.txt | 3 + .../pip-24.3.1.dist-info/top_level.txt | 1 + .../python3.12/site-packages/pip/__init__.py | 13 + .../python3.12/site-packages/pip/__main__.py | 24 + .../site-packages/pip/__pip-runner__.py | 50 + .../pip/__pycache__/__init__.cpython-312.pyc | Bin 0 -> 695 bytes .../pip/__pycache__/__main__.cpython-312.pyc | Bin 0 -> 849 bytes .../__pip-runner__.cpython-312.pyc | Bin 0 -> 2213 bytes .../site-packages/pip/_internal/__init__.py | 18 + .../__pycache__/__init__.cpython-312.pyc | Bin 0 -> 795 bytes .../__pycache__/build_env.cpython-312.pyc | Bin 0 -> 14507 bytes .../__pycache__/cache.cpython-312.pyc | Bin 0 -> 12675 bytes .../__pycache__/configuration.cpython-312.pyc | Bin 0 -> 17640 bytes .../__pycache__/exceptions.cpython-312.pyc | Bin 0 -> 36853 bytes .../__pycache__/main.cpython-312.pyc | Bin 0 -> 678 bytes .../__pycache__/pyproject.cpython-312.pyc | Bin 0 -> 5126 bytes .../self_outdated_check.cpython-312.pyc | Bin 0 -> 10216 bytes .../__pycache__/wheel_builder.cpython-312.pyc | Bin 0 -> 13623 bytes .../site-packages/pip/_internal/build_env.py | 319 + .../site-packages/pip/_internal/cache.py | 290 + .../pip/_internal/cli/__init__.py | 4 + .../cli/__pycache__/__init__.cpython-312.pyc | Bin 0 -> 286 bytes .../autocompletion.cpython-312.pyc | Bin 0 -> 8614 bytes .../__pycache__/base_command.cpython-312.pyc | Bin 0 -> 10202 bytes .../__pycache__/cmdoptions.cpython-312.pyc | Bin 0 -> 30403 bytes .../command_context.cpython-312.pyc | Bin 0 -> 1782 bytes .../__pycache__/index_command.cpython-312.pyc | Bin 0 -> 7132 bytes .../cli/__pycache__/main.cpython-312.pyc | Bin 0 -> 2308 bytes .../__pycache__/main_parser.cpython-312.pyc | Bin 0 -> 4914 bytes .../cli/__pycache__/parser.cpython-312.pyc | Bin 0 -> 15048 bytes .../__pycache__/progress_bars.cpython-312.pyc | Bin 0 -> 3852 bytes .../__pycache__/req_command.cpython-312.pyc | Bin 0 -> 12249 bytes .../cli/__pycache__/spinners.cpython-312.pyc | Bin 0 -> 7841 bytes .../__pycache__/status_codes.cpython-312.pyc | Bin 0 -> 383 bytes .../pip/_internal/cli/autocompletion.py | 176 + .../pip/_internal/cli/base_command.py | 231 + .../pip/_internal/cli/cmdoptions.py | 1075 ++ .../pip/_internal/cli/command_context.py | 27 + .../pip/_internal/cli/index_command.py | 170 + .../site-packages/pip/_internal/cli/main.py | 80 + .../pip/_internal/cli/main_parser.py | 134 + .../site-packages/pip/_internal/cli/parser.py | 294 + .../pip/_internal/cli/progress_bars.py | 94 + .../pip/_internal/cli/req_command.py | 329 + .../pip/_internal/cli/spinners.py | 159 + .../pip/_internal/cli/status_codes.py | 6 + .../pip/_internal/commands/__init__.py | 132 + .../__pycache__/__init__.cpython-312.pyc | Bin 0 -> 4010 bytes .../__pycache__/cache.cpython-312.pyc | Bin 0 -> 9709 bytes .../__pycache__/check.cpython-312.pyc | Bin 0 -> 2600 bytes .../__pycache__/completion.cpython-312.pyc | Bin 0 -> 5201 bytes .../__pycache__/configuration.cpython-312.pyc | Bin 0 -> 13171 bytes .../__pycache__/debug.cpython-312.pyc | Bin 0 -> 10076 bytes .../__pycache__/download.cpython-312.pyc | Bin 0 -> 7511 bytes .../__pycache__/freeze.cpython-312.pyc | Bin 0 -> 4393 bytes .../commands/__pycache__/hash.cpython-312.pyc | Bin 0 -> 2976 bytes .../commands/__pycache__/help.cpython-312.pyc | Bin 0 -> 1681 bytes .../__pycache__/index.cpython-312.pyc | Bin 0 -> 6679 bytes .../__pycache__/inspect.cpython-312.pyc | Bin 0 -> 3988 bytes .../__pycache__/install.cpython-312.pyc | Bin 0 -> 29122 bytes .../commands/__pycache__/list.cpython-312.pyc | Bin 0 -> 15765 bytes .../__pycache__/search.cpython-312.pyc | Bin 0 -> 7526 bytes .../commands/__pycache__/show.cpython-312.pyc | Bin 0 -> 10485 bytes .../__pycache__/uninstall.cpython-312.pyc | Bin 0 -> 4717 bytes .../__pycache__/wheel.cpython-312.pyc | Bin 0 -> 8873 bytes .../pip/_internal/commands/cache.py | 225 + .../pip/_internal/commands/check.py | 67 + .../pip/_internal/commands/completion.py | 130 + .../pip/_internal/commands/configuration.py | 280 + .../pip/_internal/commands/debug.py | 201 + .../pip/_internal/commands/download.py | 146 + .../pip/_internal/commands/freeze.py | 109 + .../pip/_internal/commands/hash.py | 59 + .../pip/_internal/commands/help.py | 41 + .../pip/_internal/commands/index.py | 139 + .../pip/_internal/commands/inspect.py | 92 + .../pip/_internal/commands/install.py | 783 ++ .../pip/_internal/commands/list.py | 375 + .../pip/_internal/commands/search.py | 172 + .../pip/_internal/commands/show.py | 217 + .../pip/_internal/commands/uninstall.py | 114 + .../pip/_internal/commands/wheel.py | 182 + .../pip/_internal/configuration.py | 383 + .../pip/_internal/distributions/__init__.py | 21 + .../__pycache__/__init__.cpython-312.pyc | Bin 0 -> 949 bytes .../__pycache__/base.cpython-312.pyc | Bin 0 -> 2901 bytes .../__pycache__/installed.cpython-312.pyc | Bin 0 -> 1708 bytes .../__pycache__/sdist.cpython-312.pyc | Bin 0 -> 8435 bytes .../__pycache__/wheel.cpython-312.pyc | Bin 0 -> 2289 bytes .../pip/_internal/distributions/base.py | 53 + .../pip/_internal/distributions/installed.py | 29 + .../pip/_internal/distributions/sdist.py | 158 + .../pip/_internal/distributions/wheel.py | 42 + .../site-packages/pip/_internal/exceptions.py | 809 ++ .../pip/_internal/index/__init__.py | 2 + .../__pycache__/__init__.cpython-312.pyc | Bin 0 -> 240 bytes .../__pycache__/collector.cpython-312.pyc | Bin 0 -> 21625 bytes .../package_finder.cpython-312.pyc | Bin 0 -> 40656 bytes .../index/__pycache__/sources.cpython-312.pyc | Bin 0 -> 12532 bytes .../pip/_internal/index/collector.py | 494 + .../pip/_internal/index/package_finder.py | 1020 ++ .../pip/_internal/index/sources.py | 284 + .../pip/_internal/locations/__init__.py | 456 + .../__pycache__/__init__.cpython-312.pyc | Bin 0 -> 16448 bytes .../__pycache__/_distutils.cpython-312.pyc | Bin 0 -> 6799 bytes .../__pycache__/_sysconfig.cpython-312.pyc | Bin 0 -> 8036 bytes .../__pycache__/base.cpython-312.pyc | Bin 0 -> 3789 bytes .../pip/_internal/locations/_distutils.py | 172 + .../pip/_internal/locations/_sysconfig.py | 214 + .../pip/_internal/locations/base.py | 81 + .../site-packages/pip/_internal/main.py | 12 + .../pip/_internal/metadata/__init__.py | 128 + .../__pycache__/__init__.cpython-312.pyc | Bin 0 -> 5877 bytes .../__pycache__/_json.cpython-312.pyc | Bin 0 -> 2934 bytes .../metadata/__pycache__/base.cpython-312.pyc | Bin 0 -> 35206 bytes .../__pycache__/pkg_resources.cpython-312.pyc | Bin 0 -> 16092 bytes .../pip/_internal/metadata/_json.py | 84 + .../pip/_internal/metadata/base.py | 688 ++ .../_internal/metadata/importlib/__init__.py | 6 + .../__pycache__/__init__.cpython-312.pyc | Bin 0 -> 366 bytes .../__pycache__/_compat.cpython-312.pyc | Bin 0 -> 4499 bytes .../__pycache__/_dists.cpython-312.pyc | Bin 0 -> 12573 bytes .../__pycache__/_envs.cpython-312.pyc | Bin 0 -> 11087 bytes .../_internal/metadata/importlib/_compat.py | 85 + .../_internal/metadata/importlib/_dists.py | 221 + .../pip/_internal/metadata/importlib/_envs.py | 189 + .../pip/_internal/metadata/pkg_resources.py | 301 + .../pip/_internal/models/__init__.py | 2 + .../__pycache__/__init__.cpython-312.pyc | Bin 0 -> 274 bytes .../__pycache__/candidate.cpython-312.pyc | Bin 0 -> 1612 bytes .../__pycache__/direct_url.cpython-312.pyc | Bin 0 -> 10852 bytes .../format_control.cpython-312.pyc | Bin 0 -> 4231 bytes .../models/__pycache__/index.cpython-312.pyc | Bin 0 -> 1702 bytes .../installation_report.cpython-312.pyc | Bin 0 -> 2285 bytes .../models/__pycache__/link.cpython-312.pyc | Bin 0 -> 26625 bytes .../models/__pycache__/scheme.cpython-312.pyc | Bin 0 -> 1031 bytes .../__pycache__/search_scope.cpython-312.pyc | Bin 0 -> 4995 bytes .../selection_prefs.cpython-312.pyc | Bin 0 -> 1859 bytes .../__pycache__/target_python.cpython-312.pyc | Bin 0 -> 4961 bytes .../models/__pycache__/wheel.cpython-312.pyc | Bin 0 -> 6560 bytes .../pip/_internal/models/candidate.py | 25 + .../pip/_internal/models/direct_url.py | 224 + .../pip/_internal/models/format_control.py | 78 + .../pip/_internal/models/index.py | 28 + .../_internal/models/installation_report.py | 56 + .../pip/_internal/models/link.py | 590 ++ .../pip/_internal/models/scheme.py | 25 + .../pip/_internal/models/search_scope.py | 127 + .../pip/_internal/models/selection_prefs.py | 53 + .../pip/_internal/models/target_python.py | 121 + .../pip/_internal/models/wheel.py | 118 + .../pip/_internal/network/__init__.py | 2 + .../__pycache__/__init__.cpython-312.pyc | Bin 0 -> 262 bytes .../network/__pycache__/auth.cpython-312.pyc | Bin 0 -> 22107 bytes .../network/__pycache__/cache.cpython-312.pyc | Bin 0 -> 6459 bytes .../__pycache__/download.cpython-312.pyc | Bin 0 -> 8487 bytes .../__pycache__/lazy_wheel.cpython-312.pyc | Bin 0 -> 11615 bytes .../__pycache__/session.cpython-312.pyc | Bin 0 -> 18882 bytes .../network/__pycache__/utils.cpython-312.pyc | Bin 0 -> 2263 bytes .../__pycache__/xmlrpc.cpython-312.pyc | Bin 0 -> 2957 bytes .../pip/_internal/network/auth.py | 566 ++ .../pip/_internal/network/cache.py | 106 + .../pip/_internal/network/download.py | 187 + .../pip/_internal/network/lazy_wheel.py | 210 + .../pip/_internal/network/session.py | 522 + .../pip/_internal/network/utils.py | 98 + .../pip/_internal/network/xmlrpc.py | 62 + .../pip/_internal/operations/__init__.py | 0 .../__pycache__/__init__.cpython-312.pyc | Bin 0 -> 205 bytes .../__pycache__/check.cpython-312.pyc | Bin 0 -> 7112 bytes .../__pycache__/freeze.cpython-312.pyc | Bin 0 -> 10136 bytes .../__pycache__/prepare.cpython-312.pyc | Bin 0 -> 25780 bytes .../_internal/operations/build/__init__.py | 0 .../__pycache__/__init__.cpython-312.pyc | Bin 0 -> 211 bytes .../__pycache__/build_tracker.cpython-312.pyc | Bin 0 -> 7675 bytes .../__pycache__/metadata.cpython-312.pyc | Bin 0 -> 1865 bytes .../metadata_editable.cpython-312.pyc | Bin 0 -> 1899 bytes .../metadata_legacy.cpython-312.pyc | Bin 0 -> 3019 bytes .../build/__pycache__/wheel.cpython-312.pyc | Bin 0 -> 1685 bytes .../wheel_editable.cpython-312.pyc | Bin 0 -> 2024 bytes .../__pycache__/wheel_legacy.cpython-312.pyc | Bin 0 -> 3854 bytes .../operations/build/build_tracker.py | 138 + .../_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 | 181 + .../pip/_internal/operations/freeze.py | 258 + .../_internal/operations/install/__init__.py | 2 + .../__pycache__/__init__.cpython-312.pyc | Bin 0 -> 274 bytes .../editable_legacy.cpython-312.pyc | Bin 0 -> 1806 bytes .../install/__pycache__/wheel.cpython-312.pyc | Bin 0 -> 34111 bytes .../operations/install/editable_legacy.py | 47 + .../pip/_internal/operations/install/wheel.py | 741 ++ .../pip/_internal/operations/prepare.py | 732 ++ .../site-packages/pip/_internal/pyproject.py | 185 + .../pip/_internal/req/__init__.py | 90 + .../req/__pycache__/__init__.cpython-312.pyc | Bin 0 -> 3453 bytes .../__pycache__/constructors.cpython-312.pyc | Bin 0 -> 21263 bytes .../req/__pycache__/req_file.cpython-312.pyc | Bin 0 -> 22131 bytes .../__pycache__/req_install.cpython-312.pyc | Bin 0 -> 38483 bytes .../req/__pycache__/req_set.cpython-312.pyc | Bin 0 -> 5491 bytes .../__pycache__/req_uninstall.cpython-312.pyc | Bin 0 -> 32102 bytes .../pip/_internal/req/constructors.py | 560 ++ .../pip/_internal/req/req_file.py | 574 ++ .../pip/_internal/req/req_install.py | 934 ++ .../pip/_internal/req/req_set.py | 82 + .../pip/_internal/req/req_uninstall.py | 633 ++ .../pip/_internal/resolution/__init__.py | 0 .../__pycache__/__init__.cpython-312.pyc | Bin 0 -> 205 bytes .../__pycache__/base.cpython-312.pyc | Bin 0 -> 1193 bytes .../pip/_internal/resolution/base.py | 20 + .../_internal/resolution/legacy/__init__.py | 0 .../__pycache__/__init__.cpython-312.pyc | Bin 0 -> 212 bytes .../__pycache__/resolver.cpython-312.pyc | Bin 0 -> 22587 bytes .../_internal/resolution/legacy/resolver.py | 597 ++ .../resolution/resolvelib/__init__.py | 0 .../__pycache__/__init__.cpython-312.pyc | Bin 0 -> 216 bytes .../__pycache__/base.cpython-312.pyc | Bin 0 -> 8157 bytes .../__pycache__/candidates.cpython-312.pyc | Bin 0 -> 29416 bytes .../__pycache__/factory.cpython-312.pyc | Bin 0 -> 32527 bytes .../found_candidates.cpython-312.pyc | Bin 0 -> 6801 bytes .../__pycache__/provider.cpython-312.pyc | Bin 0 -> 10531 bytes .../__pycache__/reporter.cpython-312.pyc | Bin 0 -> 5048 bytes .../__pycache__/requirements.cpython-312.pyc | Bin 0 -> 15364 bytes .../__pycache__/resolver.cpython-312.pyc | Bin 0 -> 12322 bytes .../_internal/resolution/resolvelib/base.py | 139 + .../resolution/resolvelib/candidates.py | 574 ++ .../resolution/resolvelib/factory.py | 823 ++ .../resolution/resolvelib/found_candidates.py | 174 + .../resolution/resolvelib/provider.py | 258 + .../resolution/resolvelib/reporter.py | 81 + .../resolution/resolvelib/requirements.py | 245 + .../resolution/resolvelib/resolver.py | 317 + .../pip/_internal/self_outdated_check.py | 244 + .../pip/_internal/utils/__init__.py | 0 .../__pycache__/__init__.cpython-312.pyc | Bin 0 -> 200 bytes .../__pycache__/_jaraco_text.cpython-312.pyc | Bin 0 -> 4535 bytes .../utils/__pycache__/_log.cpython-312.pyc | Bin 0 -> 1871 bytes .../utils/__pycache__/appdirs.cpython-312.pyc | Bin 0 -> 2415 bytes .../utils/__pycache__/compat.cpython-312.pyc | Bin 0 -> 2912 bytes .../compatibility_tags.cpython-312.pyc | Bin 0 -> 6355 bytes .../__pycache__/datetime.cpython-312.pyc | Bin 0 -> 689 bytes .../__pycache__/deprecation.cpython-312.pyc | Bin 0 -> 4196 bytes .../direct_url_helpers.cpython-312.pyc | Bin 0 -> 3541 bytes .../__pycache__/egg_link.cpython-312.pyc | Bin 0 -> 3211 bytes .../__pycache__/encoding.cpython-312.pyc | Bin 0 -> 2153 bytes .../__pycache__/entrypoints.cpython-312.pyc | Bin 0 -> 3998 bytes .../__pycache__/filesystem.cpython-312.pyc | Bin 0 -> 7334 bytes .../__pycache__/filetypes.cpython-312.pyc | Bin 0 -> 1169 bytes .../utils/__pycache__/glibc.cpython-312.pyc | Bin 0 -> 2424 bytes .../utils/__pycache__/hashes.cpython-312.pyc | Bin 0 -> 7608 bytes .../utils/__pycache__/logging.cpython-312.pyc | Bin 0 -> 13563 bytes .../utils/__pycache__/misc.cpython-312.pyc | Bin 0 -> 33456 bytes .../__pycache__/packaging.cpython-312.pyc | Bin 0 -> 2588 bytes .../utils/__pycache__/retry.cpython-312.pyc | Bin 0 -> 2113 bytes .../setuptools_build.cpython-312.pyc | Bin 0 -> 4555 bytes .../__pycache__/subprocess.cpython-312.pyc | Bin 0 -> 8644 bytes .../__pycache__/temp_dir.cpython-312.pyc | Bin 0 -> 12029 bytes .../__pycache__/unpacking.cpython-312.pyc | Bin 0 -> 13503 bytes .../utils/__pycache__/urls.cpython-312.pyc | Bin 0 -> 2082 bytes .../__pycache__/virtualenv.cpython-312.pyc | Bin 0 -> 4471 bytes .../utils/__pycache__/wheel.cpython-312.pyc | Bin 0 -> 5908 bytes .../pip/_internal/utils/_jaraco_text.py | 109 + .../site-packages/pip/_internal/utils/_log.py | 38 + .../pip/_internal/utils/appdirs.py | 52 + .../pip/_internal/utils/compat.py | 79 + .../pip/_internal/utils/compatibility_tags.py | 188 + .../pip/_internal/utils/datetime.py | 11 + .../pip/_internal/utils/deprecation.py | 124 + .../pip/_internal/utils/direct_url_helpers.py | 87 + .../pip/_internal/utils/egg_link.py | 80 + .../pip/_internal/utils/encoding.py | 36 + .../pip/_internal/utils/entrypoints.py | 84 + .../pip/_internal/utils/filesystem.py | 149 + .../pip/_internal/utils/filetypes.py | 27 + .../pip/_internal/utils/glibc.py | 101 + .../pip/_internal/utils/hashes.py | 147 + .../pip/_internal/utils/logging.py | 347 + .../site-packages/pip/_internal/utils/misc.py | 772 ++ .../pip/_internal/utils/packaging.py | 57 + .../pip/_internal/utils/retry.py | 42 + .../pip/_internal/utils/setuptools_build.py | 146 + .../pip/_internal/utils/subprocess.py | 245 + .../pip/_internal/utils/temp_dir.py | 296 + .../pip/_internal/utils/unpacking.py | 337 + .../site-packages/pip/_internal/utils/urls.py | 55 + .../pip/_internal/utils/virtualenv.py | 104 + .../pip/_internal/utils/wheel.py | 134 + .../pip/_internal/vcs/__init__.py | 15 + .../vcs/__pycache__/__init__.cpython-312.pyc | Bin 0 -> 539 bytes .../vcs/__pycache__/bazaar.cpython-312.pyc | Bin 0 -> 5060 bytes .../vcs/__pycache__/git.cpython-312.pyc | Bin 0 -> 19025 bytes .../vcs/__pycache__/mercurial.cpython-312.pyc | Bin 0 -> 7613 bytes .../__pycache__/subversion.cpython-312.pyc | Bin 0 -> 12532 bytes .../versioncontrol.cpython-312.pyc | Bin 0 -> 29005 bytes .../site-packages/pip/_internal/vcs/bazaar.py | 112 + .../site-packages/pip/_internal/vcs/git.py | 527 + .../pip/_internal/vcs/mercurial.py | 163 + .../pip/_internal/vcs/subversion.py | 324 + .../pip/_internal/vcs/versioncontrol.py | 688 ++ .../pip/_internal/wheel_builder.py | 354 + .../site-packages/pip/_vendor/__init__.py | 116 + .../__pycache__/__init__.cpython-312.pyc | Bin 0 -> 4558 bytes .../typing_extensions.cpython-312.pyc | Bin 0 -> 139460 bytes .../pip/_vendor/cachecontrol/__init__.py | 28 + .../__pycache__/__init__.cpython-312.pyc | Bin 0 -> 911 bytes .../__pycache__/_cmd.cpython-312.pyc | Bin 0 -> 2655 bytes .../__pycache__/adapter.cpython-312.pyc | Bin 0 -> 6473 bytes .../__pycache__/cache.cpython-312.pyc | Bin 0 -> 3796 bytes .../__pycache__/controller.cpython-312.pyc | Bin 0 -> 16233 bytes .../__pycache__/filewrapper.cpython-312.pyc | Bin 0 -> 4356 bytes .../__pycache__/heuristics.cpython-312.pyc | Bin 0 -> 6703 bytes .../__pycache__/serialize.cpython-312.pyc | Bin 0 -> 5270 bytes .../__pycache__/wrapper.cpython-312.pyc | Bin 0 -> 1683 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-312.pyc | Bin 0 -> 444 bytes .../__pycache__/file_cache.cpython-312.pyc | Bin 0 -> 7772 bytes .../__pycache__/redis_cache.cpython-312.pyc | Bin 0 -> 2742 bytes .../_vendor/cachecontrol/caches/file_cache.py | 182 + .../cachecontrol/caches/redis_cache.py | 48 + .../pip/_vendor/cachecontrol/controller.py | 499 + .../pip/_vendor/cachecontrol/filewrapper.py | 119 + .../pip/_vendor/cachecontrol/heuristics.py | 154 + .../pip/_vendor/cachecontrol/py.typed | 0 .../pip/_vendor/cachecontrol/serialize.py | 146 + .../pip/_vendor/cachecontrol/wrapper.py | 43 + .../pip/_vendor/certifi/__init__.py | 4 + .../pip/_vendor/certifi/__main__.py | 12 + .../__pycache__/__init__.cpython-312.pyc | Bin 0 -> 327 bytes .../__pycache__/__main__.cpython-312.pyc | Bin 0 -> 654 bytes .../certifi/__pycache__/core.cpython-312.pyc | Bin 0 -> 3220 bytes .../pip/_vendor/certifi/cacert.pem | 4929 ++++++++++ .../site-packages/pip/_vendor/certifi/core.py | 114 + .../pip/_vendor/certifi/py.typed | 0 .../pip/_vendor/distlib/__init__.py | 33 + .../__pycache__/__init__.cpython-312.pyc | Bin 0 -> 1278 bytes .../__pycache__/compat.cpython-312.pyc | Bin 0 -> 45535 bytes .../__pycache__/database.cpython-312.pyc | Bin 0 -> 65590 bytes .../distlib/__pycache__/index.cpython-312.pyc | Bin 0 -> 24325 bytes .../__pycache__/locators.cpython-312.pyc | Bin 0 -> 59870 bytes .../__pycache__/manifest.cpython-312.pyc | Bin 0 -> 15085 bytes .../__pycache__/markers.cpython-312.pyc | Bin 0 -> 7663 bytes .../__pycache__/metadata.cpython-312.pyc | Bin 0 -> 41569 bytes .../__pycache__/resources.cpython-312.pyc | Bin 0 -> 17321 bytes .../__pycache__/scripts.cpython-312.pyc | Bin 0 -> 19762 bytes .../distlib/__pycache__/util.cpython-312.pyc | Bin 0 -> 88044 bytes .../__pycache__/version.cpython-312.pyc | Bin 0 -> 30353 bytes .../distlib/__pycache__/wheel.cpython-312.pyc | Bin 0 -> 52554 bytes .../pip/_vendor/distlib/compat.py | 1137 +++ .../pip/_vendor/distlib/database.py | 1329 +++ .../pip/_vendor/distlib/index.py | 508 + .../pip/_vendor/distlib/locators.py | 1295 +++ .../pip/_vendor/distlib/manifest.py | 384 + .../pip/_vendor/distlib/markers.py | 162 + .../pip/_vendor/distlib/metadata.py | 1031 ++ .../pip/_vendor/distlib/resources.py | 358 + .../pip/_vendor/distlib/scripts.py | 447 + .../site-packages/pip/_vendor/distlib/t32.exe | Bin 0 -> 97792 bytes .../pip/_vendor/distlib/t64-arm.exe | Bin 0 -> 182784 bytes .../site-packages/pip/_vendor/distlib/t64.exe | Bin 0 -> 108032 bytes .../site-packages/pip/_vendor/distlib/util.py | 1984 ++++ .../pip/_vendor/distlib/version.py | 750 ++ .../site-packages/pip/_vendor/distlib/w32.exe | Bin 0 -> 91648 bytes .../pip/_vendor/distlib/w64-arm.exe | Bin 0 -> 168448 bytes .../site-packages/pip/_vendor/distlib/w64.exe | Bin 0 -> 101888 bytes .../pip/_vendor/distlib/wheel.py | 1100 +++ .../pip/_vendor/distro/__init__.py | 54 + .../pip/_vendor/distro/__main__.py | 4 + .../__pycache__/__init__.cpython-312.pyc | Bin 0 -> 969 bytes .../__pycache__/__main__.cpython-312.pyc | Bin 0 -> 301 bytes .../distro/__pycache__/distro.cpython-312.pyc | Bin 0 -> 53801 bytes .../pip/_vendor/distro/distro.py | 1403 +++ .../site-packages/pip/_vendor/distro/py.typed | 0 .../pip/_vendor/idna/__init__.py | 44 + .../idna/__pycache__/__init__.cpython-312.pyc | Bin 0 -> 890 bytes .../idna/__pycache__/codec.cpython-312.pyc | Bin 0 -> 4985 bytes .../idna/__pycache__/compat.cpython-312.pyc | Bin 0 -> 896 bytes .../idna/__pycache__/core.cpython-312.pyc | Bin 0 -> 15800 bytes .../idna/__pycache__/idnadata.cpython-312.pyc | Bin 0 -> 99485 bytes .../__pycache__/intranges.cpython-312.pyc | Bin 0 -> 2642 bytes .../__pycache__/package_data.cpython-312.pyc | Bin 0 -> 225 bytes .../__pycache__/uts46data.cpython-312.pyc | Bin 0 -> 158857 bytes .../site-packages/pip/_vendor/idna/codec.py | 118 + .../site-packages/pip/_vendor/idna/compat.py | 13 + .../site-packages/pip/_vendor/idna/core.py | 395 + .../pip/_vendor/idna/idnadata.py | 4245 ++++++++ .../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 | 8598 ++++++++++++++++ .../pip/_vendor/msgpack/__init__.py | 55 + .../__pycache__/__init__.cpython-312.pyc | Bin 0 -> 1750 bytes .../__pycache__/exceptions.cpython-312.pyc | Bin 0 -> 2034 bytes .../msgpack/__pycache__/ext.cpython-312.pyc | Bin 0 -> 8179 bytes .../__pycache__/fallback.cpython-312.pyc | Bin 0 -> 42052 bytes .../pip/_vendor/msgpack/exceptions.py | 48 + .../site-packages/pip/_vendor/msgpack/ext.py | 168 + .../pip/_vendor/msgpack/fallback.py | 951 ++ .../pip/_vendor/packaging/__init__.py | 15 + .../__pycache__/__init__.cpython-312.pyc | Bin 0 -> 567 bytes .../__pycache__/_elffile.cpython-312.pyc | Bin 0 -> 4976 bytes .../__pycache__/_manylinux.cpython-312.pyc | Bin 0 -> 9694 bytes .../__pycache__/_musllinux.cpython-312.pyc | Bin 0 -> 4563 bytes .../__pycache__/_parser.cpython-312.pyc | Bin 0 -> 13994 bytes .../__pycache__/_structures.cpython-312.pyc | Bin 0 -> 3250 bytes .../__pycache__/_tokenizer.cpython-312.pyc | Bin 0 -> 7924 bytes .../__pycache__/markers.cpython-312.pyc | Bin 0 -> 11020 bytes .../__pycache__/metadata.cpython-312.pyc | Bin 0 -> 24962 bytes .../__pycache__/requirements.cpython-312.pyc | Bin 0 -> 4419 bytes .../__pycache__/specifiers.cpython-312.pyc | Bin 0 -> 38748 bytes .../__pycache__/tags.cpython-312.pyc | Bin 0 -> 23228 bytes .../__pycache__/utils.cpython-312.pyc | Bin 0 -> 7350 bytes .../__pycache__/version.cpython-312.pyc | Bin 0 -> 19516 bytes .../pip/_vendor/packaging/_elffile.py | 110 + .../pip/_vendor/packaging/_manylinux.py | 262 + .../pip/_vendor/packaging/_musllinux.py | 85 + .../pip/_vendor/packaging/_parser.py | 354 + .../pip/_vendor/packaging/_structures.py | 61 + .../pip/_vendor/packaging/_tokenizer.py | 194 + .../pip/_vendor/packaging/markers.py | 325 + .../pip/_vendor/packaging/metadata.py | 804 ++ .../pip/_vendor/packaging/py.typed | 0 .../pip/_vendor/packaging/requirements.py | 91 + .../pip/_vendor/packaging/specifiers.py | 1009 ++ .../pip/_vendor/packaging/tags.py | 627 ++ .../pip/_vendor/packaging/utils.py | 174 + .../pip/_vendor/packaging/version.py | 563 ++ .../pip/_vendor/pkg_resources/__init__.py | 3676 +++++++ .../__pycache__/__init__.cpython-312.pyc | Bin 0 -> 161270 bytes .../pip/_vendor/platformdirs/__init__.py | 627 ++ .../pip/_vendor/platformdirs/__main__.py | 55 + .../__pycache__/__init__.cpython-312.pyc | Bin 0 -> 19838 bytes .../__pycache__/__main__.cpython-312.pyc | Bin 0 -> 1957 bytes .../__pycache__/android.cpython-312.pyc | Bin 0 -> 10706 bytes .../__pycache__/api.cpython-312.pyc | Bin 0 -> 12920 bytes .../__pycache__/macos.cpython-312.pyc | Bin 0 -> 8016 bytes .../__pycache__/unix.cpython-312.pyc | Bin 0 -> 15046 bytes .../__pycache__/version.cpython-312.pyc | Bin 0 -> 606 bytes .../__pycache__/windows.cpython-312.pyc | Bin 0 -> 13683 bytes .../pip/_vendor/platformdirs/android.py | 249 + .../pip/_vendor/platformdirs/api.py | 292 + .../pip/_vendor/platformdirs/macos.py | 130 + .../pip/_vendor/platformdirs/py.typed | 0 .../pip/_vendor/platformdirs/unix.py | 275 + .../pip/_vendor/platformdirs/version.py | 16 + .../pip/_vendor/platformdirs/windows.py | 272 + .../pip/_vendor/pygments/__init__.py | 82 + .../pip/_vendor/pygments/__main__.py | 17 + .../__pycache__/__init__.cpython-312.pyc | Bin 0 -> 3498 bytes .../__pycache__/__main__.cpython-312.pyc | Bin 0 -> 744 bytes .../__pycache__/cmdline.cpython-312.pyc | Bin 0 -> 26594 bytes .../__pycache__/console.cpython-312.pyc | Bin 0 -> 2638 bytes .../__pycache__/filter.cpython-312.pyc | Bin 0 -> 3231 bytes .../__pycache__/formatter.cpython-312.pyc | Bin 0 -> 4730 bytes .../__pycache__/lexer.cpython-312.pyc | Bin 0 -> 38371 bytes .../__pycache__/modeline.cpython-312.pyc | Bin 0 -> 1569 bytes .../__pycache__/plugin.cpython-312.pyc | Bin 0 -> 2618 bytes .../__pycache__/regexopt.cpython-312.pyc | Bin 0 -> 4087 bytes .../__pycache__/scanner.cpython-312.pyc | Bin 0 -> 4766 bytes .../__pycache__/sphinxext.cpython-312.pyc | Bin 0 -> 12108 bytes .../__pycache__/style.cpython-312.pyc | Bin 0 -> 6703 bytes .../__pycache__/token.cpython-312.pyc | Bin 0 -> 8199 bytes .../__pycache__/unistring.cpython-312.pyc | Bin 0 -> 32982 bytes .../pygments/__pycache__/util.cpython-312.pyc | Bin 0 -> 14079 bytes .../pip/_vendor/pygments/cmdline.py | 668 ++ .../pip/_vendor/pygments/console.py | 70 + .../pip/_vendor/pygments/filter.py | 70 + .../pip/_vendor/pygments/filters/__init__.py | 940 ++ .../__pycache__/__init__.cpython-312.pyc | Bin 0 -> 37921 bytes .../pip/_vendor/pygments/formatter.py | 129 + .../_vendor/pygments/formatters/__init__.py | 157 + .../__pycache__/__init__.cpython-312.pyc | Bin 0 -> 6912 bytes .../__pycache__/_mapping.cpython-312.pyc | Bin 0 -> 4225 bytes .../__pycache__/bbcode.cpython-312.pyc | Bin 0 -> 4232 bytes .../__pycache__/groff.cpython-312.pyc | Bin 0 -> 7303 bytes .../__pycache__/html.cpython-312.pyc | Bin 0 -> 41036 bytes .../__pycache__/img.cpython-312.pyc | Bin 0 -> 28558 bytes .../__pycache__/irc.cpython-312.pyc | Bin 0 -> 6065 bytes .../__pycache__/latex.cpython-312.pyc | Bin 0 -> 20135 bytes .../__pycache__/other.cpython-312.pyc | Bin 0 -> 6887 bytes .../__pycache__/pangomarkup.cpython-312.pyc | Bin 0 -> 2968 bytes .../__pycache__/rtf.cpython-312.pyc | Bin 0 -> 13783 bytes .../__pycache__/svg.cpython-312.pyc | Bin 0 -> 9149 bytes .../__pycache__/terminal.cpython-312.pyc | Bin 0 -> 5829 bytes .../__pycache__/terminal256.cpython-312.pyc | Bin 0 -> 15128 bytes .../_vendor/pygments/formatters/_mapping.py | 23 + .../pip/_vendor/pygments/formatters/bbcode.py | 108 + .../pip/_vendor/pygments/formatters/groff.py | 170 + .../pip/_vendor/pygments/formatters/html.py | 987 ++ .../pip/_vendor/pygments/formatters/img.py | 685 ++ .../pip/_vendor/pygments/formatters/irc.py | 154 + .../pip/_vendor/pygments/formatters/latex.py | 518 + .../pip/_vendor/pygments/formatters/other.py | 160 + .../pygments/formatters/pangomarkup.py | 83 + .../pip/_vendor/pygments/formatters/rtf.py | 349 + .../pip/_vendor/pygments/formatters/svg.py | 185 + .../_vendor/pygments/formatters/terminal.py | 127 + .../pygments/formatters/terminal256.py | 338 + .../pip/_vendor/pygments/lexer.py | 963 ++ .../pip/_vendor/pygments/lexers/__init__.py | 362 + .../__pycache__/__init__.cpython-312.pyc | Bin 0 -> 14631 bytes .../__pycache__/_mapping.cpython-312.pyc | Bin 0 -> 68273 bytes .../lexers/__pycache__/python.cpython-312.pyc | Bin 0 -> 42977 bytes .../pip/_vendor/pygments/lexers/_mapping.py | 589 ++ .../pip/_vendor/pygments/lexers/python.py | 1198 +++ .../pip/_vendor/pygments/modeline.py | 43 + .../pip/_vendor/pygments/plugin.py | 72 + .../pip/_vendor/pygments/regexopt.py | 91 + .../pip/_vendor/pygments/scanner.py | 104 + .../pip/_vendor/pygments/sphinxext.py | 247 + .../pip/_vendor/pygments/style.py | 203 + .../pip/_vendor/pygments/styles/__init__.py | 61 + .../__pycache__/__init__.cpython-312.pyc | Bin 0 -> 2674 bytes .../__pycache__/_mapping.cpython-312.pyc | Bin 0 -> 3658 bytes .../pip/_vendor/pygments/styles/_mapping.py | 54 + .../pip/_vendor/pygments/token.py | 214 + .../pip/_vendor/pygments/unistring.py | 153 + .../pip/_vendor/pygments/util.py | 324 + .../pip/_vendor/pyproject_hooks/__init__.py | 23 + .../__pycache__/__init__.cpython-312.pyc | Bin 0 -> 623 bytes .../__pycache__/_compat.cpython-312.pyc | Bin 0 -> 384 bytes .../__pycache__/_impl.cpython-312.pyc | Bin 0 -> 14703 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-312.pyc | Bin 0 -> 1090 bytes .../__pycache__/_in_process.cpython-312.pyc | Bin 0 -> 14363 bytes .../_in_process/_in_process.py | 353 + .../pip/_vendor/requests/__init__.py | 179 + .../__pycache__/__init__.cpython-312.pyc | Bin 0 -> 5263 bytes .../__pycache__/__version__.cpython-312.pyc | Bin 0 -> 594 bytes .../_internal_utils.cpython-312.pyc | Bin 0 -> 2034 bytes .../__pycache__/adapters.cpython-312.pyc | Bin 0 -> 28441 bytes .../requests/__pycache__/api.cpython-312.pyc | Bin 0 -> 7201 bytes .../requests/__pycache__/auth.cpython-312.pyc | Bin 0 -> 13931 bytes .../__pycache__/certs.cpython-312.pyc | Bin 0 -> 932 bytes .../__pycache__/compat.cpython-312.pyc | Bin 0 -> 1687 bytes .../__pycache__/cookies.cpython-312.pyc | Bin 0 -> 25208 bytes .../__pycache__/exceptions.cpython-312.pyc | Bin 0 -> 7608 bytes .../requests/__pycache__/help.cpython-312.pyc | Bin 0 -> 4238 bytes .../__pycache__/hooks.cpython-312.pyc | Bin 0 -> 1061 bytes .../__pycache__/models.cpython-312.pyc | Bin 0 -> 35438 bytes .../__pycache__/packages.cpython-312.pyc | Bin 0 -> 1276 bytes .../__pycache__/sessions.cpython-312.pyc | Bin 0 -> 27856 bytes .../__pycache__/status_codes.cpython-312.pyc | Bin 0 -> 6033 bytes .../__pycache__/structures.cpython-312.pyc | Bin 0 -> 5633 bytes .../__pycache__/utils.cpython-312.pyc | Bin 0 -> 36376 bytes .../pip/_vendor/requests/__version__.py | 14 + .../pip/_vendor/requests/_internal_utils.py | 50 + .../pip/_vendor/requests/adapters.py | 719 ++ .../site-packages/pip/_vendor/requests/api.py | 157 + .../pip/_vendor/requests/auth.py | 314 + .../pip/_vendor/requests/certs.py | 24 + .../pip/_vendor/requests/compat.py | 78 + .../pip/_vendor/requests/cookies.py | 561 ++ .../pip/_vendor/requests/exceptions.py | 151 + .../pip/_vendor/requests/help.py | 127 + .../pip/_vendor/requests/hooks.py | 33 + .../pip/_vendor/requests/models.py | 1037 ++ .../pip/_vendor/requests/packages.py | 25 + .../pip/_vendor/requests/sessions.py | 831 ++ .../pip/_vendor/requests/status_codes.py | 128 + .../pip/_vendor/requests/structures.py | 99 + .../pip/_vendor/requests/utils.py | 1096 +++ .../pip/_vendor/resolvelib/__init__.py | 26 + .../__pycache__/__init__.cpython-312.pyc | Bin 0 -> 644 bytes .../__pycache__/providers.cpython-312.pyc | Bin 0 -> 6861 bytes .../__pycache__/reporters.cpython-312.pyc | Bin 0 -> 2664 bytes .../__pycache__/resolvers.cpython-312.pyc | Bin 0 -> 25890 bytes .../__pycache__/structs.cpython-312.pyc | Bin 0 -> 10510 bytes .../pip/_vendor/resolvelib/compat/__init__.py | 0 .../__pycache__/__init__.cpython-312.pyc | Bin 0 -> 210 bytes .../collections_abc.cpython-312.pyc | Bin 0 -> 430 bytes .../resolvelib/compat/collections_abc.py | 6 + .../pip/_vendor/resolvelib/providers.py | 133 + .../pip/_vendor/resolvelib/py.typed | 0 .../pip/_vendor/resolvelib/reporters.py | 43 + .../pip/_vendor/resolvelib/resolvers.py | 547 ++ .../pip/_vendor/resolvelib/structs.py | 170 + .../pip/_vendor/rich/__init__.py | 177 + .../pip/_vendor/rich/__main__.py | 273 + .../rich/__pycache__/__init__.cpython-312.pyc | Bin 0 -> 7025 bytes .../rich/__pycache__/__main__.cpython-312.pyc | Bin 0 -> 10302 bytes .../__pycache__/_cell_widths.cpython-312.pyc | Bin 0 -> 7882 bytes .../__pycache__/_emoji_codes.cpython-312.pyc | Bin 0 -> 205986 bytes .../_emoji_replace.cpython-312.pyc | Bin 0 -> 1739 bytes .../_export_format.cpython-312.pyc | Bin 0 -> 2359 bytes .../__pycache__/_extension.cpython-312.pyc | Bin 0 -> 547 bytes .../rich/__pycache__/_fileno.cpython-312.pyc | Bin 0 -> 865 bytes .../rich/__pycache__/_inspect.cpython-312.pyc | Bin 0 -> 12083 bytes .../__pycache__/_log_render.cpython-312.pyc | Bin 0 -> 4157 bytes .../rich/__pycache__/_loop.cpython-312.pyc | Bin 0 -> 1880 bytes .../__pycache__/_null_file.cpython-312.pyc | Bin 0 -> 3630 bytes .../__pycache__/_palettes.cpython-312.pyc | Bin 0 -> 5170 bytes .../rich/__pycache__/_pick.cpython-312.pyc | Bin 0 -> 731 bytes .../rich/__pycache__/_ratio.cpython-312.pyc | Bin 0 -> 6580 bytes .../__pycache__/_spinners.cpython-312.pyc | Bin 0 -> 13189 bytes .../rich/__pycache__/_stack.cpython-312.pyc | Bin 0 -> 975 bytes .../rich/__pycache__/_timer.cpython-312.pyc | Bin 0 -> 875 bytes .../_win32_console.cpython-312.pyc | Bin 0 -> 28986 bytes .../rich/__pycache__/_windows.cpython-312.pyc | Bin 0 -> 2500 bytes .../_windows_renderer.cpython-312.pyc | Bin 0 -> 3573 bytes .../rich/__pycache__/_wrap.cpython-312.pyc | Bin 0 -> 3336 bytes .../rich/__pycache__/abc.cpython-312.pyc | Bin 0 -> 1618 bytes .../rich/__pycache__/align.cpython-312.pyc | Bin 0 -> 12297 bytes .../rich/__pycache__/ansi.cpython-312.pyc | Bin 0 -> 9076 bytes .../rich/__pycache__/bar.cpython-312.pyc | Bin 0 -> 4282 bytes .../rich/__pycache__/box.cpython-312.pyc | Bin 0 -> 11848 bytes .../rich/__pycache__/cells.cpython-312.pyc | Bin 0 -> 5820 bytes .../rich/__pycache__/color.cpython-312.pyc | Bin 0 -> 26579 bytes .../__pycache__/color_triplet.cpython-312.pyc | Bin 0 -> 1711 bytes .../rich/__pycache__/columns.cpython-312.pyc | Bin 0 -> 8594 bytes .../rich/__pycache__/console.cpython-312.pyc | Bin 0 -> 113446 bytes .../__pycache__/constrain.cpython-312.pyc | Bin 0 -> 2268 bytes .../__pycache__/containers.cpython-312.pyc | Bin 0 -> 9220 bytes .../rich/__pycache__/control.cpython-312.pyc | Bin 0 -> 10951 bytes .../default_styles.cpython-312.pyc | Bin 0 -> 10376 bytes .../rich/__pycache__/diagnose.cpython-312.pyc | Bin 0 -> 1498 bytes .../rich/__pycache__/emoji.cpython-312.pyc | Bin 0 -> 4222 bytes .../rich/__pycache__/errors.cpython-312.pyc | Bin 0 -> 1855 bytes .../__pycache__/file_proxy.cpython-312.pyc | Bin 0 -> 3581 bytes .../rich/__pycache__/filesize.cpython-312.pyc | Bin 0 -> 3082 bytes .../__pycache__/highlighter.cpython-312.pyc | Bin 0 -> 9897 bytes .../rich/__pycache__/json.cpython-312.pyc | Bin 0 -> 6045 bytes .../rich/__pycache__/jupyter.cpython-312.pyc | Bin 0 -> 5218 bytes .../rich/__pycache__/layout.cpython-312.pyc | Bin 0 -> 20168 bytes .../rich/__pycache__/live.cpython-312.pyc | Bin 0 -> 19019 bytes .../__pycache__/live_render.cpython-312.pyc | Bin 0 -> 4899 bytes .../rich/__pycache__/logging.cpython-312.pyc | Bin 0 -> 13564 bytes .../rich/__pycache__/markup.cpython-312.pyc | Bin 0 -> 9577 bytes .../rich/__pycache__/measure.cpython-312.pyc | Bin 0 -> 6388 bytes .../rich/__pycache__/padding.cpython-312.pyc | Bin 0 -> 7134 bytes .../rich/__pycache__/pager.cpython-312.pyc | Bin 0 -> 1821 bytes .../rich/__pycache__/palette.cpython-312.pyc | Bin 0 -> 5307 bytes .../rich/__pycache__/panel.cpython-312.pyc | Bin 0 -> 12193 bytes .../rich/__pycache__/pretty.cpython-312.pyc | Bin 0 -> 40157 bytes .../rich/__pycache__/progress.cpython-312.pyc | Bin 0 -> 74945 bytes .../__pycache__/progress_bar.cpython-312.pyc | Bin 0 -> 10387 bytes .../rich/__pycache__/prompt.cpython-312.pyc | Bin 0 -> 14797 bytes .../rich/__pycache__/protocol.cpython-312.pyc | Bin 0 -> 1802 bytes .../rich/__pycache__/region.cpython-312.pyc | Bin 0 -> 577 bytes .../rich/__pycache__/repr.cpython-312.pyc | Bin 0 -> 6623 bytes .../rich/__pycache__/rule.cpython-312.pyc | Bin 0 -> 6578 bytes .../rich/__pycache__/scope.cpython-312.pyc | Bin 0 -> 3835 bytes .../rich/__pycache__/screen.cpython-312.pyc | Bin 0 -> 2489 bytes .../rich/__pycache__/segment.cpython-312.pyc | Bin 0 -> 28125 bytes .../rich/__pycache__/spinner.cpython-312.pyc | Bin 0 -> 6074 bytes .../rich/__pycache__/status.cpython-312.pyc | Bin 0 -> 6071 bytes .../rich/__pycache__/style.cpython-312.pyc | Bin 0 -> 33510 bytes .../rich/__pycache__/styled.cpython-312.pyc | Bin 0 -> 2149 bytes .../rich/__pycache__/syntax.cpython-312.pyc | Bin 0 -> 39958 bytes .../rich/__pycache__/table.cpython-312.pyc | Bin 0 -> 43549 bytes .../terminal_theme.cpython-312.pyc | Bin 0 -> 3358 bytes .../rich/__pycache__/text.cpython-312.pyc | Bin 0 -> 60859 bytes .../rich/__pycache__/theme.cpython-312.pyc | Bin 0 -> 6345 bytes .../rich/__pycache__/themes.cpython-312.pyc | Bin 0 -> 324 bytes .../__pycache__/traceback.cpython-312.pyc | Bin 0 -> 31521 bytes .../rich/__pycache__/tree.cpython-312.pyc | Bin 0 -> 11446 bytes .../pip/_vendor/rich/_cell_widths.py | 454 + .../pip/_vendor/rich/_emoji_codes.py | 3610 +++++++ .../pip/_vendor/rich/_emoji_replace.py | 32 + .../pip/_vendor/rich/_export_format.py | 76 + .../pip/_vendor/rich/_extension.py | 10 + .../site-packages/pip/_vendor/rich/_fileno.py | 24 + .../pip/_vendor/rich/_inspect.py | 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 | 159 + .../pip/_vendor/rich/_spinners.py | 482 + .../site-packages/pip/_vendor/rich/_stack.py | 16 + .../site-packages/pip/_vendor/rich/_timer.py | 19 + .../pip/_vendor/rich/_win32_console.py | 662 ++ .../pip/_vendor/rich/_windows.py | 71 + .../pip/_vendor/rich/_windows_renderer.py | 56 + .../site-packages/pip/_vendor/rich/_wrap.py | 93 + .../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 | 93 + .../site-packages/pip/_vendor/rich/box.py | 480 + .../site-packages/pip/_vendor/rich/cells.py | 167 + .../site-packages/pip/_vendor/rich/color.py | 621 ++ .../pip/_vendor/rich/color_triplet.py | 38 + .../site-packages/pip/_vendor/rich/columns.py | 187 + .../site-packages/pip/_vendor/rich/console.py | 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 | 139 + .../site-packages/pip/_vendor/rich/jupyter.py | 101 + .../site-packages/pip/_vendor/rich/layout.py | 442 + .../site-packages/pip/_vendor/rich/live.py | 375 + .../pip/_vendor/rich/live_render.py | 112 + .../site-packages/pip/_vendor/rich/logging.py | 289 + .../site-packages/pip/_vendor/rich/markup.py | 251 + .../site-packages/pip/_vendor/rich/measure.py | 151 + .../site-packages/pip/_vendor/rich/padding.py | 141 + .../site-packages/pip/_vendor/rich/pager.py | 34 + .../site-packages/pip/_vendor/rich/palette.py | 100 + .../site-packages/pip/_vendor/rich/panel.py | 312 + .../site-packages/pip/_vendor/rich/pretty.py | 995 ++ .../pip/_vendor/rich/progress.py | 1699 ++++ .../pip/_vendor/rich/progress_bar.py | 223 + .../site-packages/pip/_vendor/rich/prompt.py | 375 + .../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 | 738 ++ .../site-packages/pip/_vendor/rich/spinner.py | 137 + .../site-packages/pip/_vendor/rich/status.py | 131 + .../site-packages/pip/_vendor/rich/style.py | 796 ++ .../site-packages/pip/_vendor/rich/styled.py | 42 + .../site-packages/pip/_vendor/rich/syntax.py | 958 ++ .../site-packages/pip/_vendor/rich/table.py | 1000 ++ .../pip/_vendor/rich/terminal_theme.py | 153 + .../site-packages/pip/_vendor/rich/text.py | 1357 +++ .../site-packages/pip/_vendor/rich/theme.py | 115 + .../site-packages/pip/_vendor/rich/themes.py | 5 + .../pip/_vendor/rich/traceback.py | 753 ++ .../site-packages/pip/_vendor/rich/tree.py | 249 + .../pip/_vendor/tomli/__init__.py | 11 + .../__pycache__/__init__.cpython-312.pyc | Bin 0 -> 394 bytes .../tomli/__pycache__/_parser.cpython-312.pyc | Bin 0 -> 26909 bytes .../tomli/__pycache__/_re.cpython-312.pyc | Bin 0 -> 3918 bytes .../tomli/__pycache__/_types.cpython-312.pyc | Bin 0 -> 376 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 | 36 + .../__pycache__/__init__.cpython-312.pyc | Bin 0 -> 1354 bytes .../__pycache__/_api.cpython-312.pyc | Bin 0 -> 16783 bytes .../__pycache__/_macos.cpython-312.pyc | Bin 0 -> 18997 bytes .../__pycache__/_openssl.cpython-312.pyc | Bin 0 -> 2215 bytes .../_ssl_constants.cpython-312.pyc | Bin 0 -> 1109 bytes .../__pycache__/_windows.cpython-312.pyc | Bin 0 -> 15775 bytes .../pip/_vendor/truststore/_api.py | 316 + .../pip/_vendor/truststore/_macos.py | 571 ++ .../pip/_vendor/truststore/_openssl.py | 66 + .../pip/_vendor/truststore/_ssl_constants.py | 31 + .../pip/_vendor/truststore/_windows.py | 567 ++ .../pip/_vendor/truststore/py.typed | 0 .../pip/_vendor/typing_extensions.py | 3641 +++++++ .../pip/_vendor/urllib3/__init__.py | 102 + .../__pycache__/__init__.cpython-312.pyc | Bin 0 -> 3415 bytes .../__pycache__/_collections.cpython-312.pyc | Bin 0 -> 16374 bytes .../__pycache__/_version.cpython-312.pyc | Bin 0 -> 228 bytes .../__pycache__/connection.cpython-312.pyc | Bin 0 -> 20413 bytes .../connectionpool.cpython-312.pyc | Bin 0 -> 36548 bytes .../__pycache__/exceptions.cpython-312.pyc | Bin 0 -> 13503 bytes .../__pycache__/fields.cpython-312.pyc | Bin 0 -> 10412 bytes .../__pycache__/filepost.cpython-312.pyc | Bin 0 -> 4022 bytes .../__pycache__/poolmanager.cpython-312.pyc | Bin 0 -> 20439 bytes .../__pycache__/request.cpython-312.pyc | Bin 0 -> 7304 bytes .../__pycache__/response.cpython-312.pyc | Bin 0 -> 33953 bytes .../pip/_vendor/urllib3/_collections.py | 355 + .../pip/_vendor/urllib3/_version.py | 2 + .../pip/_vendor/urllib3/connection.py | 572 ++ .../pip/_vendor/urllib3/connectionpool.py | 1140 +++ .../pip/_vendor/urllib3/contrib/__init__.py | 0 .../__pycache__/__init__.cpython-312.pyc | Bin 0 -> 208 bytes .../_appengine_environ.cpython-312.pyc | Bin 0 -> 1858 bytes .../__pycache__/appengine.cpython-312.pyc | Bin 0 -> 11574 bytes .../__pycache__/ntlmpool.cpython-312.pyc | Bin 0 -> 5724 bytes .../__pycache__/pyopenssl.cpython-312.pyc | Bin 0 -> 24458 bytes .../securetransport.cpython-312.pyc | Bin 0 -> 35511 bytes .../contrib/__pycache__/socks.cpython-312.pyc | Bin 0 -> 7521 bytes .../urllib3/contrib/_appengine_environ.py | 36 + .../contrib/_securetransport/__init__.py | 0 .../__pycache__/__init__.cpython-312.pyc | Bin 0 -> 225 bytes .../__pycache__/bindings.cpython-312.pyc | Bin 0 -> 17437 bytes .../__pycache__/low_level.cpython-312.pyc | Bin 0 -> 14773 bytes .../contrib/_securetransport/bindings.py | 519 + .../contrib/_securetransport/low_level.py | 397 + .../pip/_vendor/urllib3/contrib/appengine.py | 314 + .../pip/_vendor/urllib3/contrib/ntlmpool.py | 130 + .../pip/_vendor/urllib3/contrib/pyopenssl.py | 518 + .../urllib3/contrib/securetransport.py | 920 ++ .../pip/_vendor/urllib3/contrib/socks.py | 216 + .../pip/_vendor/urllib3/exceptions.py | 323 + .../pip/_vendor/urllib3/fields.py | 274 + .../pip/_vendor/urllib3/filepost.py | 98 + .../pip/_vendor/urllib3/packages/__init__.py | 0 .../__pycache__/__init__.cpython-312.pyc | Bin 0 -> 209 bytes .../packages/__pycache__/six.cpython-312.pyc | Bin 0 -> 41265 bytes .../urllib3/packages/backports/__init__.py | 0 .../__pycache__/__init__.cpython-312.pyc | Bin 0 -> 219 bytes .../__pycache__/makefile.cpython-312.pyc | Bin 0 -> 1835 bytes .../weakref_finalize.cpython-312.pyc | Bin 0 -> 7346 bytes .../urllib3/packages/backports/makefile.py | 51 + .../packages/backports/weakref_finalize.py | 155 + .../pip/_vendor/urllib3/packages/six.py | 1076 ++ .../pip/_vendor/urllib3/poolmanager.py | 540 + .../pip/_vendor/urllib3/request.py | 191 + .../pip/_vendor/urllib3/response.py | 879 ++ .../pip/_vendor/urllib3/util/__init__.py | 49 + .../util/__pycache__/__init__.cpython-312.pyc | Bin 0 -> 1156 bytes .../__pycache__/connection.cpython-312.pyc | Bin 0 -> 4757 bytes .../util/__pycache__/proxy.cpython-312.pyc | Bin 0 -> 1562 bytes .../util/__pycache__/queue.cpython-312.pyc | Bin 0 -> 1362 bytes .../util/__pycache__/request.cpython-312.pyc | Bin 0 -> 4193 bytes .../util/__pycache__/response.cpython-312.pyc | Bin 0 -> 3002 bytes .../util/__pycache__/retry.cpython-312.pyc | Bin 0 -> 21732 bytes .../util/__pycache__/ssl_.cpython-312.pyc | Bin 0 -> 15374 bytes .../ssl_match_hostname.cpython-312.pyc | Bin 0 -> 5061 bytes .../__pycache__/ssltransport.cpython-312.pyc | Bin 0 -> 10763 bytes .../util/__pycache__/timeout.cpython-312.pyc | Bin 0 -> 11149 bytes .../util/__pycache__/url.cpython-312.pyc | Bin 0 -> 15795 bytes .../util/__pycache__/wait.cpython-312.pyc | Bin 0 -> 4413 bytes .../pip/_vendor/urllib3/util/connection.py | 149 + .../pip/_vendor/urllib3/util/proxy.py | 57 + .../pip/_vendor/urllib3/util/queue.py | 22 + .../pip/_vendor/urllib3/util/request.py | 137 + .../pip/_vendor/urllib3/util/response.py | 107 + .../pip/_vendor/urllib3/util/retry.py | 622 ++ .../pip/_vendor/urllib3/util/ssl_.py | 504 + .../urllib3/util/ssl_match_hostname.py | 159 + .../pip/_vendor/urllib3/util/ssltransport.py | 221 + .../pip/_vendor/urllib3/util/timeout.py | 271 + .../pip/_vendor/urllib3/util/url.py | 435 + .../pip/_vendor/urllib3/util/wait.py | 152 + .../site-packages/pip/_vendor/vendor.txt | 18 + .../lib/python3.12/site-packages/pip/py.typed | 4 + .../pytz-2024.2.dist-info/INSTALLER | 1 + .../pytz-2024.2.dist-info/LICENSE.txt | 19 + .../pytz-2024.2.dist-info/METADATA | 650 ++ .../pytz-2024.2.dist-info/RECORD | 623 ++ .../pytz-2024.2.dist-info/REQUESTED | 0 .../site-packages/pytz-2024.2.dist-info/WHEEL | 6 + .../pytz-2024.2.dist-info/top_level.txt | 1 + .../pytz-2024.2.dist-info/zip-safe | 1 + .../python3.12/site-packages/pytz/__init__.py | 1554 +++ .../pytz/__pycache__/__init__.cpython-312.pyc | Bin 0 -> 30497 bytes .../__pycache__/exceptions.cpython-312.pyc | Bin 0 -> 2310 bytes .../pytz/__pycache__/lazy.cpython-312.pyc | Bin 0 -> 7686 bytes .../__pycache__/reference.cpython-312.pyc | Bin 0 -> 5543 bytes .../pytz/__pycache__/tzfile.cpython-312.pyc | Bin 0 -> 5266 bytes .../pytz/__pycache__/tzinfo.cpython-312.pyc | Bin 0 -> 19274 bytes .../site-packages/pytz/exceptions.py | 59 + .../lib/python3.12/site-packages/pytz/lazy.py | 172 + .../site-packages/pytz/reference.py | 140 + .../python3.12/site-packages/pytz/tzfile.py | 133 + .../python3.12/site-packages/pytz/tzinfo.py | 580 ++ .../pytz/zoneinfo/Africa/Abidjan | Bin 0 -> 148 bytes .../site-packages/pytz/zoneinfo/Africa/Accra | Bin 0 -> 148 bytes .../pytz/zoneinfo/Africa/Addis_Ababa | Bin 0 -> 265 bytes .../pytz/zoneinfo/Africa/Algiers | Bin 0 -> 735 bytes .../site-packages/pytz/zoneinfo/Africa/Asmara | Bin 0 -> 265 bytes .../site-packages/pytz/zoneinfo/Africa/Asmera | Bin 0 -> 265 bytes .../site-packages/pytz/zoneinfo/Africa/Bamako | Bin 0 -> 148 bytes .../site-packages/pytz/zoneinfo/Africa/Bangui | Bin 0 -> 235 bytes .../site-packages/pytz/zoneinfo/Africa/Banjul | Bin 0 -> 148 bytes .../site-packages/pytz/zoneinfo/Africa/Bissau | Bin 0 -> 194 bytes .../pytz/zoneinfo/Africa/Blantyre | Bin 0 -> 149 bytes .../pytz/zoneinfo/Africa/Brazzaville | Bin 0 -> 235 bytes .../pytz/zoneinfo/Africa/Bujumbura | Bin 0 -> 149 bytes .../site-packages/pytz/zoneinfo/Africa/Cairo | Bin 0 -> 2399 bytes .../pytz/zoneinfo/Africa/Casablanca | Bin 0 -> 2429 bytes .../site-packages/pytz/zoneinfo/Africa/Ceuta | Bin 0 -> 2052 bytes .../pytz/zoneinfo/Africa/Conakry | Bin 0 -> 148 bytes .../site-packages/pytz/zoneinfo/Africa/Dakar | Bin 0 -> 148 bytes .../pytz/zoneinfo/Africa/Dar_es_Salaam | Bin 0 -> 265 bytes .../pytz/zoneinfo/Africa/Djibouti | Bin 0 -> 265 bytes .../site-packages/pytz/zoneinfo/Africa/Douala | Bin 0 -> 235 bytes .../pytz/zoneinfo/Africa/El_Aaiun | Bin 0 -> 2295 bytes .../pytz/zoneinfo/Africa/Freetown | Bin 0 -> 148 bytes .../pytz/zoneinfo/Africa/Gaborone | Bin 0 -> 149 bytes .../site-packages/pytz/zoneinfo/Africa/Harare | Bin 0 -> 149 bytes .../pytz/zoneinfo/Africa/Johannesburg | Bin 0 -> 246 bytes .../site-packages/pytz/zoneinfo/Africa/Juba | Bin 0 -> 679 bytes .../pytz/zoneinfo/Africa/Kampala | Bin 0 -> 265 bytes .../pytz/zoneinfo/Africa/Khartoum | Bin 0 -> 679 bytes .../site-packages/pytz/zoneinfo/Africa/Kigali | Bin 0 -> 149 bytes .../pytz/zoneinfo/Africa/Kinshasa | Bin 0 -> 235 bytes .../site-packages/pytz/zoneinfo/Africa/Lagos | Bin 0 -> 235 bytes .../pytz/zoneinfo/Africa/Libreville | Bin 0 -> 235 bytes .../site-packages/pytz/zoneinfo/Africa/Lome | Bin 0 -> 148 bytes .../site-packages/pytz/zoneinfo/Africa/Luanda | Bin 0 -> 235 bytes .../pytz/zoneinfo/Africa/Lubumbashi | Bin 0 -> 149 bytes .../site-packages/pytz/zoneinfo/Africa/Lusaka | Bin 0 -> 149 bytes .../site-packages/pytz/zoneinfo/Africa/Malabo | Bin 0 -> 235 bytes .../site-packages/pytz/zoneinfo/Africa/Maputo | Bin 0 -> 149 bytes .../site-packages/pytz/zoneinfo/Africa/Maseru | Bin 0 -> 246 bytes .../pytz/zoneinfo/Africa/Mbabane | Bin 0 -> 246 bytes .../pytz/zoneinfo/Africa/Mogadishu | Bin 0 -> 265 bytes .../pytz/zoneinfo/Africa/Monrovia | Bin 0 -> 208 bytes .../pytz/zoneinfo/Africa/Nairobi | Bin 0 -> 265 bytes .../pytz/zoneinfo/Africa/Ndjamena | Bin 0 -> 199 bytes .../site-packages/pytz/zoneinfo/Africa/Niamey | Bin 0 -> 235 bytes .../pytz/zoneinfo/Africa/Nouakchott | Bin 0 -> 148 bytes .../pytz/zoneinfo/Africa/Ouagadougou | Bin 0 -> 148 bytes .../pytz/zoneinfo/Africa/Porto-Novo | Bin 0 -> 235 bytes .../pytz/zoneinfo/Africa/Sao_Tome | Bin 0 -> 254 bytes .../pytz/zoneinfo/Africa/Timbuktu | Bin 0 -> 148 bytes .../pytz/zoneinfo/Africa/Tripoli | Bin 0 -> 625 bytes .../site-packages/pytz/zoneinfo/Africa/Tunis | Bin 0 -> 689 bytes .../pytz/zoneinfo/Africa/Windhoek | Bin 0 -> 955 bytes .../site-packages/pytz/zoneinfo/America/Adak | Bin 0 -> 2356 bytes .../pytz/zoneinfo/America/Anchorage | Bin 0 -> 2371 bytes .../pytz/zoneinfo/America/Anguilla | Bin 0 -> 246 bytes .../pytz/zoneinfo/America/Antigua | Bin 0 -> 246 bytes .../pytz/zoneinfo/America/Araguaina | Bin 0 -> 870 bytes .../zoneinfo/America/Argentina/Buenos_Aires | Bin 0 -> 1062 bytes .../pytz/zoneinfo/America/Argentina/Catamarca | Bin 0 -> 1062 bytes .../zoneinfo/America/Argentina/ComodRivadavia | Bin 0 -> 1062 bytes .../pytz/zoneinfo/America/Argentina/Cordoba | Bin 0 -> 1062 bytes .../pytz/zoneinfo/America/Argentina/Jujuy | Bin 0 -> 1034 bytes .../pytz/zoneinfo/America/Argentina/La_Rioja | Bin 0 -> 1076 bytes .../pytz/zoneinfo/America/Argentina/Mendoza | Bin 0 -> 1062 bytes .../zoneinfo/America/Argentina/Rio_Gallegos | Bin 0 -> 1062 bytes .../pytz/zoneinfo/America/Argentina/Salta | Bin 0 -> 1034 bytes .../pytz/zoneinfo/America/Argentina/San_Juan | Bin 0 -> 1076 bytes .../pytz/zoneinfo/America/Argentina/San_Luis | Bin 0 -> 1088 bytes .../pytz/zoneinfo/America/Argentina/Tucuman | Bin 0 -> 1090 bytes .../pytz/zoneinfo/America/Argentina/Ushuaia | Bin 0 -> 1062 bytes .../site-packages/pytz/zoneinfo/America/Aruba | Bin 0 -> 246 bytes .../pytz/zoneinfo/America/Asuncion | Bin 0 -> 2030 bytes .../pytz/zoneinfo/America/Atikokan | Bin 0 -> 182 bytes .../site-packages/pytz/zoneinfo/America/Atka | Bin 0 -> 2356 bytes .../site-packages/pytz/zoneinfo/America/Bahia | Bin 0 -> 1010 bytes .../pytz/zoneinfo/America/Bahia_Banderas | Bin 0 -> 1100 bytes .../pytz/zoneinfo/America/Barbados | Bin 0 -> 436 bytes .../site-packages/pytz/zoneinfo/America/Belem | Bin 0 -> 562 bytes .../pytz/zoneinfo/America/Belize | Bin 0 -> 1614 bytes .../pytz/zoneinfo/America/Blanc-Sablon | Bin 0 -> 246 bytes .../pytz/zoneinfo/America/Boa_Vista | Bin 0 -> 618 bytes .../pytz/zoneinfo/America/Bogota | Bin 0 -> 232 bytes .../site-packages/pytz/zoneinfo/America/Boise | Bin 0 -> 2410 bytes .../pytz/zoneinfo/America/Buenos_Aires | Bin 0 -> 1062 bytes .../pytz/zoneinfo/America/Cambridge_Bay | Bin 0 -> 2254 bytes .../pytz/zoneinfo/America/Campo_Grande | Bin 0 -> 1430 bytes .../pytz/zoneinfo/America/Cancun | Bin 0 -> 864 bytes .../pytz/zoneinfo/America/Caracas | Bin 0 -> 250 bytes .../pytz/zoneinfo/America/Catamarca | Bin 0 -> 1062 bytes .../pytz/zoneinfo/America/Cayenne | Bin 0 -> 184 bytes .../pytz/zoneinfo/America/Cayman | Bin 0 -> 182 bytes .../pytz/zoneinfo/America/Chicago | Bin 0 -> 3592 bytes .../pytz/zoneinfo/America/Chihuahua | Bin 0 -> 1102 bytes .../pytz/zoneinfo/America/Ciudad_Juarez | Bin 0 -> 1538 bytes .../pytz/zoneinfo/America/Coral_Harbour | Bin 0 -> 182 bytes .../pytz/zoneinfo/America/Cordoba | Bin 0 -> 1062 bytes .../pytz/zoneinfo/America/Costa_Rica | Bin 0 -> 316 bytes .../pytz/zoneinfo/America/Creston | Bin 0 -> 360 bytes .../pytz/zoneinfo/America/Cuiaba | Bin 0 -> 1402 bytes .../pytz/zoneinfo/America/Curacao | Bin 0 -> 246 bytes .../pytz/zoneinfo/America/Danmarkshavn | Bin 0 -> 698 bytes .../pytz/zoneinfo/America/Dawson | Bin 0 -> 1614 bytes .../pytz/zoneinfo/America/Dawson_Creek | Bin 0 -> 1050 bytes .../pytz/zoneinfo/America/Denver | Bin 0 -> 2460 bytes .../pytz/zoneinfo/America/Detroit | Bin 0 -> 2230 bytes .../pytz/zoneinfo/America/Dominica | Bin 0 -> 246 bytes .../pytz/zoneinfo/America/Edmonton | Bin 0 -> 2332 bytes .../pytz/zoneinfo/America/Eirunepe | Bin 0 -> 642 bytes .../pytz/zoneinfo/America/El_Salvador | Bin 0 -> 224 bytes .../pytz/zoneinfo/America/Ensenada | Bin 0 -> 2458 bytes .../pytz/zoneinfo/America/Fort_Nelson | Bin 0 -> 2240 bytes .../pytz/zoneinfo/America/Fort_Wayne | Bin 0 -> 1682 bytes .../pytz/zoneinfo/America/Fortaleza | Bin 0 -> 702 bytes .../pytz/zoneinfo/America/Glace_Bay | Bin 0 -> 2192 bytes .../pytz/zoneinfo/America/Godthab | Bin 0 -> 1889 bytes .../pytz/zoneinfo/America/Goose_Bay | Bin 0 -> 3210 bytes .../pytz/zoneinfo/America/Grand_Turk | Bin 0 -> 1834 bytes .../pytz/zoneinfo/America/Grenada | Bin 0 -> 246 bytes .../pytz/zoneinfo/America/Guadeloupe | Bin 0 -> 246 bytes .../pytz/zoneinfo/America/Guatemala | Bin 0 -> 280 bytes .../pytz/zoneinfo/America/Guayaquil | Bin 0 -> 232 bytes .../pytz/zoneinfo/America/Guyana | Bin 0 -> 248 bytes .../pytz/zoneinfo/America/Halifax | Bin 0 -> 3424 bytes .../pytz/zoneinfo/America/Havana | Bin 0 -> 2416 bytes .../pytz/zoneinfo/America/Hermosillo | Bin 0 -> 388 bytes .../zoneinfo/America/Indiana/Indianapolis | Bin 0 -> 1682 bytes .../pytz/zoneinfo/America/Indiana/Knox | Bin 0 -> 2444 bytes .../pytz/zoneinfo/America/Indiana/Marengo | Bin 0 -> 1738 bytes .../pytz/zoneinfo/America/Indiana/Petersburg | Bin 0 -> 1920 bytes .../pytz/zoneinfo/America/Indiana/Tell_City | Bin 0 -> 1700 bytes .../pytz/zoneinfo/America/Indiana/Vevay | Bin 0 -> 1430 bytes .../pytz/zoneinfo/America/Indiana/Vincennes | Bin 0 -> 1710 bytes .../pytz/zoneinfo/America/Indiana/Winamac | Bin 0 -> 1794 bytes .../pytz/zoneinfo/America/Indianapolis | Bin 0 -> 1682 bytes .../pytz/zoneinfo/America/Inuvik | Bin 0 -> 2074 bytes .../pytz/zoneinfo/America/Iqaluit | Bin 0 -> 2202 bytes .../pytz/zoneinfo/America/Jamaica | Bin 0 -> 482 bytes .../site-packages/pytz/zoneinfo/America/Jujuy | Bin 0 -> 1034 bytes .../pytz/zoneinfo/America/Juneau | Bin 0 -> 2353 bytes .../pytz/zoneinfo/America/Kentucky/Louisville | Bin 0 -> 2788 bytes .../pytz/zoneinfo/America/Kentucky/Monticello | Bin 0 -> 2368 bytes .../pytz/zoneinfo/America/Knox_IN | Bin 0 -> 2444 bytes .../pytz/zoneinfo/America/Kralendijk | Bin 0 -> 246 bytes .../pytz/zoneinfo/America/La_Paz | Bin 0 -> 218 bytes .../site-packages/pytz/zoneinfo/America/Lima | Bin 0 -> 392 bytes .../pytz/zoneinfo/America/Los_Angeles | Bin 0 -> 2852 bytes .../pytz/zoneinfo/America/Louisville | Bin 0 -> 2788 bytes .../pytz/zoneinfo/America/Lower_Princes | Bin 0 -> 246 bytes .../pytz/zoneinfo/America/Maceio | Bin 0 -> 730 bytes .../pytz/zoneinfo/America/Managua | Bin 0 -> 430 bytes .../pytz/zoneinfo/America/Manaus | Bin 0 -> 590 bytes .../pytz/zoneinfo/America/Marigot | Bin 0 -> 246 bytes .../pytz/zoneinfo/America/Martinique | Bin 0 -> 232 bytes .../pytz/zoneinfo/America/Matamoros | Bin 0 -> 1418 bytes .../pytz/zoneinfo/America/Mazatlan | Bin 0 -> 1060 bytes .../pytz/zoneinfo/America/Mendoza | Bin 0 -> 1062 bytes .../pytz/zoneinfo/America/Menominee | Bin 0 -> 2274 bytes .../pytz/zoneinfo/America/Merida | Bin 0 -> 1004 bytes .../pytz/zoneinfo/America/Metlakatla | Bin 0 -> 1423 bytes .../pytz/zoneinfo/America/Mexico_City | Bin 0 -> 1222 bytes .../pytz/zoneinfo/America/Miquelon | Bin 0 -> 1652 bytes .../pytz/zoneinfo/America/Moncton | Bin 0 -> 3154 bytes .../pytz/zoneinfo/America/Monterrey | Bin 0 -> 1114 bytes .../pytz/zoneinfo/America/Montevideo | Bin 0 -> 1496 bytes .../pytz/zoneinfo/America/Montreal | Bin 0 -> 3494 bytes .../pytz/zoneinfo/America/Montserrat | Bin 0 -> 246 bytes .../pytz/zoneinfo/America/Nassau | Bin 0 -> 3494 bytes .../pytz/zoneinfo/America/New_York | Bin 0 -> 3552 bytes .../pytz/zoneinfo/America/Nipigon | Bin 0 -> 3494 bytes .../site-packages/pytz/zoneinfo/America/Nome | Bin 0 -> 2367 bytes .../pytz/zoneinfo/America/Noronha | Bin 0 -> 702 bytes .../pytz/zoneinfo/America/North_Dakota/Beulah | Bin 0 -> 2396 bytes .../pytz/zoneinfo/America/North_Dakota/Center | Bin 0 -> 2396 bytes .../zoneinfo/America/North_Dakota/New_Salem | Bin 0 -> 2396 bytes .../site-packages/pytz/zoneinfo/America/Nuuk | Bin 0 -> 1889 bytes .../pytz/zoneinfo/America/Ojinaga | Bin 0 -> 1524 bytes .../pytz/zoneinfo/America/Panama | Bin 0 -> 182 bytes .../pytz/zoneinfo/America/Pangnirtung | Bin 0 -> 2202 bytes .../pytz/zoneinfo/America/Paramaribo | Bin 0 -> 248 bytes .../pytz/zoneinfo/America/Phoenix | Bin 0 -> 360 bytes .../pytz/zoneinfo/America/Port-au-Prince | Bin 0 -> 1434 bytes .../pytz/zoneinfo/America/Port_of_Spain | Bin 0 -> 246 bytes .../pytz/zoneinfo/America/Porto_Acre | Bin 0 -> 614 bytes .../pytz/zoneinfo/America/Porto_Velho | Bin 0 -> 562 bytes .../pytz/zoneinfo/America/Puerto_Rico | Bin 0 -> 246 bytes .../pytz/zoneinfo/America/Punta_Arenas | Bin 0 -> 1902 bytes .../pytz/zoneinfo/America/Rainy_River | Bin 0 -> 2868 bytes .../pytz/zoneinfo/America/Rankin_Inlet | Bin 0 -> 2066 bytes .../pytz/zoneinfo/America/Recife | Bin 0 -> 702 bytes .../pytz/zoneinfo/America/Regina | Bin 0 -> 980 bytes .../pytz/zoneinfo/America/Resolute | Bin 0 -> 2066 bytes .../pytz/zoneinfo/America/Rio_Branco | Bin 0 -> 614 bytes .../pytz/zoneinfo/America/Rosario | Bin 0 -> 1062 bytes .../pytz/zoneinfo/America/Santa_Isabel | Bin 0 -> 2458 bytes .../pytz/zoneinfo/America/Santarem | Bin 0 -> 588 bytes .../pytz/zoneinfo/America/Santiago | Bin 0 -> 2515 bytes .../pytz/zoneinfo/America/Santo_Domingo | Bin 0 -> 458 bytes .../pytz/zoneinfo/America/Sao_Paulo | Bin 0 -> 1430 bytes .../pytz/zoneinfo/America/Scoresbysund | Bin 0 -> 1935 bytes .../pytz/zoneinfo/America/Shiprock | Bin 0 -> 2460 bytes .../site-packages/pytz/zoneinfo/America/Sitka | Bin 0 -> 2329 bytes .../pytz/zoneinfo/America/St_Barthelemy | Bin 0 -> 246 bytes .../pytz/zoneinfo/America/St_Johns | Bin 0 -> 3655 bytes .../pytz/zoneinfo/America/St_Kitts | Bin 0 -> 246 bytes .../pytz/zoneinfo/America/St_Lucia | Bin 0 -> 246 bytes .../pytz/zoneinfo/America/St_Thomas | Bin 0 -> 246 bytes .../pytz/zoneinfo/America/St_Vincent | Bin 0 -> 246 bytes .../pytz/zoneinfo/America/Swift_Current | Bin 0 -> 560 bytes .../pytz/zoneinfo/America/Tegucigalpa | Bin 0 -> 252 bytes .../site-packages/pytz/zoneinfo/America/Thule | Bin 0 -> 1502 bytes .../pytz/zoneinfo/America/Thunder_Bay | Bin 0 -> 3494 bytes .../pytz/zoneinfo/America/Tijuana | Bin 0 -> 2458 bytes .../pytz/zoneinfo/America/Toronto | Bin 0 -> 3494 bytes .../pytz/zoneinfo/America/Tortola | Bin 0 -> 246 bytes .../pytz/zoneinfo/America/Vancouver | Bin 0 -> 2892 bytes .../pytz/zoneinfo/America/Virgin | Bin 0 -> 246 bytes .../pytz/zoneinfo/America/Whitehorse | Bin 0 -> 1614 bytes .../pytz/zoneinfo/America/Winnipeg | Bin 0 -> 2868 bytes .../pytz/zoneinfo/America/Yakutat | Bin 0 -> 2305 bytes .../pytz/zoneinfo/America/Yellowknife | Bin 0 -> 2332 bytes .../pytz/zoneinfo/Antarctica/Casey | Bin 0 -> 423 bytes .../pytz/zoneinfo/Antarctica/Davis | Bin 0 -> 283 bytes .../pytz/zoneinfo/Antarctica/DumontDUrville | Bin 0 -> 172 bytes .../pytz/zoneinfo/Antarctica/Macquarie | Bin 0 -> 2260 bytes .../pytz/zoneinfo/Antarctica/Mawson | Bin 0 -> 185 bytes .../pytz/zoneinfo/Antarctica/McMurdo | Bin 0 -> 2437 bytes .../pytz/zoneinfo/Antarctica/Palmer | Bin 0 -> 1404 bytes .../pytz/zoneinfo/Antarctica/Rothera | Bin 0 -> 150 bytes .../pytz/zoneinfo/Antarctica/South_Pole | Bin 0 -> 2437 bytes .../pytz/zoneinfo/Antarctica/Syowa | Bin 0 -> 151 bytes .../pytz/zoneinfo/Antarctica/Troll | Bin 0 -> 1148 bytes .../pytz/zoneinfo/Antarctica/Vostok | Bin 0 -> 213 bytes .../pytz/zoneinfo/Arctic/Longyearbyen | Bin 0 -> 2298 bytes .../site-packages/pytz/zoneinfo/Asia/Aden | Bin 0 -> 151 bytes .../site-packages/pytz/zoneinfo/Asia/Almaty | Bin 0 -> 983 bytes .../site-packages/pytz/zoneinfo/Asia/Amman | Bin 0 -> 1433 bytes .../site-packages/pytz/zoneinfo/Asia/Anadyr | Bin 0 -> 1174 bytes .../site-packages/pytz/zoneinfo/Asia/Aqtau | Bin 0 -> 969 bytes .../site-packages/pytz/zoneinfo/Asia/Aqtobe | Bin 0 -> 997 bytes .../site-packages/pytz/zoneinfo/Asia/Ashgabat | Bin 0 -> 605 bytes .../pytz/zoneinfo/Asia/Ashkhabad | Bin 0 -> 605 bytes .../site-packages/pytz/zoneinfo/Asia/Atyrau | Bin 0 -> 977 bytes .../site-packages/pytz/zoneinfo/Asia/Baghdad | Bin 0 -> 969 bytes .../site-packages/pytz/zoneinfo/Asia/Bahrain | Bin 0 -> 185 bytes .../site-packages/pytz/zoneinfo/Asia/Baku | Bin 0 -> 1213 bytes .../site-packages/pytz/zoneinfo/Asia/Bangkok | Bin 0 -> 185 bytes .../site-packages/pytz/zoneinfo/Asia/Barnaul | Bin 0 -> 1207 bytes .../site-packages/pytz/zoneinfo/Asia/Beirut | Bin 0 -> 2154 bytes .../site-packages/pytz/zoneinfo/Asia/Bishkek | Bin 0 -> 969 bytes .../site-packages/pytz/zoneinfo/Asia/Brunei | Bin 0 -> 469 bytes .../site-packages/pytz/zoneinfo/Asia/Calcutta | Bin 0 -> 285 bytes .../site-packages/pytz/zoneinfo/Asia/Chita | Bin 0 -> 1207 bytes .../pytz/zoneinfo/Asia/Choibalsan | Bin 0 -> 877 bytes .../pytz/zoneinfo/Asia/Chongqing | Bin 0 -> 561 bytes .../pytz/zoneinfo/Asia/Chungking | Bin 0 -> 561 bytes .../site-packages/pytz/zoneinfo/Asia/Colombo | Bin 0 -> 358 bytes .../site-packages/pytz/zoneinfo/Asia/Dacca | Bin 0 -> 323 bytes .../site-packages/pytz/zoneinfo/Asia/Damascus | Bin 0 -> 1873 bytes .../site-packages/pytz/zoneinfo/Asia/Dhaka | Bin 0 -> 323 bytes .../site-packages/pytz/zoneinfo/Asia/Dili | Bin 0 -> 257 bytes .../site-packages/pytz/zoneinfo/Asia/Dubai | Bin 0 -> 151 bytes .../site-packages/pytz/zoneinfo/Asia/Dushanbe | Bin 0 -> 577 bytes .../pytz/zoneinfo/Asia/Famagusta | Bin 0 -> 2028 bytes .../site-packages/pytz/zoneinfo/Asia/Gaza | Bin 0 -> 3844 bytes .../site-packages/pytz/zoneinfo/Asia/Harbin | Bin 0 -> 561 bytes .../site-packages/pytz/zoneinfo/Asia/Hebron | Bin 0 -> 3872 bytes .../pytz/zoneinfo/Asia/Ho_Chi_Minh | Bin 0 -> 337 bytes .../pytz/zoneinfo/Asia/Hong_Kong | Bin 0 -> 1233 bytes .../site-packages/pytz/zoneinfo/Asia/Hovd | Bin 0 -> 877 bytes .../site-packages/pytz/zoneinfo/Asia/Irkutsk | Bin 0 -> 1229 bytes .../site-packages/pytz/zoneinfo/Asia/Istanbul | Bin 0 -> 1933 bytes .../site-packages/pytz/zoneinfo/Asia/Jakarta | Bin 0 -> 383 bytes .../site-packages/pytz/zoneinfo/Asia/Jayapura | Bin 0 -> 221 bytes .../pytz/zoneinfo/Asia/Jerusalem | Bin 0 -> 2388 bytes .../site-packages/pytz/zoneinfo/Asia/Kabul | Bin 0 -> 194 bytes .../pytz/zoneinfo/Asia/Kamchatka | Bin 0 -> 1152 bytes .../site-packages/pytz/zoneinfo/Asia/Karachi | Bin 0 -> 379 bytes .../site-packages/pytz/zoneinfo/Asia/Kashgar | Bin 0 -> 151 bytes .../pytz/zoneinfo/Asia/Kathmandu | Bin 0 -> 198 bytes .../site-packages/pytz/zoneinfo/Asia/Katmandu | Bin 0 -> 198 bytes .../site-packages/pytz/zoneinfo/Asia/Khandyga | Bin 0 -> 1257 bytes .../site-packages/pytz/zoneinfo/Asia/Kolkata | Bin 0 -> 285 bytes .../pytz/zoneinfo/Asia/Krasnoyarsk | Bin 0 -> 1193 bytes .../pytz/zoneinfo/Asia/Kuala_Lumpur | Bin 0 -> 401 bytes .../site-packages/pytz/zoneinfo/Asia/Kuching | Bin 0 -> 469 bytes .../site-packages/pytz/zoneinfo/Asia/Kuwait | Bin 0 -> 151 bytes .../site-packages/pytz/zoneinfo/Asia/Macao | Bin 0 -> 1227 bytes .../site-packages/pytz/zoneinfo/Asia/Macau | Bin 0 -> 1227 bytes .../site-packages/pytz/zoneinfo/Asia/Magadan | Bin 0 -> 1208 bytes .../site-packages/pytz/zoneinfo/Asia/Makassar | Bin 0 -> 254 bytes .../site-packages/pytz/zoneinfo/Asia/Manila | Bin 0 -> 328 bytes .../site-packages/pytz/zoneinfo/Asia/Muscat | Bin 0 -> 151 bytes .../site-packages/pytz/zoneinfo/Asia/Nicosia | Bin 0 -> 2002 bytes .../pytz/zoneinfo/Asia/Novokuznetsk | Bin 0 -> 1151 bytes .../pytz/zoneinfo/Asia/Novosibirsk | Bin 0 -> 1207 bytes .../site-packages/pytz/zoneinfo/Asia/Omsk | Bin 0 -> 1193 bytes .../site-packages/pytz/zoneinfo/Asia/Oral | Bin 0 -> 991 bytes .../pytz/zoneinfo/Asia/Phnom_Penh | Bin 0 -> 185 bytes .../pytz/zoneinfo/Asia/Pontianak | Bin 0 -> 353 bytes .../pytz/zoneinfo/Asia/Pyongyang | Bin 0 -> 237 bytes .../site-packages/pytz/zoneinfo/Asia/Qatar | Bin 0 -> 185 bytes .../site-packages/pytz/zoneinfo/Asia/Qostanay | Bin 0 -> 1025 bytes .../pytz/zoneinfo/Asia/Qyzylorda | Bin 0 -> 1011 bytes .../site-packages/pytz/zoneinfo/Asia/Rangoon | Bin 0 -> 254 bytes .../site-packages/pytz/zoneinfo/Asia/Riyadh | Bin 0 -> 151 bytes .../site-packages/pytz/zoneinfo/Asia/Saigon | Bin 0 -> 337 bytes .../site-packages/pytz/zoneinfo/Asia/Sakhalin | Bin 0 -> 1188 bytes .../pytz/zoneinfo/Asia/Samarkand | Bin 0 -> 563 bytes .../site-packages/pytz/zoneinfo/Asia/Seoul | Bin 0 -> 617 bytes .../site-packages/pytz/zoneinfo/Asia/Shanghai | Bin 0 -> 561 bytes .../pytz/zoneinfo/Asia/Singapore | Bin 0 -> 401 bytes .../pytz/zoneinfo/Asia/Srednekolymsk | Bin 0 -> 1194 bytes .../site-packages/pytz/zoneinfo/Asia/Taipei | Bin 0 -> 761 bytes .../site-packages/pytz/zoneinfo/Asia/Tashkent | Bin 0 -> 577 bytes .../site-packages/pytz/zoneinfo/Asia/Tbilisi | Bin 0 -> 1021 bytes .../site-packages/pytz/zoneinfo/Asia/Tehran | Bin 0 -> 1248 bytes .../site-packages/pytz/zoneinfo/Asia/Tel_Aviv | Bin 0 -> 2388 bytes .../site-packages/pytz/zoneinfo/Asia/Thimbu | Bin 0 -> 189 bytes .../site-packages/pytz/zoneinfo/Asia/Thimphu | Bin 0 -> 189 bytes .../site-packages/pytz/zoneinfo/Asia/Tokyo | Bin 0 -> 309 bytes .../site-packages/pytz/zoneinfo/Asia/Tomsk | Bin 0 -> 1207 bytes .../pytz/zoneinfo/Asia/Ujung_Pandang | Bin 0 -> 254 bytes .../pytz/zoneinfo/Asia/Ulaanbaatar | Bin 0 -> 877 bytes .../pytz/zoneinfo/Asia/Ulan_Bator | Bin 0 -> 877 bytes .../site-packages/pytz/zoneinfo/Asia/Urumqi | Bin 0 -> 151 bytes .../site-packages/pytz/zoneinfo/Asia/Ust-Nera | Bin 0 -> 1238 bytes .../pytz/zoneinfo/Asia/Vientiane | Bin 0 -> 185 bytes .../pytz/zoneinfo/Asia/Vladivostok | Bin 0 -> 1194 bytes .../site-packages/pytz/zoneinfo/Asia/Yakutsk | Bin 0 -> 1193 bytes .../site-packages/pytz/zoneinfo/Asia/Yangon | Bin 0 -> 254 bytes .../pytz/zoneinfo/Asia/Yekaterinburg | Bin 0 -> 1229 bytes .../site-packages/pytz/zoneinfo/Asia/Yerevan | Bin 0 -> 1137 bytes .../pytz/zoneinfo/Atlantic/Azores | Bin 0 -> 3442 bytes .../pytz/zoneinfo/Atlantic/Bermuda | Bin 0 -> 2396 bytes .../pytz/zoneinfo/Atlantic/Canary | Bin 0 -> 1897 bytes .../pytz/zoneinfo/Atlantic/Cape_Verde | Bin 0 -> 256 bytes .../pytz/zoneinfo/Atlantic/Faeroe | Bin 0 -> 1815 bytes .../pytz/zoneinfo/Atlantic/Faroe | Bin 0 -> 1815 bytes .../pytz/zoneinfo/Atlantic/Jan_Mayen | Bin 0 -> 2298 bytes .../pytz/zoneinfo/Atlantic/Madeira | Bin 0 -> 3377 bytes .../pytz/zoneinfo/Atlantic/Reykjavik | Bin 0 -> 148 bytes .../pytz/zoneinfo/Atlantic/South_Georgia | Bin 0 -> 150 bytes .../pytz/zoneinfo/Atlantic/St_Helena | Bin 0 -> 148 bytes .../pytz/zoneinfo/Atlantic/Stanley | Bin 0 -> 1200 bytes .../site-packages/pytz/zoneinfo/Australia/ACT | Bin 0 -> 2190 bytes .../pytz/zoneinfo/Australia/Adelaide | Bin 0 -> 2208 bytes .../pytz/zoneinfo/Australia/Brisbane | Bin 0 -> 419 bytes .../pytz/zoneinfo/Australia/Broken_Hill | Bin 0 -> 2229 bytes .../pytz/zoneinfo/Australia/Canberra | Bin 0 -> 2190 bytes .../pytz/zoneinfo/Australia/Currie | Bin 0 -> 2358 bytes .../pytz/zoneinfo/Australia/Darwin | Bin 0 -> 325 bytes .../pytz/zoneinfo/Australia/Eucla | Bin 0 -> 456 bytes .../pytz/zoneinfo/Australia/Hobart | Bin 0 -> 2358 bytes .../site-packages/pytz/zoneinfo/Australia/LHI | Bin 0 -> 1846 bytes .../pytz/zoneinfo/Australia/Lindeman | Bin 0 -> 475 bytes .../pytz/zoneinfo/Australia/Lord_Howe | Bin 0 -> 1846 bytes .../pytz/zoneinfo/Australia/Melbourne | Bin 0 -> 2190 bytes .../site-packages/pytz/zoneinfo/Australia/NSW | Bin 0 -> 2190 bytes .../pytz/zoneinfo/Australia/North | Bin 0 -> 325 bytes .../pytz/zoneinfo/Australia/Perth | Bin 0 -> 446 bytes .../pytz/zoneinfo/Australia/Queensland | Bin 0 -> 419 bytes .../pytz/zoneinfo/Australia/South | Bin 0 -> 2208 bytes .../pytz/zoneinfo/Australia/Sydney | Bin 0 -> 2190 bytes .../pytz/zoneinfo/Australia/Tasmania | Bin 0 -> 2358 bytes .../pytz/zoneinfo/Australia/Victoria | Bin 0 -> 2190 bytes .../pytz/zoneinfo/Australia/West | Bin 0 -> 446 bytes .../pytz/zoneinfo/Australia/Yancowinna | Bin 0 -> 2229 bytes .../site-packages/pytz/zoneinfo/Brazil/Acre | Bin 0 -> 614 bytes .../pytz/zoneinfo/Brazil/DeNoronha | Bin 0 -> 702 bytes .../site-packages/pytz/zoneinfo/Brazil/East | Bin 0 -> 1430 bytes .../site-packages/pytz/zoneinfo/Brazil/West | Bin 0 -> 590 bytes .../site-packages/pytz/zoneinfo/CET | Bin 0 -> 2933 bytes .../site-packages/pytz/zoneinfo/CST6CDT | Bin 0 -> 3592 bytes .../pytz/zoneinfo/Canada/Atlantic | Bin 0 -> 3424 bytes .../pytz/zoneinfo/Canada/Central | Bin 0 -> 2868 bytes .../pytz/zoneinfo/Canada/Eastern | Bin 0 -> 3494 bytes .../pytz/zoneinfo/Canada/Mountain | Bin 0 -> 2332 bytes .../pytz/zoneinfo/Canada/Newfoundland | Bin 0 -> 3655 bytes .../pytz/zoneinfo/Canada/Pacific | Bin 0 -> 2892 bytes .../pytz/zoneinfo/Canada/Saskatchewan | Bin 0 -> 980 bytes .../site-packages/pytz/zoneinfo/Canada/Yukon | Bin 0 -> 1614 bytes .../pytz/zoneinfo/Chile/Continental | Bin 0 -> 2515 bytes .../pytz/zoneinfo/Chile/EasterIsland | Bin 0 -> 2219 bytes .../site-packages/pytz/zoneinfo/Cuba | Bin 0 -> 2416 bytes .../site-packages/pytz/zoneinfo/EET | Bin 0 -> 2262 bytes .../site-packages/pytz/zoneinfo/EST | Bin 0 -> 182 bytes .../site-packages/pytz/zoneinfo/EST5EDT | Bin 0 -> 3552 bytes .../site-packages/pytz/zoneinfo/Egypt | Bin 0 -> 2399 bytes .../site-packages/pytz/zoneinfo/Eire | Bin 0 -> 3492 bytes .../site-packages/pytz/zoneinfo/Etc/GMT | Bin 0 -> 114 bytes .../site-packages/pytz/zoneinfo/Etc/GMT+0 | Bin 0 -> 114 bytes .../site-packages/pytz/zoneinfo/Etc/GMT+1 | Bin 0 -> 116 bytes .../site-packages/pytz/zoneinfo/Etc/GMT+10 | Bin 0 -> 117 bytes .../site-packages/pytz/zoneinfo/Etc/GMT+11 | Bin 0 -> 117 bytes .../site-packages/pytz/zoneinfo/Etc/GMT+12 | Bin 0 -> 117 bytes .../site-packages/pytz/zoneinfo/Etc/GMT+2 | Bin 0 -> 116 bytes .../site-packages/pytz/zoneinfo/Etc/GMT+3 | Bin 0 -> 116 bytes .../site-packages/pytz/zoneinfo/Etc/GMT+4 | Bin 0 -> 116 bytes .../site-packages/pytz/zoneinfo/Etc/GMT+5 | Bin 0 -> 116 bytes .../site-packages/pytz/zoneinfo/Etc/GMT+6 | Bin 0 -> 116 bytes .../site-packages/pytz/zoneinfo/Etc/GMT+7 | Bin 0 -> 116 bytes .../site-packages/pytz/zoneinfo/Etc/GMT+8 | Bin 0 -> 116 bytes .../site-packages/pytz/zoneinfo/Etc/GMT+9 | Bin 0 -> 116 bytes .../site-packages/pytz/zoneinfo/Etc/GMT-0 | Bin 0 -> 114 bytes .../site-packages/pytz/zoneinfo/Etc/GMT-1 | Bin 0 -> 117 bytes .../site-packages/pytz/zoneinfo/Etc/GMT-10 | Bin 0 -> 118 bytes .../site-packages/pytz/zoneinfo/Etc/GMT-11 | Bin 0 -> 118 bytes .../site-packages/pytz/zoneinfo/Etc/GMT-12 | Bin 0 -> 118 bytes .../site-packages/pytz/zoneinfo/Etc/GMT-13 | Bin 0 -> 118 bytes .../site-packages/pytz/zoneinfo/Etc/GMT-14 | Bin 0 -> 118 bytes .../site-packages/pytz/zoneinfo/Etc/GMT-2 | Bin 0 -> 117 bytes .../site-packages/pytz/zoneinfo/Etc/GMT-3 | Bin 0 -> 117 bytes .../site-packages/pytz/zoneinfo/Etc/GMT-4 | Bin 0 -> 117 bytes .../site-packages/pytz/zoneinfo/Etc/GMT-5 | Bin 0 -> 117 bytes .../site-packages/pytz/zoneinfo/Etc/GMT-6 | Bin 0 -> 117 bytes .../site-packages/pytz/zoneinfo/Etc/GMT-7 | Bin 0 -> 117 bytes .../site-packages/pytz/zoneinfo/Etc/GMT-8 | Bin 0 -> 117 bytes .../site-packages/pytz/zoneinfo/Etc/GMT-9 | Bin 0 -> 117 bytes .../site-packages/pytz/zoneinfo/Etc/GMT0 | Bin 0 -> 114 bytes .../site-packages/pytz/zoneinfo/Etc/Greenwich | Bin 0 -> 114 bytes .../site-packages/pytz/zoneinfo/Etc/UCT | Bin 0 -> 114 bytes .../site-packages/pytz/zoneinfo/Etc/UTC | Bin 0 -> 114 bytes .../site-packages/pytz/zoneinfo/Etc/Universal | Bin 0 -> 114 bytes .../site-packages/pytz/zoneinfo/Etc/Zulu | Bin 0 -> 114 bytes .../pytz/zoneinfo/Europe/Amsterdam | Bin 0 -> 2933 bytes .../pytz/zoneinfo/Europe/Andorra | Bin 0 -> 1742 bytes .../pytz/zoneinfo/Europe/Astrakhan | Bin 0 -> 1151 bytes .../site-packages/pytz/zoneinfo/Europe/Athens | Bin 0 -> 2262 bytes .../pytz/zoneinfo/Europe/Belfast | Bin 0 -> 3664 bytes .../pytz/zoneinfo/Europe/Belgrade | Bin 0 -> 1920 bytes .../site-packages/pytz/zoneinfo/Europe/Berlin | Bin 0 -> 2298 bytes .../pytz/zoneinfo/Europe/Bratislava | Bin 0 -> 2301 bytes .../pytz/zoneinfo/Europe/Brussels | Bin 0 -> 2933 bytes .../pytz/zoneinfo/Europe/Bucharest | Bin 0 -> 2184 bytes .../pytz/zoneinfo/Europe/Budapest | Bin 0 -> 2368 bytes .../pytz/zoneinfo/Europe/Busingen | Bin 0 -> 1909 bytes .../pytz/zoneinfo/Europe/Chisinau | Bin 0 -> 2390 bytes .../pytz/zoneinfo/Europe/Copenhagen | Bin 0 -> 2298 bytes .../site-packages/pytz/zoneinfo/Europe/Dublin | Bin 0 -> 3492 bytes .../pytz/zoneinfo/Europe/Gibraltar | Bin 0 -> 3068 bytes .../pytz/zoneinfo/Europe/Guernsey | Bin 0 -> 3664 bytes .../pytz/zoneinfo/Europe/Helsinki | Bin 0 -> 1900 bytes .../pytz/zoneinfo/Europe/Isle_of_Man | Bin 0 -> 3664 bytes .../pytz/zoneinfo/Europe/Istanbul | Bin 0 -> 1933 bytes .../site-packages/pytz/zoneinfo/Europe/Jersey | Bin 0 -> 3664 bytes .../pytz/zoneinfo/Europe/Kaliningrad | Bin 0 -> 1493 bytes .../site-packages/pytz/zoneinfo/Europe/Kiev | Bin 0 -> 2120 bytes .../site-packages/pytz/zoneinfo/Europe/Kirov | Bin 0 -> 1185 bytes .../site-packages/pytz/zoneinfo/Europe/Kyiv | Bin 0 -> 2120 bytes .../site-packages/pytz/zoneinfo/Europe/Lisbon | Bin 0 -> 3527 bytes .../pytz/zoneinfo/Europe/Ljubljana | Bin 0 -> 1920 bytes .../site-packages/pytz/zoneinfo/Europe/London | Bin 0 -> 3664 bytes .../pytz/zoneinfo/Europe/Luxembourg | Bin 0 -> 2933 bytes .../site-packages/pytz/zoneinfo/Europe/Madrid | Bin 0 -> 2614 bytes .../site-packages/pytz/zoneinfo/Europe/Malta | Bin 0 -> 2620 bytes .../pytz/zoneinfo/Europe/Mariehamn | Bin 0 -> 1900 bytes .../site-packages/pytz/zoneinfo/Europe/Minsk | Bin 0 -> 1307 bytes .../site-packages/pytz/zoneinfo/Europe/Monaco | Bin 0 -> 2962 bytes .../site-packages/pytz/zoneinfo/Europe/Moscow | Bin 0 -> 1535 bytes .../pytz/zoneinfo/Europe/Nicosia | Bin 0 -> 2002 bytes .../site-packages/pytz/zoneinfo/Europe/Oslo | Bin 0 -> 2298 bytes .../site-packages/pytz/zoneinfo/Europe/Paris | Bin 0 -> 2962 bytes .../pytz/zoneinfo/Europe/Podgorica | Bin 0 -> 1920 bytes .../site-packages/pytz/zoneinfo/Europe/Prague | Bin 0 -> 2301 bytes .../site-packages/pytz/zoneinfo/Europe/Riga | Bin 0 -> 2198 bytes .../site-packages/pytz/zoneinfo/Europe/Rome | Bin 0 -> 2641 bytes .../site-packages/pytz/zoneinfo/Europe/Samara | Bin 0 -> 1201 bytes .../pytz/zoneinfo/Europe/San_Marino | Bin 0 -> 2641 bytes .../pytz/zoneinfo/Europe/Sarajevo | Bin 0 -> 1920 bytes .../pytz/zoneinfo/Europe/Saratov | Bin 0 -> 1169 bytes .../pytz/zoneinfo/Europe/Simferopol | Bin 0 -> 1469 bytes .../site-packages/pytz/zoneinfo/Europe/Skopje | Bin 0 -> 1920 bytes .../site-packages/pytz/zoneinfo/Europe/Sofia | Bin 0 -> 2077 bytes .../pytz/zoneinfo/Europe/Stockholm | Bin 0 -> 2298 bytes .../pytz/zoneinfo/Europe/Tallinn | Bin 0 -> 2148 bytes .../site-packages/pytz/zoneinfo/Europe/Tirane | Bin 0 -> 2084 bytes .../pytz/zoneinfo/Europe/Tiraspol | Bin 0 -> 2390 bytes .../pytz/zoneinfo/Europe/Ulyanovsk | Bin 0 -> 1253 bytes .../pytz/zoneinfo/Europe/Uzhgorod | Bin 0 -> 2120 bytes .../site-packages/pytz/zoneinfo/Europe/Vaduz | Bin 0 -> 1909 bytes .../pytz/zoneinfo/Europe/Vatican | Bin 0 -> 2641 bytes .../site-packages/pytz/zoneinfo/Europe/Vienna | Bin 0 -> 2200 bytes .../pytz/zoneinfo/Europe/Vilnius | Bin 0 -> 2162 bytes .../pytz/zoneinfo/Europe/Volgograd | Bin 0 -> 1193 bytes .../site-packages/pytz/zoneinfo/Europe/Warsaw | Bin 0 -> 2654 bytes .../site-packages/pytz/zoneinfo/Europe/Zagreb | Bin 0 -> 1920 bytes .../pytz/zoneinfo/Europe/Zaporozhye | Bin 0 -> 2120 bytes .../site-packages/pytz/zoneinfo/Europe/Zurich | Bin 0 -> 1909 bytes .../site-packages/pytz/zoneinfo/Factory | Bin 0 -> 116 bytes .../python3.12/site-packages/pytz/zoneinfo/GB | Bin 0 -> 3664 bytes .../site-packages/pytz/zoneinfo/GB-Eire | Bin 0 -> 3664 bytes .../site-packages/pytz/zoneinfo/GMT | Bin 0 -> 114 bytes .../site-packages/pytz/zoneinfo/GMT+0 | Bin 0 -> 114 bytes .../site-packages/pytz/zoneinfo/GMT-0 | Bin 0 -> 114 bytes .../site-packages/pytz/zoneinfo/GMT0 | Bin 0 -> 114 bytes .../site-packages/pytz/zoneinfo/Greenwich | Bin 0 -> 114 bytes .../site-packages/pytz/zoneinfo/HST | Bin 0 -> 329 bytes .../site-packages/pytz/zoneinfo/Hongkong | Bin 0 -> 1233 bytes .../site-packages/pytz/zoneinfo/Iceland | Bin 0 -> 148 bytes .../pytz/zoneinfo/Indian/Antananarivo | Bin 0 -> 265 bytes .../site-packages/pytz/zoneinfo/Indian/Chagos | Bin 0 -> 185 bytes .../pytz/zoneinfo/Indian/Christmas | Bin 0 -> 185 bytes .../site-packages/pytz/zoneinfo/Indian/Cocos | Bin 0 -> 254 bytes .../site-packages/pytz/zoneinfo/Indian/Comoro | Bin 0 -> 265 bytes .../pytz/zoneinfo/Indian/Kerguelen | Bin 0 -> 185 bytes .../site-packages/pytz/zoneinfo/Indian/Mahe | Bin 0 -> 151 bytes .../pytz/zoneinfo/Indian/Maldives | Bin 0 -> 185 bytes .../pytz/zoneinfo/Indian/Mauritius | Bin 0 -> 227 bytes .../pytz/zoneinfo/Indian/Mayotte | Bin 0 -> 265 bytes .../pytz/zoneinfo/Indian/Reunion | Bin 0 -> 151 bytes .../site-packages/pytz/zoneinfo/Iran | Bin 0 -> 1248 bytes .../site-packages/pytz/zoneinfo/Israel | Bin 0 -> 2388 bytes .../site-packages/pytz/zoneinfo/Jamaica | Bin 0 -> 482 bytes .../site-packages/pytz/zoneinfo/Japan | Bin 0 -> 309 bytes .../site-packages/pytz/zoneinfo/Kwajalein | Bin 0 -> 302 bytes .../site-packages/pytz/zoneinfo/Libya | Bin 0 -> 625 bytes .../site-packages/pytz/zoneinfo/MET | Bin 0 -> 2933 bytes .../site-packages/pytz/zoneinfo/MST | Bin 0 -> 360 bytes .../site-packages/pytz/zoneinfo/MST7MDT | Bin 0 -> 2460 bytes .../pytz/zoneinfo/Mexico/BajaNorte | Bin 0 -> 2458 bytes .../pytz/zoneinfo/Mexico/BajaSur | Bin 0 -> 1060 bytes .../pytz/zoneinfo/Mexico/General | Bin 0 -> 1222 bytes .../python3.12/site-packages/pytz/zoneinfo/NZ | Bin 0 -> 2437 bytes .../site-packages/pytz/zoneinfo/NZ-CHAT | Bin 0 -> 2054 bytes .../site-packages/pytz/zoneinfo/Navajo | Bin 0 -> 2460 bytes .../site-packages/pytz/zoneinfo/PRC | Bin 0 -> 561 bytes .../site-packages/pytz/zoneinfo/PST8PDT | Bin 0 -> 2852 bytes .../site-packages/pytz/zoneinfo/Pacific/Apia | Bin 0 -> 598 bytes .../pytz/zoneinfo/Pacific/Auckland | Bin 0 -> 2437 bytes .../pytz/zoneinfo/Pacific/Bougainville | Bin 0 -> 254 bytes .../pytz/zoneinfo/Pacific/Chatham | Bin 0 -> 2054 bytes .../site-packages/pytz/zoneinfo/Pacific/Chuuk | Bin 0 -> 172 bytes .../pytz/zoneinfo/Pacific/Easter | Bin 0 -> 2219 bytes .../site-packages/pytz/zoneinfo/Pacific/Efate | Bin 0 -> 524 bytes .../pytz/zoneinfo/Pacific/Enderbury | Bin 0 -> 220 bytes .../pytz/zoneinfo/Pacific/Fakaofo | Bin 0 -> 186 bytes .../site-packages/pytz/zoneinfo/Pacific/Fiji | Bin 0 -> 564 bytes .../pytz/zoneinfo/Pacific/Funafuti | Bin 0 -> 152 bytes .../pytz/zoneinfo/Pacific/Galapagos | Bin 0 -> 224 bytes .../pytz/zoneinfo/Pacific/Gambier | Bin 0 -> 150 bytes .../pytz/zoneinfo/Pacific/Guadalcanal | Bin 0 -> 152 bytes .../site-packages/pytz/zoneinfo/Pacific/Guam | Bin 0 -> 494 bytes .../pytz/zoneinfo/Pacific/Honolulu | Bin 0 -> 329 bytes .../pytz/zoneinfo/Pacific/Johnston | Bin 0 -> 329 bytes .../pytz/zoneinfo/Pacific/Kanton | Bin 0 -> 220 bytes .../pytz/zoneinfo/Pacific/Kiritimati | Bin 0 -> 224 bytes .../pytz/zoneinfo/Pacific/Kosrae | Bin 0 -> 337 bytes .../pytz/zoneinfo/Pacific/Kwajalein | Bin 0 -> 302 bytes .../pytz/zoneinfo/Pacific/Majuro | Bin 0 -> 152 bytes .../pytz/zoneinfo/Pacific/Marquesas | Bin 0 -> 159 bytes .../pytz/zoneinfo/Pacific/Midway | Bin 0 -> 175 bytes .../site-packages/pytz/zoneinfo/Pacific/Nauru | Bin 0 -> 238 bytes .../site-packages/pytz/zoneinfo/Pacific/Niue | Bin 0 -> 189 bytes .../pytz/zoneinfo/Pacific/Norfolk | Bin 0 -> 866 bytes .../pytz/zoneinfo/Pacific/Noumea | Bin 0 -> 290 bytes .../pytz/zoneinfo/Pacific/Pago_Pago | Bin 0 -> 175 bytes .../site-packages/pytz/zoneinfo/Pacific/Palau | Bin 0 -> 166 bytes .../pytz/zoneinfo/Pacific/Pitcairn | Bin 0 -> 188 bytes .../pytz/zoneinfo/Pacific/Pohnpei | Bin 0 -> 152 bytes .../pytz/zoneinfo/Pacific/Ponape | Bin 0 -> 152 bytes .../pytz/zoneinfo/Pacific/Port_Moresby | Bin 0 -> 172 bytes .../pytz/zoneinfo/Pacific/Rarotonga | Bin 0 -> 589 bytes .../pytz/zoneinfo/Pacific/Saipan | Bin 0 -> 494 bytes .../site-packages/pytz/zoneinfo/Pacific/Samoa | Bin 0 -> 175 bytes .../pytz/zoneinfo/Pacific/Tahiti | Bin 0 -> 151 bytes .../pytz/zoneinfo/Pacific/Tarawa | Bin 0 -> 152 bytes .../pytz/zoneinfo/Pacific/Tongatapu | Bin 0 -> 358 bytes .../site-packages/pytz/zoneinfo/Pacific/Truk | Bin 0 -> 172 bytes .../site-packages/pytz/zoneinfo/Pacific/Wake | Bin 0 -> 152 bytes .../pytz/zoneinfo/Pacific/Wallis | Bin 0 -> 152 bytes .../site-packages/pytz/zoneinfo/Pacific/Yap | Bin 0 -> 172 bytes .../site-packages/pytz/zoneinfo/Poland | Bin 0 -> 2654 bytes .../site-packages/pytz/zoneinfo/Portugal | Bin 0 -> 3527 bytes .../site-packages/pytz/zoneinfo/ROC | Bin 0 -> 761 bytes .../site-packages/pytz/zoneinfo/ROK | Bin 0 -> 617 bytes .../site-packages/pytz/zoneinfo/Singapore | Bin 0 -> 401 bytes .../site-packages/pytz/zoneinfo/Turkey | Bin 0 -> 1933 bytes .../site-packages/pytz/zoneinfo/UCT | Bin 0 -> 114 bytes .../site-packages/pytz/zoneinfo/US/Alaska | Bin 0 -> 2371 bytes .../site-packages/pytz/zoneinfo/US/Aleutian | Bin 0 -> 2356 bytes .../site-packages/pytz/zoneinfo/US/Arizona | Bin 0 -> 360 bytes .../site-packages/pytz/zoneinfo/US/Central | Bin 0 -> 3592 bytes .../pytz/zoneinfo/US/East-Indiana | Bin 0 -> 1682 bytes .../site-packages/pytz/zoneinfo/US/Eastern | Bin 0 -> 3552 bytes .../site-packages/pytz/zoneinfo/US/Hawaii | Bin 0 -> 329 bytes .../pytz/zoneinfo/US/Indiana-Starke | Bin 0 -> 2444 bytes .../site-packages/pytz/zoneinfo/US/Michigan | Bin 0 -> 2230 bytes .../site-packages/pytz/zoneinfo/US/Mountain | Bin 0 -> 2460 bytes .../site-packages/pytz/zoneinfo/US/Pacific | Bin 0 -> 2852 bytes .../site-packages/pytz/zoneinfo/US/Samoa | Bin 0 -> 175 bytes .../site-packages/pytz/zoneinfo/UTC | Bin 0 -> 114 bytes .../site-packages/pytz/zoneinfo/Universal | Bin 0 -> 114 bytes .../site-packages/pytz/zoneinfo/W-SU | Bin 0 -> 1535 bytes .../site-packages/pytz/zoneinfo/WET | Bin 0 -> 3527 bytes .../site-packages/pytz/zoneinfo/Zulu | Bin 0 -> 114 bytes .../site-packages/pytz/zoneinfo/iso3166.tab | 279 + .../site-packages/pytz/zoneinfo/leapseconds | 79 + .../site-packages/pytz/zoneinfo/tzdata.zi | 4281 ++++++++ .../site-packages/pytz/zoneinfo/zone.tab | 447 + .../site-packages/pytz/zoneinfo/zone1970.tab | 374 + .../site-packages/pytz/zoneinfo/zonenow.tab | 299 + .../requests-2.32.3.dist-info/INSTALLER | 1 + .../requests-2.32.3.dist-info/LICENSE | 175 + .../requests-2.32.3.dist-info/METADATA | 119 + .../requests-2.32.3.dist-info/RECORD | 43 + .../requests-2.32.3.dist-info/REQUESTED | 0 .../requests-2.32.3.dist-info/WHEEL | 5 + .../requests-2.32.3.dist-info/top_level.txt | 1 + .../site-packages/requests/__init__.py | 184 + .../__pycache__/__init__.cpython-312.pyc | Bin 0 -> 5418 bytes .../__pycache__/__version__.cpython-312.pyc | Bin 0 -> 582 bytes .../_internal_utils.cpython-312.pyc | Bin 0 -> 2022 bytes .../__pycache__/adapters.cpython-312.pyc | Bin 0 -> 28356 bytes .../requests/__pycache__/api.cpython-312.pyc | Bin 0 -> 7189 bytes .../requests/__pycache__/auth.cpython-312.pyc | Bin 0 -> 13919 bytes .../__pycache__/certs.cpython-312.pyc | Bin 0 -> 664 bytes .../__pycache__/compat.cpython-312.pyc | Bin 0 -> 2078 bytes .../__pycache__/cookies.cpython-312.pyc | Bin 0 -> 25196 bytes .../__pycache__/exceptions.cpython-312.pyc | Bin 0 -> 7583 bytes .../requests/__pycache__/help.cpython-312.pyc | Bin 0 -> 4325 bytes .../__pycache__/hooks.cpython-312.pyc | Bin 0 -> 1049 bytes .../__pycache__/models.cpython-312.pyc | Bin 0 -> 35354 bytes .../__pycache__/packages.cpython-312.pyc | Bin 0 -> 1116 bytes .../__pycache__/sessions.cpython-312.pyc | Bin 0 -> 27844 bytes .../__pycache__/status_codes.cpython-312.pyc | Bin 0 -> 6021 bytes .../__pycache__/structures.cpython-312.pyc | Bin 0 -> 5621 bytes .../__pycache__/utils.cpython-312.pyc | Bin 0 -> 36352 bytes .../site-packages/requests/__version__.py | 14 + .../site-packages/requests/_internal_utils.py | 50 + .../site-packages/requests/adapters.py | 719 ++ .../python3.12/site-packages/requests/api.py | 157 + .../python3.12/site-packages/requests/auth.py | 314 + .../site-packages/requests/certs.py | 17 + .../site-packages/requests/compat.py | 94 + .../site-packages/requests/cookies.py | 561 ++ .../site-packages/requests/exceptions.py | 151 + .../python3.12/site-packages/requests/help.py | 134 + .../site-packages/requests/hooks.py | 33 + .../site-packages/requests/models.py | 1037 ++ .../site-packages/requests/packages.py | 23 + .../site-packages/requests/sessions.py | 831 ++ .../site-packages/requests/status_codes.py | 128 + .../site-packages/requests/structures.py | 99 + .../site-packages/requests/utils.py | 1096 +++ .../site-packages/sqlalchemy/__init__.py | 294 + .../__pycache__/__init__.cpython-312.pyc | Bin 0 -> 9946 bytes .../__pycache__/events.cpython-312.pyc | Bin 0 -> 564 bytes .../__pycache__/exc.cpython-312.pyc | Bin 0 -> 31233 bytes .../__pycache__/inspection.cpython-312.pyc | Bin 0 -> 6663 bytes .../__pycache__/log.cpython-312.pyc | Bin 0 -> 11621 bytes .../__pycache__/schema.cpython-312.pyc | Bin 0 -> 2343 bytes .../__pycache__/types.cpython-312.pyc | Bin 0 -> 2291 bytes .../sqlalchemy/connectors/__init__.py | 18 + .../__pycache__/__init__.cpython-312.pyc | Bin 0 -> 603 bytes .../__pycache__/aioodbc.cpython-312.pyc | Bin 0 -> 7068 bytes .../__pycache__/asyncio.cpython-312.pyc | Bin 0 -> 12389 bytes .../__pycache__/pyodbc.cpython-312.pyc | Bin 0 -> 9383 bytes .../sqlalchemy/connectors/aioodbc.py | 174 + .../sqlalchemy/connectors/asyncio.py | 213 + .../sqlalchemy/connectors/pyodbc.py | 249 + .../sqlalchemy/cyextension/__init__.py | 6 + .../__pycache__/__init__.cpython-312.pyc | Bin 0 -> 203 bytes ...ollections.cpython-312-x86_64-linux-gnu.so | Bin 0 -> 1932256 bytes .../sqlalchemy/cyextension/collections.pyx | 409 + ...utabledict.cpython-312-x86_64-linux-gnu.so | Bin 0 -> 805632 bytes .../sqlalchemy/cyextension/immutabledict.pxd | 8 + .../sqlalchemy/cyextension/immutabledict.pyx | 133 + ...processors.cpython-312-x86_64-linux-gnu.so | Bin 0 -> 530680 bytes .../sqlalchemy/cyextension/processors.pyx | 68 + ...esultproxy.cpython-312-x86_64-linux-gnu.so | Bin 0 -> 621328 bytes .../sqlalchemy/cyextension/resultproxy.pyx | 102 + .../util.cpython-312-x86_64-linux-gnu.so | Bin 0 -> 950928 bytes .../sqlalchemy/cyextension/util.pyx | 91 + .../sqlalchemy/dialects/__init__.py | 61 + .../__pycache__/__init__.cpython-312.pyc | Bin 0 -> 1890 bytes .../__pycache__/_typing.cpython-312.pyc | Bin 0 -> 903 bytes .../sqlalchemy/dialects/_typing.py | 25 + .../sqlalchemy/dialects/mssql/__init__.py | 88 + .../__pycache__/__init__.cpython-312.pyc | Bin 0 -> 1671 bytes .../mssql/__pycache__/aioodbc.cpython-312.pyc | Bin 0 -> 2413 bytes .../mssql/__pycache__/base.cpython-312.pyc | Bin 0 -> 152316 bytes .../information_schema.cpython-312.pyc | Bin 0 -> 8083 bytes .../mssql/__pycache__/json.cpython-312.pyc | Bin 0 -> 5293 bytes .../__pycache__/provision.cpython-312.pyc | Bin 0 -> 7403 bytes .../mssql/__pycache__/pymssql.cpython-312.pyc | Bin 0 -> 5963 bytes .../mssql/__pycache__/pyodbc.cpython-312.pyc | Bin 0 -> 30524 bytes .../sqlalchemy/dialects/mssql/aioodbc.py | 64 + .../sqlalchemy/dialects/mssql/base.py | 4010 ++++++++ .../dialects/mssql/information_schema.py | 254 + .../sqlalchemy/dialects/mssql/json.py | 133 + .../sqlalchemy/dialects/mssql/provision.py | 162 + .../sqlalchemy/dialects/mssql/pymssql.py | 126 + .../sqlalchemy/dialects/mssql/pyodbc.py | 745 ++ .../sqlalchemy/dialects/mysql/__init__.py | 101 + .../__pycache__/__init__.cpython-312.pyc | Bin 0 -> 1964 bytes .../__pycache__/aiomysql.cpython-312.pyc | Bin 0 -> 16895 bytes .../mysql/__pycache__/asyncmy.cpython-312.pyc | Bin 0 -> 17347 bytes .../mysql/__pycache__/base.cpython-312.pyc | Bin 0 -> 139291 bytes .../mysql/__pycache__/cymysql.cpython-312.pyc | Bin 0 -> 3141 bytes .../mysql/__pycache__/dml.cpython-312.pyc | Bin 0 -> 8223 bytes .../__pycache__/enumerated.cpython-312.pyc | Bin 0 -> 10201 bytes .../__pycache__/expression.cpython-312.pyc | Bin 0 -> 5025 bytes .../mysql/__pycache__/json.cpython-312.pyc | Bin 0 -> 3455 bytes .../mysql/__pycache__/mariadb.cpython-312.pyc | Bin 0 -> 1076 bytes .../mariadbconnector.cpython-312.pyc | Bin 0 -> 11688 bytes .../mysqlconnector.cpython-312.pyc | Bin 0 -> 9180 bytes .../mysql/__pycache__/mysqldb.cpython-312.pyc | Bin 0 -> 11751 bytes .../__pycache__/provision.cpython-312.pyc | Bin 0 -> 4252 bytes .../mysql/__pycache__/pymysql.cpython-312.pyc | Bin 0 -> 5314 bytes .../mysql/__pycache__/pyodbc.cpython-312.pyc | Bin 0 -> 5268 bytes .../__pycache__/reflection.cpython-312.pyc | Bin 0 -> 24062 bytes .../reserved_words.cpython-312.pyc | Bin 0 -> 4400 bytes .../mysql/__pycache__/types.cpython-312.pyc | Bin 0 -> 30476 bytes .../sqlalchemy/dialects/mysql/aiomysql.py | 333 + .../sqlalchemy/dialects/mysql/asyncmy.py | 337 + .../sqlalchemy/dialects/mysql/base.py | 3494 +++++++ .../sqlalchemy/dialects/mysql/cymysql.py | 84 + .../sqlalchemy/dialects/mysql/dml.py | 219 + .../sqlalchemy/dialects/mysql/enumerated.py | 244 + .../sqlalchemy/dialects/mysql/expression.py | 141 + .../sqlalchemy/dialects/mysql/json.py | 81 + .../sqlalchemy/dialects/mysql/mariadb.py | 32 + .../dialects/mysql/mariadbconnector.py | 277 + .../dialects/mysql/mysqlconnector.py | 180 + .../sqlalchemy/dialects/mysql/mysqldb.py | 303 + .../sqlalchemy/dialects/mysql/provision.py | 110 + .../sqlalchemy/dialects/mysql/pymysql.py | 137 + .../sqlalchemy/dialects/mysql/pyodbc.py | 138 + .../sqlalchemy/dialects/mysql/reflection.py | 677 ++ .../dialects/mysql/reserved_words.py | 571 ++ .../sqlalchemy/dialects/mysql/types.py | 774 ++ .../sqlalchemy/dialects/oracle/__init__.py | 67 + .../__pycache__/__init__.cpython-312.pyc | Bin 0 -> 1357 bytes .../oracle/__pycache__/base.cpython-312.pyc | Bin 0 -> 134119 bytes .../__pycache__/cx_oracle.cpython-312.pyc | Bin 0 -> 59410 bytes .../__pycache__/dictionary.cpython-312.pyc | Bin 0 -> 24607 bytes .../__pycache__/oracledb.cpython-312.pyc | Bin 0 -> 21057 bytes .../__pycache__/provision.cpython-312.pyc | Bin 0 -> 10774 bytes .../oracle/__pycache__/types.cpython-312.pyc | Bin 0 -> 12386 bytes .../sqlalchemy/dialects/oracle/base.py | 3271 +++++++ .../sqlalchemy/dialects/oracle/cx_oracle.py | 1483 +++ .../sqlalchemy/dialects/oracle/dictionary.py | 507 + .../sqlalchemy/dialects/oracle/oracledb.py | 431 + .../sqlalchemy/dialects/oracle/provision.py | 220 + .../sqlalchemy/dialects/oracle/types.py | 287 + .../dialects/postgresql/__init__.py | 167 + .../__pycache__/__init__.cpython-312.pyc | Bin 0 -> 3441 bytes .../_psycopg_common.cpython-312.pyc | Bin 0 -> 7708 bytes .../__pycache__/array.cpython-312.pyc | Bin 0 -> 16607 bytes .../__pycache__/asyncpg.cpython-312.pyc | Bin 0 -> 57857 bytes .../__pycache__/base.cpython-312.pyc | Bin 0 -> 204602 bytes .../__pycache__/dml.cpython-312.pyc | Bin 0 -> 11619 bytes .../__pycache__/ext.cpython-312.pyc | Bin 0 -> 19261 bytes .../__pycache__/hstore.cpython-312.pyc | Bin 0 -> 15365 bytes .../__pycache__/json.cpython-312.pyc | Bin 0 -> 13943 bytes .../__pycache__/named_types.cpython-312.pyc | Bin 0 -> 22917 bytes .../__pycache__/operators.cpython-312.pyc | Bin 0 -> 2164 bytes .../__pycache__/pg8000.cpython-312.pyc | Bin 0 -> 30268 bytes .../__pycache__/pg_catalog.cpython-312.pyc | Bin 0 -> 10969 bytes .../__pycache__/provision.cpython-312.pyc | Bin 0 -> 7720 bytes .../__pycache__/psycopg.cpython-312.pyc | Bin 0 -> 37408 bytes .../__pycache__/psycopg2.cpython-312.pyc | Bin 0 -> 35946 bytes .../__pycache__/psycopg2cffi.cpython-312.pyc | Bin 0 -> 2171 bytes .../__pycache__/ranges.cpython-312.pyc | Bin 0 -> 34751 bytes .../__pycache__/types.cpython-312.pyc | Bin 0 -> 11086 bytes .../dialects/postgresql/_psycopg_common.py | 187 + .../sqlalchemy/dialects/postgresql/array.py | 425 + .../sqlalchemy/dialects/postgresql/asyncpg.py | 1274 +++ .../sqlalchemy/dialects/postgresql/base.py | 5008 ++++++++++ .../sqlalchemy/dialects/postgresql/dml.py | 310 + .../sqlalchemy/dialects/postgresql/ext.py | 496 + .../sqlalchemy/dialects/postgresql/hstore.py | 397 + .../sqlalchemy/dialects/postgresql/json.py | 333 + .../dialects/postgresql/named_types.py | 509 + .../dialects/postgresql/operators.py | 129 + .../sqlalchemy/dialects/postgresql/pg8000.py | 662 ++ .../dialects/postgresql/pg_catalog.py | 300 + .../dialects/postgresql/provision.py | 175 + .../sqlalchemy/dialects/postgresql/psycopg.py | 772 ++ .../dialects/postgresql/psycopg2.py | 886 ++ .../dialects/postgresql/psycopg2cffi.py | 61 + .../sqlalchemy/dialects/postgresql/ranges.py | 1029 ++ .../sqlalchemy/dialects/postgresql/types.py | 303 + .../sqlalchemy/dialects/sqlite/__init__.py | 57 + .../__pycache__/__init__.cpython-312.pyc | Bin 0 -> 1067 bytes .../__pycache__/aiosqlite.cpython-312.pyc | Bin 0 -> 17920 bytes .../sqlite/__pycache__/base.cpython-312.pyc | Bin 0 -> 101091 bytes .../sqlite/__pycache__/dml.cpython-312.pyc | Bin 0 -> 9247 bytes .../sqlite/__pycache__/json.cpython-312.pyc | Bin 0 -> 3784 bytes .../__pycache__/provision.cpython-312.pyc | Bin 0 -> 7285 bytes .../__pycache__/pysqlcipher.cpython-312.pyc | Bin 0 -> 6204 bytes .../__pycache__/pysqlite.cpython-312.pyc | Bin 0 -> 31429 bytes .../sqlalchemy/dialects/sqlite/aiosqlite.py | 396 + .../sqlalchemy/dialects/sqlite/base.py | 2805 ++++++ .../sqlalchemy/dialects/sqlite/dml.py | 240 + .../sqlalchemy/dialects/sqlite/json.py | 92 + .../sqlalchemy/dialects/sqlite/provision.py | 198 + .../sqlalchemy/dialects/sqlite/pysqlcipher.py | 155 + .../sqlalchemy/dialects/sqlite/pysqlite.py | 756 ++ .../dialects/type_migration_guidelines.txt | 145 + .../sqlalchemy/engine/__init__.py | 62 + .../__pycache__/__init__.cpython-312.pyc | Bin 0 -> 2282 bytes .../_py_processors.cpython-312.pyc | Bin 0 -> 4505 bytes .../__pycache__/_py_row.cpython-312.pyc | Bin 0 -> 5774 bytes .../__pycache__/_py_util.cpython-312.pyc | Bin 0 -> 2186 bytes .../engine/__pycache__/base.cpython-312.pyc | Bin 0 -> 130043 bytes .../characteristics.cpython-312.pyc | Bin 0 -> 6849 bytes .../engine/__pycache__/create.cpython-312.pyc | Bin 0 -> 34322 bytes .../engine/__pycache__/cursor.cpython-312.pyc | Bin 0 -> 79488 bytes .../__pycache__/default.cpython-312.pyc | Bin 0 -> 88041 bytes .../engine/__pycache__/events.cpython-312.pyc | Bin 0 -> 39909 bytes .../__pycache__/interfaces.cpython-312.pyc | Bin 0 -> 99496 bytes .../engine/__pycache__/mock.cpython-312.pyc | Bin 0 -> 5696 bytes .../__pycache__/processors.cpython-312.pyc | Bin 0 -> 1296 bytes .../__pycache__/reflection.cpython-312.pyc | Bin 0 -> 80292 bytes .../engine/__pycache__/result.cpython-312.pyc | Bin 0 -> 91239 bytes .../engine/__pycache__/row.cpython-312.pyc | Bin 0 -> 17445 bytes .../__pycache__/strategies.cpython-312.pyc | Bin 0 -> 565 bytes .../engine/__pycache__/url.cpython-312.pyc | Bin 0 -> 34168 bytes .../engine/__pycache__/util.cpython-312.pyc | Bin 0 -> 6641 bytes .../sqlalchemy/engine/_py_processors.py | 136 + .../sqlalchemy/engine/_py_row.py | 128 + .../sqlalchemy/engine/_py_util.py | 74 + .../site-packages/sqlalchemy/engine/base.py | 3375 +++++++ .../sqlalchemy/engine/characteristics.py | 155 + .../site-packages/sqlalchemy/engine/create.py | 875 ++ .../site-packages/sqlalchemy/engine/cursor.py | 2181 +++++ .../sqlalchemy/engine/default.py | 2365 +++++ .../site-packages/sqlalchemy/engine/events.py | 951 ++ .../sqlalchemy/engine/interfaces.py | 3403 +++++++ .../site-packages/sqlalchemy/engine/mock.py | 131 + .../sqlalchemy/engine/processors.py | 61 + .../sqlalchemy/engine/reflection.py | 2098 ++++ .../site-packages/sqlalchemy/engine/result.py | 2382 +++++ .../site-packages/sqlalchemy/engine/row.py | 401 + .../sqlalchemy/engine/strategies.py | 19 + .../site-packages/sqlalchemy/engine/url.py | 910 ++ .../site-packages/sqlalchemy/engine/util.py | 167 + .../sqlalchemy/event/__init__.py | 25 + .../__pycache__/__init__.cpython-312.pyc | Bin 0 -> 845 bytes .../event/__pycache__/api.cpython-312.pyc | Bin 0 -> 9197 bytes .../event/__pycache__/attr.cpython-312.pyc | Bin 0 -> 30367 bytes .../event/__pycache__/base.cpython-312.pyc | Bin 0 -> 19797 bytes .../event/__pycache__/legacy.cpython-312.pyc | Bin 0 -> 9386 bytes .../__pycache__/registry.cpython-312.pyc | Bin 0 -> 12597 bytes .../site-packages/sqlalchemy/event/api.py | 225 + .../site-packages/sqlalchemy/event/attr.py | 655 ++ .../site-packages/sqlalchemy/event/base.py | 470 + .../site-packages/sqlalchemy/event/legacy.py | 246 + .../sqlalchemy/event/registry.py | 386 + .../site-packages/sqlalchemy/events.py | 17 + .../site-packages/sqlalchemy/exc.py | 830 ++ .../site-packages/sqlalchemy/ext/__init__.py | 11 + .../ext/__pycache__/__init__.cpython-312.pyc | Bin 0 -> 358 bytes .../associationproxy.cpython-312.pyc | Bin 0 -> 86868 bytes .../ext/__pycache__/automap.cpython-312.pyc | Bin 0 -> 57312 bytes .../ext/__pycache__/baked.cpython-312.pyc | Bin 0 -> 23461 bytes .../ext/__pycache__/compiler.cpython-312.pyc | Bin 0 -> 21230 bytes .../horizontal_shard.cpython-312.pyc | Bin 0 -> 17699 bytes .../ext/__pycache__/hybrid.cpython-312.pyc | Bin 0 -> 59769 bytes .../ext/__pycache__/indexable.cpython-312.pyc | Bin 0 -> 12164 bytes .../instrumentation.cpython-312.pyc | Bin 0 -> 19874 bytes .../ext/__pycache__/mutable.cpython-312.pyc | Bin 0 -> 46104 bytes .../__pycache__/orderinglist.cpython-312.pyc | Bin 0 -> 17276 bytes .../__pycache__/serializer.cpython-312.pyc | Bin 0 -> 8024 bytes .../sqlalchemy/ext/associationproxy.py | 2013 ++++ .../sqlalchemy/ext/asyncio/__init__.py | 25 + .../__pycache__/__init__.cpython-312.pyc | Bin 0 -> 981 bytes .../asyncio/__pycache__/base.cpython-312.pyc | Bin 0 -> 11185 bytes .../__pycache__/engine.cpython-312.pyc | Bin 0 -> 57392 bytes .../asyncio/__pycache__/exc.cpython-312.pyc | Bin 0 -> 1041 bytes .../__pycache__/result.cpython-312.pyc | Bin 0 -> 37454 bytes .../__pycache__/scoping.cpython-312.pyc | Bin 0 -> 57030 bytes .../__pycache__/session.cpython-312.pyc | Bin 0 -> 71400 bytes .../sqlalchemy/ext/asyncio/base.py | 279 + .../sqlalchemy/ext/asyncio/engine.py | 1466 +++ .../sqlalchemy/ext/asyncio/exc.py | 21 + .../sqlalchemy/ext/asyncio/result.py | 961 ++ .../sqlalchemy/ext/asyncio/scoping.py | 1614 +++ .../sqlalchemy/ext/asyncio/session.py | 1936 ++++ .../site-packages/sqlalchemy/ext/automap.py | 1691 ++++ .../site-packages/sqlalchemy/ext/baked.py | 574 ++ .../site-packages/sqlalchemy/ext/compiler.py | 570 ++ .../sqlalchemy/ext/declarative/__init__.py | 65 + .../__pycache__/__init__.cpython-312.pyc | Bin 0 -> 2017 bytes .../__pycache__/extensions.cpython-312.pyc | Bin 0 -> 21255 bytes .../sqlalchemy/ext/declarative/extensions.py | 548 ++ .../sqlalchemy/ext/horizontal_shard.py | 481 + .../site-packages/sqlalchemy/ext/hybrid.py | 1514 +++ .../site-packages/sqlalchemy/ext/indexable.py | 341 + .../sqlalchemy/ext/instrumentation.py | 450 + .../site-packages/sqlalchemy/ext/mutable.py | 1073 ++ .../sqlalchemy/ext/mypy/__init__.py | 6 + .../mypy/__pycache__/__init__.cpython-312.pyc | Bin 0 -> 200 bytes .../mypy/__pycache__/apply.cpython-312.pyc | Bin 0 -> 10477 bytes .../__pycache__/decl_class.cpython-312.pyc | Bin 0 -> 15824 bytes .../mypy/__pycache__/infer.cpython-312.pyc | Bin 0 -> 15632 bytes .../mypy/__pycache__/names.cpython-312.pyc | Bin 0 -> 11043 bytes .../mypy/__pycache__/plugin.cpython-312.pyc | Bin 0 -> 12519 bytes .../ext/mypy/__pycache__/util.cpython-312.pyc | Bin 0 -> 14014 bytes .../sqlalchemy/ext/mypy/apply.py | 320 + .../sqlalchemy/ext/mypy/decl_class.py | 515 + .../sqlalchemy/ext/mypy/infer.py | 590 ++ .../sqlalchemy/ext/mypy/names.py | 335 + .../sqlalchemy/ext/mypy/plugin.py | 303 + .../site-packages/sqlalchemy/ext/mypy/util.py | 357 + .../sqlalchemy/ext/orderinglist.py | 416 + .../sqlalchemy/ext/serializer.py | 181 + .../sqlalchemy/future/__init__.py | 16 + .../__pycache__/__init__.cpython-312.pyc | Bin 0 -> 468 bytes .../future/__pycache__/engine.cpython-312.pyc | Bin 0 -> 401 bytes .../site-packages/sqlalchemy/future/engine.py | 15 + .../site-packages/sqlalchemy/inspection.py | 174 + .../site-packages/sqlalchemy/log.py | 288 + .../site-packages/sqlalchemy/orm/__init__.py | 170 + .../orm/__pycache__/__init__.cpython-312.pyc | Bin 0 -> 6349 bytes .../_orm_constructors.cpython-312.pyc | Bin 0 -> 105250 bytes .../orm/__pycache__/_typing.cpython-312.pyc | Bin 0 -> 6818 bytes .../__pycache__/attributes.cpython-312.pyc | Bin 0 -> 99855 bytes .../orm/__pycache__/base.cpython-312.pyc | Bin 0 -> 30354 bytes .../bulk_persistence.cpython-312.pyc | Bin 0 -> 64430 bytes .../__pycache__/clsregistry.cpython-312.pyc | Bin 0 -> 23781 bytes .../__pycache__/collections.cpython-312.pyc | Bin 0 -> 61704 bytes .../orm/__pycache__/context.cpython-312.pyc | Bin 0 -> 100774 bytes .../orm/__pycache__/decl_api.cpython-312.pyc | Bin 0 -> 66751 bytes .../orm/__pycache__/decl_base.cpython-312.pyc | Bin 0 -> 68879 bytes .../__pycache__/dependency.cpython-312.pyc | Bin 0 -> 43127 bytes .../descriptor_props.cpython-312.pyc | Bin 0 -> 48896 bytes .../orm/__pycache__/dynamic.cpython-312.pyc | Bin 0 -> 12947 bytes .../orm/__pycache__/evaluator.cpython-312.pyc | Bin 0 -> 16753 bytes .../orm/__pycache__/events.cpython-312.pyc | Bin 0 -> 137184 bytes .../orm/__pycache__/exc.cpython-312.pyc | Bin 0 -> 9858 bytes .../orm/__pycache__/identity.cpython-312.pyc | Bin 0 -> 12621 bytes .../instrumentation.cpython-312.pyc | Bin 0 -> 31204 bytes .../__pycache__/interfaces.cpython-312.pyc | Bin 0 -> 54165 bytes .../orm/__pycache__/loading.cpython-312.pyc | Bin 0 -> 46863 bytes .../mapped_collection.cpython-312.pyc | Bin 0 -> 21892 bytes .../orm/__pycache__/mapper.cpython-312.pyc | Bin 0 -> 168852 bytes .../__pycache__/path_registry.cpython-312.pyc | Bin 0 -> 31503 bytes .../__pycache__/persistence.cpython-312.pyc | Bin 0 -> 48242 bytes .../__pycache__/properties.cpython-312.pyc | Bin 0 -> 33003 bytes .../orm/__pycache__/query.cpython-312.pyc | Bin 0 -> 127733 bytes .../__pycache__/relationships.cpython-312.pyc | Bin 0 -> 130169 bytes .../orm/__pycache__/scoping.cpython-312.pyc | Bin 0 -> 83676 bytes .../orm/__pycache__/session.cpython-312.pyc | Bin 0 -> 203196 bytes .../orm/__pycache__/state.cpython-312.pyc | Bin 0 -> 45117 bytes .../__pycache__/state_changes.cpython-312.pyc | Bin 0 -> 7030 bytes .../__pycache__/strategies.cpython-312.pyc | Bin 0 -> 105099 bytes .../strategy_options.cpython-312.pyc | Bin 0 -> 87088 bytes .../orm/__pycache__/sync.cpython-312.pyc | Bin 0 -> 6577 bytes .../__pycache__/unitofwork.cpython-312.pyc | Bin 0 -> 34038 bytes .../orm/__pycache__/util.cpython-312.pyc | Bin 0 -> 85789 bytes .../orm/__pycache__/writeonly.cpython-312.pyc | Bin 0 -> 28812 bytes .../sqlalchemy/orm/_orm_constructors.py | 2571 +++++ .../site-packages/sqlalchemy/orm/_typing.py | 179 + .../sqlalchemy/orm/attributes.py | 2835 ++++++ .../site-packages/sqlalchemy/orm/base.py | 973 ++ .../sqlalchemy/orm/bulk_persistence.py | 2123 ++++ .../sqlalchemy/orm/clsregistry.py | 571 ++ .../sqlalchemy/orm/collections.py | 1620 +++ .../site-packages/sqlalchemy/orm/context.py | 3268 +++++++ .../site-packages/sqlalchemy/orm/decl_api.py | 1883 ++++ .../site-packages/sqlalchemy/orm/decl_base.py | 2190 +++++ .../sqlalchemy/orm/dependency.py | 1304 +++ .../sqlalchemy/orm/descriptor_props.py | 1076 ++ .../site-packages/sqlalchemy/orm/dynamic.py | 300 + .../site-packages/sqlalchemy/orm/evaluator.py | 379 + .../site-packages/sqlalchemy/orm/events.py | 3261 +++++++ .../site-packages/sqlalchemy/orm/exc.py | 228 + .../site-packages/sqlalchemy/orm/identity.py | 302 + .../sqlalchemy/orm/instrumentation.py | 754 ++ .../sqlalchemy/orm/interfaces.py | 1474 +++ .../site-packages/sqlalchemy/orm/loading.py | 1682 ++++ .../sqlalchemy/orm/mapped_collection.py | 557 ++ .../site-packages/sqlalchemy/orm/mapper.py | 4432 +++++++++ .../sqlalchemy/orm/path_registry.py | 811 ++ .../sqlalchemy/orm/persistence.py | 1782 ++++ .../sqlalchemy/orm/properties.py | 886 ++ .../site-packages/sqlalchemy/orm/query.py | 3396 +++++++ .../sqlalchemy/orm/relationships.py | 3500 +++++++ .../site-packages/sqlalchemy/orm/scoping.py | 2165 ++++ .../site-packages/sqlalchemy/orm/session.py | 5301 ++++++++++ .../site-packages/sqlalchemy/orm/state.py | 1143 +++ .../sqlalchemy/orm/state_changes.py | 198 + .../sqlalchemy/orm/strategies.py | 3473 +++++++ .../sqlalchemy/orm/strategy_options.py | 2569 +++++ .../site-packages/sqlalchemy/orm/sync.py | 164 + .../sqlalchemy/orm/unitofwork.py | 796 ++ .../site-packages/sqlalchemy/orm/util.py | 2424 +++++ .../site-packages/sqlalchemy/orm/writeonly.py | 678 ++ .../site-packages/sqlalchemy/pool/__init__.py | 44 + .../pool/__pycache__/__init__.cpython-312.pyc | Bin 0 -> 1519 bytes .../pool/__pycache__/base.cpython-312.pyc | Bin 0 -> 56239 bytes .../pool/__pycache__/events.cpython-312.pyc | Bin 0 -> 14328 bytes .../pool/__pycache__/impl.cpython-312.pyc | Bin 0 -> 25904 bytes .../site-packages/sqlalchemy/pool/base.py | 1515 +++ .../site-packages/sqlalchemy/pool/events.py | 370 + .../site-packages/sqlalchemy/pool/impl.py | 581 ++ .../site-packages/sqlalchemy/py.typed | 0 .../site-packages/sqlalchemy/schema.py | 70 + .../site-packages/sqlalchemy/sql/__init__.py | 145 + .../sql/__pycache__/__init__.cpython-312.pyc | Bin 0 -> 4692 bytes .../_dml_constructors.cpython-312.pyc | Bin 0 -> 4100 bytes .../_elements_constructors.cpython-312.pyc | Bin 0 -> 66204 bytes .../__pycache__/_orm_types.cpython-312.pyc | Bin 0 -> 632 bytes .../sql/__pycache__/_py_util.cpython-312.pyc | Bin 0 -> 2971 bytes .../_selectable_constructors.cpython-312.pyc | Bin 0 -> 21504 bytes .../sql/__pycache__/_typing.cpython-312.pyc | Bin 0 -> 14831 bytes .../__pycache__/annotation.cpython-312.pyc | Bin 0 -> 21344 bytes .../sql/__pycache__/base.cpython-312.pyc | Bin 0 -> 97839 bytes .../sql/__pycache__/cache_key.cpython-312.pyc | Bin 0 -> 35649 bytes .../sql/__pycache__/coercions.cpython-312.pyc | Bin 0 -> 48966 bytes .../sql/__pycache__/compiler.cpython-312.pyc | Bin 0 -> 271584 bytes .../sql/__pycache__/crud.cpython-312.pyc | Bin 0 -> 45475 bytes .../sql/__pycache__/ddl.cpython-312.pyc | Bin 0 -> 56099 bytes .../default_comparator.cpython-312.pyc | Bin 0 -> 19488 bytes .../sql/__pycache__/dml.cpython-312.pyc | Bin 0 -> 73618 bytes .../sql/__pycache__/elements.cpython-312.pyc | Bin 0 -> 210804 bytes .../sql/__pycache__/events.cpython-312.pyc | Bin 0 -> 19219 bytes .../__pycache__/expression.cpython-312.pyc | Bin 0 -> 5154 bytes .../sql/__pycache__/functions.cpython-312.pyc | Bin 0 -> 75706 bytes .../sql/__pycache__/lambdas.cpython-312.pyc | Bin 0 -> 54941 bytes .../sql/__pycache__/naming.cpython-312.pyc | Bin 0 -> 8469 bytes .../sql/__pycache__/operators.cpython-312.pyc | Bin 0 -> 89335 bytes .../sql/__pycache__/roles.cpython-312.pyc | Bin 0 -> 12251 bytes .../sql/__pycache__/schema.cpython-312.pyc | Bin 0 -> 245385 bytes .../__pycache__/selectable.cpython-312.pyc | Bin 0 -> 259713 bytes .../sql/__pycache__/sqltypes.cpython-312.pyc | Bin 0 -> 150448 bytes .../__pycache__/traversals.cpython-312.pyc | Bin 0 -> 42354 bytes .../sql/__pycache__/type_api.cpython-312.pyc | Bin 0 -> 86484 bytes .../sql/__pycache__/util.cpython-312.pyc | Bin 0 -> 54348 bytes .../sql/__pycache__/visitors.cpython-312.pyc | Bin 0 -> 36075 bytes .../sqlalchemy/sql/_dml_constructors.py | 140 + .../sqlalchemy/sql/_elements_constructors.py | 1850 ++++ .../sqlalchemy/sql/_orm_types.py | 20 + .../site-packages/sqlalchemy/sql/_py_util.py | 75 + .../sql/_selectable_constructors.py | 635 ++ .../site-packages/sqlalchemy/sql/_typing.py | 460 + .../sqlalchemy/sql/annotation.py | 585 ++ .../site-packages/sqlalchemy/sql/base.py | 2185 +++++ .../site-packages/sqlalchemy/sql/cache_key.py | 1057 ++ .../site-packages/sqlalchemy/sql/coercions.py | 1405 +++ .../site-packages/sqlalchemy/sql/compiler.py | 7818 +++++++++++++++ .../site-packages/sqlalchemy/sql/crud.py | 1669 ++++ .../site-packages/sqlalchemy/sql/ddl.py | 1378 +++ .../sqlalchemy/sql/default_comparator.py | 552 ++ .../site-packages/sqlalchemy/sql/dml.py | 1817 ++++ .../site-packages/sqlalchemy/sql/elements.py | 5499 +++++++++++ .../site-packages/sqlalchemy/sql/events.py | 455 + .../sqlalchemy/sql/expression.py | 162 + .../site-packages/sqlalchemy/sql/functions.py | 2055 ++++ .../site-packages/sqlalchemy/sql/lambdas.py | 1449 +++ .../site-packages/sqlalchemy/sql/naming.py | 212 + .../site-packages/sqlalchemy/sql/operators.py | 2579 +++++ .../site-packages/sqlalchemy/sql/roles.py | 323 + .../site-packages/sqlalchemy/sql/schema.py | 6158 ++++++++++++ .../sqlalchemy/sql/selectable.py | 7004 +++++++++++++ .../site-packages/sqlalchemy/sql/sqltypes.py | 3827 ++++++++ .../sqlalchemy/sql/traversals.py | 1024 ++ .../site-packages/sqlalchemy/sql/type_api.py | 2339 +++++ .../site-packages/sqlalchemy/sql/util.py | 1486 +++ .../site-packages/sqlalchemy/sql/visitors.py | 1165 +++ .../sqlalchemy/testing/__init__.py | 96 + .../__pycache__/__init__.cpython-312.pyc | Bin 0 -> 3336 bytes .../__pycache__/assertions.cpython-312.pyc | Bin 0 -> 41766 bytes .../__pycache__/assertsql.cpython-312.pyc | Bin 0 -> 20204 bytes .../__pycache__/asyncio.cpython-312.pyc | Bin 0 -> 4156 bytes .../__pycache__/config.cpython-312.pyc | Bin 0 -> 17668 bytes .../__pycache__/engines.cpython-312.pyc | Bin 0 -> 21568 bytes .../__pycache__/entities.cpython-312.pyc | Bin 0 -> 4990 bytes .../__pycache__/exclusions.cpython-312.pyc | Bin 0 -> 21248 bytes .../__pycache__/pickleable.cpython-312.pyc | Bin 0 -> 6695 bytes .../__pycache__/profiling.cpython-312.pyc | Bin 0 -> 12991 bytes .../__pycache__/provision.cpython-312.pyc | Bin 0 -> 20990 bytes .../__pycache__/requirements.cpython-312.pyc | Bin 0 -> 86558 bytes .../__pycache__/schema.cpython-312.pyc | Bin 0 -> 8967 bytes .../testing/__pycache__/util.cpython-312.pyc | Bin 0 -> 21674 bytes .../__pycache__/warnings.cpython-312.pyc | Bin 0 -> 2010 bytes .../sqlalchemy/testing/assertions.py | 989 ++ .../sqlalchemy/testing/assertsql.py | 516 + .../sqlalchemy/testing/asyncio.py | 135 + .../sqlalchemy/testing/config.py | 427 + .../sqlalchemy/testing/engines.py | 472 + .../sqlalchemy/testing/entities.py | 117 + .../sqlalchemy/testing/exclusions.py | 435 + .../sqlalchemy/testing/fixtures/__init__.py | 28 + .../__pycache__/__init__.cpython-312.pyc | Bin 0 -> 917 bytes .../fixtures/__pycache__/base.cpython-312.pyc | Bin 0 -> 13260 bytes .../fixtures/__pycache__/mypy.cpython-312.pyc | Bin 0 -> 12810 bytes .../fixtures/__pycache__/orm.cpython-312.pyc | Bin 0 -> 11456 bytes .../fixtures/__pycache__/sql.cpython-312.pyc | Bin 0 -> 22409 bytes .../sqlalchemy/testing/fixtures/base.py | 366 + .../sqlalchemy/testing/fixtures/mypy.py | 312 + .../sqlalchemy/testing/fixtures/orm.py | 227 + .../sqlalchemy/testing/fixtures/sql.py | 503 + .../sqlalchemy/testing/pickleable.py | 155 + .../sqlalchemy/testing/plugin/__init__.py | 6 + .../__pycache__/__init__.cpython-312.pyc | Bin 0 -> 206 bytes .../__pycache__/bootstrap.cpython-312.pyc | Bin 0 -> 2157 bytes .../__pycache__/plugin_base.cpython-312.pyc | Bin 0 -> 27745 bytes .../__pycache__/pytestplugin.cpython-312.pyc | Bin 0 -> 32816 bytes .../sqlalchemy/testing/plugin/bootstrap.py | 51 + .../sqlalchemy/testing/plugin/plugin_base.py | 779 ++ .../sqlalchemy/testing/plugin/pytestplugin.py | 868 ++ .../sqlalchemy/testing/profiling.py | 324 + .../sqlalchemy/testing/provision.py | 496 + .../sqlalchemy/testing/requirements.py | 1818 ++++ .../sqlalchemy/testing/schema.py | 224 + .../sqlalchemy/testing/suite/__init__.py | 19 + .../__pycache__/__init__.cpython-312.pyc | Bin 0 -> 573 bytes .../__pycache__/test_cte.cpython-312.pyc | Bin 0 -> 9907 bytes .../__pycache__/test_ddl.cpython-312.pyc | Bin 0 -> 18756 bytes .../test_deprecations.cpython-312.pyc | Bin 0 -> 9014 bytes .../__pycache__/test_dialect.cpython-312.pyc | Bin 0 -> 34402 bytes .../__pycache__/test_insert.cpython-312.pyc | Bin 0 -> 25282 bytes .../test_reflection.cpython-312.pyc | Bin 0 -> 141196 bytes .../__pycache__/test_results.cpython-312.pyc | Bin 0 -> 25264 bytes .../__pycache__/test_rowcount.cpython-312.pyc | Bin 0 -> 10357 bytes .../__pycache__/test_select.cpython-312.pyc | Bin 0 -> 114256 bytes .../__pycache__/test_sequence.cpython-312.pyc | Bin 0 -> 14989 bytes .../__pycache__/test_types.cpython-312.pyc | Bin 0 -> 98722 bytes .../test_unicode_ddl.cpython-312.pyc | Bin 0 -> 7627 bytes .../test_update_delete.cpython-312.pyc | Bin 0 -> 7391 bytes .../sqlalchemy/testing/suite/test_cte.py | 211 + .../sqlalchemy/testing/suite/test_ddl.py | 389 + .../testing/suite/test_deprecations.py | 153 + .../sqlalchemy/testing/suite/test_dialect.py | 740 ++ .../sqlalchemy/testing/suite/test_insert.py | 630 ++ .../testing/suite/test_reflection.py | 3225 ++++++ .../sqlalchemy/testing/suite/test_results.py | 502 + .../sqlalchemy/testing/suite/test_rowcount.py | 258 + .../sqlalchemy/testing/suite/test_select.py | 1999 ++++ .../sqlalchemy/testing/suite/test_sequence.py | 317 + .../sqlalchemy/testing/suite/test_types.py | 2141 ++++ .../testing/suite/test_unicode_ddl.py | 189 + .../testing/suite/test_update_delete.py | 139 + .../site-packages/sqlalchemy/testing/util.py | 537 + .../sqlalchemy/testing/warnings.py | 52 + .../site-packages/sqlalchemy/types.py | 76 + .../site-packages/sqlalchemy/util/__init__.py | 160 + .../util/__pycache__/__init__.cpython-312.pyc | Bin 0 -> 5684 bytes .../__pycache__/_collections.cpython-312.pyc | Bin 0 -> 31664 bytes .../_concurrency_py3k.cpython-312.pyc | Bin 0 -> 10852 bytes .../util/__pycache__/_has_cy.cpython-312.pyc | Bin 0 -> 1097 bytes .../_py_collections.cpython-312.pyc | Bin 0 -> 29240 bytes .../util/__pycache__/compat.cpython-312.pyc | Bin 0 -> 12466 bytes .../__pycache__/concurrency.cpython-312.pyc | Bin 0 -> 4049 bytes .../__pycache__/deprecations.cpython-312.pyc | Bin 0 -> 13609 bytes .../__pycache__/langhelpers.cpython-312.pyc | Bin 0 -> 84653 bytes .../__pycache__/preloaded.cpython-312.pyc | Bin 0 -> 5889 bytes .../util/__pycache__/queue.cpython-312.pyc | Bin 0 -> 14577 bytes .../__pycache__/tool_support.cpython-312.pyc | Bin 0 -> 8702 bytes .../__pycache__/topological.cpython-312.pyc | Bin 0 -> 3915 bytes .../util/__pycache__/typing.cpython-312.pyc | Bin 0 -> 21303 bytes .../sqlalchemy/util/_collections.py | 715 ++ .../sqlalchemy/util/_concurrency_py3k.py | 288 + .../site-packages/sqlalchemy/util/_has_cy.py | 40 + .../sqlalchemy/util/_py_collections.py | 541 + .../site-packages/sqlalchemy/util/compat.py | 301 + .../sqlalchemy/util/concurrency.py | 108 + .../sqlalchemy/util/deprecations.py | 401 + .../sqlalchemy/util/langhelpers.py | 2218 +++++ .../sqlalchemy/util/preloaded.py | 150 + .../site-packages/sqlalchemy/util/queue.py | 322 + .../sqlalchemy/util/tool_support.py | 201 + .../sqlalchemy/util/topological.py | 120 + .../site-packages/sqlalchemy/util/typing.py | 629 ++ .../sqlparse-0.5.3.dist-info/INSTALLER | 1 + .../sqlparse-0.5.3.dist-info/METADATA | 113 + .../sqlparse-0.5.3.dist-info/RECORD | 50 + .../sqlparse-0.5.3.dist-info/WHEEL | 4 + .../sqlparse-0.5.3.dist-info/entry_points.txt | 2 + .../sqlparse-0.5.3.dist-info/licenses/AUTHORS | 86 + .../sqlparse-0.5.3.dist-info/licenses/LICENSE | 25 + .../site-packages/sqlparse/__init__.py | 72 + .../site-packages/sqlparse/__main__.py | 22 + .../__pycache__/__init__.cpython-312.pyc | Bin 0 -> 3103 bytes .../__pycache__/__main__.cpython-312.pyc | Bin 0 -> 659 bytes .../sqlparse/__pycache__/cli.cpython-312.pyc | Bin 0 -> 7420 bytes .../__pycache__/exceptions.cpython-312.pyc | Bin 0 -> 485 bytes .../__pycache__/formatter.cpython-312.pyc | Bin 0 -> 8364 bytes .../__pycache__/keywords.cpython-312.pyc | Bin 0 -> 51136 bytes .../__pycache__/lexer.cpython-312.pyc | Bin 0 -> 6775 bytes .../sqlparse/__pycache__/sql.cpython-312.pyc | Bin 0 -> 31766 bytes .../__pycache__/tokens.cpython-312.pyc | Bin 0 -> 2280 bytes .../__pycache__/utils.cpython-312.pyc | Bin 0 -> 4587 bytes .../python3.12/site-packages/sqlparse/cli.py | 203 + .../site-packages/sqlparse/engine/__init__.py | 16 + .../__pycache__/__init__.cpython-312.pyc | Bin 0 -> 432 bytes .../__pycache__/filter_stack.cpython-312.pyc | Bin 0 -> 2234 bytes .../__pycache__/grouping.cpython-312.pyc | Bin 0 -> 25092 bytes .../statement_splitter.cpython-312.pyc | Bin 0 -> 3993 bytes .../sqlparse/engine/filter_stack.py | 51 + .../site-packages/sqlparse/engine/grouping.py | 486 + .../sqlparse/engine/statement_splitter.py | 115 + .../site-packages/sqlparse/exceptions.py | 12 + .../sqlparse/filters/__init__.py | 42 + .../__pycache__/__init__.cpython-312.pyc | Bin 0 -> 1022 bytes .../aligned_indent.cpython-312.pyc | Bin 0 -> 7946 bytes .../__pycache__/others.cpython-312.pyc | Bin 0 -> 9988 bytes .../__pycache__/output.cpython-312.pyc | Bin 0 -> 6517 bytes .../__pycache__/reindent.cpython-312.pyc | Bin 0 -> 15571 bytes .../__pycache__/right_margin.cpython-312.pyc | Bin 0 -> 2215 bytes .../__pycache__/tokens.cpython-312.pyc | Bin 0 -> 2916 bytes .../sqlparse/filters/aligned_indent.py | 135 + .../site-packages/sqlparse/filters/others.py | 172 + .../site-packages/sqlparse/filters/output.py | 122 + .../sqlparse/filters/reindent.py | 247 + .../sqlparse/filters/right_margin.py | 48 + .../site-packages/sqlparse/filters/tokens.py | 59 + .../site-packages/sqlparse/formatter.py | 204 + .../site-packages/sqlparse/keywords.py | 1002 ++ .../site-packages/sqlparse/lexer.py | 161 + .../python3.12/site-packages/sqlparse/sql.py | 660 ++ .../site-packages/sqlparse/tokens.py | 71 + .../site-packages/sqlparse/utils.py | 124 + .../termcolor-2.5.0.dist-info/INSTALLER | 1 + .../termcolor-2.5.0.dist-info/METADATA | 142 + .../termcolor-2.5.0.dist-info/RECORD | 14 + .../termcolor-2.5.0.dist-info/WHEEL | 4 + .../licenses/COPYING.txt | 19 + .../site-packages/termcolor/__init__.py | 14 + .../site-packages/termcolor/__main__.py | 69 + .../__pycache__/__init__.cpython-312.pyc | Bin 0 -> 473 bytes .../__pycache__/__main__.cpython-312.pyc | Bin 0 -> 3494 bytes .../__pycache__/_types.cpython-312.pyc | Bin 0 -> 821 bytes .../__pycache__/termcolor.cpython-312.pyc | Bin 0 -> 5726 bytes .../site-packages/termcolor/_types.py | 53 + .../site-packages/termcolor/py.typed | 0 .../site-packages/termcolor/termcolor.py | 214 + .../INSTALLER | 1 + .../LICENSE | 279 + .../METADATA | 67 + .../typing_extensions-4.12.2.dist-info/RECORD | 7 + .../typing_extensions-4.12.2.dist-info/WHEEL | 4 + .../site-packages/typing_extensions.py | 3641 +++++++ .../urllib3-2.2.3.dist-info/INSTALLER | 1 + .../urllib3-2.2.3.dist-info/METADATA | 155 + .../urllib3-2.2.3.dist-info/RECORD | 79 + .../urllib3-2.2.3.dist-info/WHEEL | 4 + .../licenses/LICENSE.txt | 21 + .../site-packages/urllib3/__init__.py | 211 + .../__pycache__/__init__.cpython-312.pyc | Bin 0 -> 7313 bytes .../_base_connection.cpython-312.pyc | Bin 0 -> 6860 bytes .../__pycache__/_collections.cpython-312.pyc | Bin 0 -> 22602 bytes .../_request_methods.cpython-312.pyc | Bin 0 -> 10629 bytes .../__pycache__/_version.cpython-312.pyc | Bin 0 -> 590 bytes .../__pycache__/connection.cpython-312.pyc | Bin 0 -> 35743 bytes .../connectionpool.cpython-312.pyc | Bin 0 -> 39741 bytes .../__pycache__/exceptions.cpython-312.pyc | Bin 0 -> 15835 bytes .../__pycache__/fields.cpython-312.pyc | Bin 0 -> 12057 bytes .../__pycache__/filepost.cpython-312.pyc | Bin 0 -> 3506 bytes .../__pycache__/poolmanager.cpython-312.pyc | Bin 0 -> 24034 bytes .../__pycache__/response.cpython-312.pyc | Bin 0 -> 50446 bytes .../site-packages/urllib3/_base_connection.py | 172 + .../site-packages/urllib3/_collections.py | 483 + .../site-packages/urllib3/_request_methods.py | 278 + .../site-packages/urllib3/_version.py | 16 + .../site-packages/urllib3/connection.py | 1033 ++ .../site-packages/urllib3/connectionpool.py | 1182 +++ .../site-packages/urllib3/contrib/__init__.py | 0 .../__pycache__/__init__.cpython-312.pyc | Bin 0 -> 196 bytes .../__pycache__/pyopenssl.cpython-312.pyc | Bin 0 -> 27277 bytes .../contrib/__pycache__/socks.cpython-312.pyc | Bin 0 -> 8174 bytes .../urllib3/contrib/emscripten/__init__.py | 16 + .../__pycache__/__init__.cpython-312.pyc | Bin 0 -> 904 bytes .../__pycache__/connection.cpython-312.pyc | Bin 0 -> 10238 bytes .../__pycache__/fetch.cpython-312.pyc | Bin 0 -> 18374 bytes .../__pycache__/request.cpython-312.pyc | Bin 0 -> 1424 bytes .../__pycache__/response.cpython-312.pyc | Bin 0 -> 12701 bytes .../urllib3/contrib/emscripten/connection.py | 254 + .../emscripten/emscripten_fetch_worker.js | 110 + .../urllib3/contrib/emscripten/fetch.py | 418 + .../urllib3/contrib/emscripten/request.py | 22 + .../urllib3/contrib/emscripten/response.py | 285 + .../urllib3/contrib/pyopenssl.py | 552 ++ .../site-packages/urllib3/contrib/socks.py | 228 + .../site-packages/urllib3/exceptions.py | 321 + .../site-packages/urllib3/fields.py | 341 + .../site-packages/urllib3/filepost.py | 89 + .../site-packages/urllib3/http2/__init__.py | 53 + .../__pycache__/__init__.cpython-312.pyc | Bin 0 -> 1749 bytes .../__pycache__/connection.cpython-312.pyc | Bin 0 -> 16970 bytes .../http2/__pycache__/probe.cpython-312.pyc | Bin 0 -> 3660 bytes .../site-packages/urllib3/http2/connection.py | 356 + .../site-packages/urllib3/http2/probe.py | 87 + .../site-packages/urllib3/poolmanager.py | 637 ++ .../python3.12/site-packages/urllib3/py.typed | 2 + .../site-packages/urllib3/response.py | 1265 +++ .../site-packages/urllib3/util/__init__.py | 42 + .../util/__pycache__/__init__.cpython-312.pyc | Bin 0 -> 1009 bytes .../__pycache__/connection.cpython-312.pyc | Bin 0 -> 4738 bytes .../util/__pycache__/proxy.cpython-312.pyc | Bin 0 -> 1221 bytes .../util/__pycache__/request.cpython-312.pyc | Bin 0 -> 8035 bytes .../util/__pycache__/response.cpython-312.pyc | Bin 0 -> 2880 bytes .../util/__pycache__/retry.cpython-312.pyc | Bin 0 -> 20295 bytes .../util/__pycache__/ssl_.cpython-312.pyc | Bin 0 -> 16709 bytes .../ssl_match_hostname.cpython-312.pyc | Bin 0 -> 5541 bytes .../__pycache__/ssltransport.cpython-312.pyc | Bin 0 -> 13311 bytes .../util/__pycache__/timeout.cpython-312.pyc | Bin 0 -> 11693 bytes .../util/__pycache__/url.cpython-312.pyc | Bin 0 -> 16227 bytes .../util/__pycache__/util.cpython-312.pyc | Bin 0 -> 1998 bytes .../util/__pycache__/wait.cpython-312.pyc | Bin 0 -> 3444 bytes .../site-packages/urllib3/util/connection.py | 137 + .../site-packages/urllib3/util/proxy.py | 43 + .../site-packages/urllib3/util/request.py | 256 + .../site-packages/urllib3/util/response.py | 101 + .../site-packages/urllib3/util/retry.py | 533 + .../site-packages/urllib3/util/ssl_.py | 513 + .../urllib3/util/ssl_match_hostname.py | 159 + .../urllib3/util/ssltransport.py | 276 + .../site-packages/urllib3/util/timeout.py | 275 + .../site-packages/urllib3/util/url.py | 471 + .../site-packages/urllib3/util/util.py | 42 + .../site-packages/urllib3/util/wait.py | 124 + .../werkzeug-3.1.3.dist-info/INSTALLER | 1 + .../werkzeug-3.1.3.dist-info/LICENSE.txt | 28 + .../werkzeug-3.1.3.dist-info/METADATA | 99 + .../werkzeug-3.1.3.dist-info/RECORD | 116 + .../werkzeug-3.1.3.dist-info/WHEEL | 4 + .../site-packages/werkzeug/__init__.py | 4 + .../__pycache__/__init__.cpython-312.pyc | Bin 0 -> 343 bytes .../__pycache__/_internal.cpython-312.pyc | Bin 0 -> 9766 bytes .../__pycache__/_reloader.cpython-312.pyc | Bin 0 -> 20556 bytes .../__pycache__/exceptions.cpython-312.pyc | Bin 0 -> 33327 bytes .../__pycache__/formparser.cpython-312.pyc | Bin 0 -> 17024 bytes .../werkzeug/__pycache__/http.cpython-312.pyc | Bin 0 -> 50215 bytes .../__pycache__/local.cpython-312.pyc | Bin 0 -> 28467 bytes .../__pycache__/security.cpython-312.pyc | Bin 0 -> 7134 bytes .../__pycache__/serving.cpython-312.pyc | Bin 0 -> 46092 bytes .../werkzeug/__pycache__/test.cpython-312.pyc | Bin 0 -> 59815 bytes .../__pycache__/testapp.cpython-312.pyc | Bin 0 -> 8866 bytes .../werkzeug/__pycache__/urls.cpython-312.pyc | Bin 0 -> 8267 bytes .../__pycache__/user_agent.cpython-312.pyc | Bin 0 -> 2156 bytes .../__pycache__/utils.cpython-312.pyc | Bin 0 -> 28135 bytes .../werkzeug/__pycache__/wsgi.cpython-312.pyc | Bin 0 -> 25212 bytes .../site-packages/werkzeug/_internal.py | 211 + .../site-packages/werkzeug/_reloader.py | 471 + .../werkzeug/datastructures/__init__.py | 64 + .../__pycache__/__init__.cpython-312.pyc | Bin 0 -> 2420 bytes .../__pycache__/accept.cpython-312.pyc | Bin 0 -> 15920 bytes .../__pycache__/auth.cpython-312.pyc | Bin 0 -> 14453 bytes .../__pycache__/cache_control.cpython-312.pyc | Bin 0 -> 12226 bytes .../__pycache__/csp.cpython-312.pyc | Bin 0 -> 6189 bytes .../__pycache__/etag.cpython-312.pyc | Bin 0 -> 5413 bytes .../__pycache__/file_storage.cpython-312.pyc | Bin 0 -> 8827 bytes .../__pycache__/headers.cpython-312.pyc | Bin 0 -> 30460 bytes .../__pycache__/mixins.cpython-312.pyc | Bin 0 -> 16403 bytes .../__pycache__/range.cpython-312.pyc | Bin 0 -> 10046 bytes .../__pycache__/structures.cpython-312.pyc | Bin 0 -> 58941 bytes .../werkzeug/datastructures/accept.py | 350 + .../werkzeug/datastructures/auth.py | 317 + .../werkzeug/datastructures/cache_control.py | 273 + .../werkzeug/datastructures/csp.py | 100 + .../werkzeug/datastructures/etag.py | 106 + .../werkzeug/datastructures/file_storage.py | 209 + .../werkzeug/datastructures/headers.py | 662 ++ .../werkzeug/datastructures/mixins.py | 317 + .../werkzeug/datastructures/range.py | 214 + .../werkzeug/datastructures/structures.py | 1239 +++ .../site-packages/werkzeug/debug/__init__.py | 565 ++ .../__pycache__/__init__.cpython-312.pyc | Bin 0 -> 23410 bytes .../debug/__pycache__/console.cpython-312.pyc | Bin 0 -> 11635 bytes .../debug/__pycache__/repr.cpython-312.pyc | Bin 0 -> 13777 bytes .../debug/__pycache__/tbtools.cpython-312.pyc | Bin 0 -> 16978 bytes .../site-packages/werkzeug/debug/console.py | 219 + .../site-packages/werkzeug/debug/repr.py | 282 + .../werkzeug/debug/shared/ICON_LICENSE.md | 6 + .../werkzeug/debug/shared/console.png | Bin 0 -> 507 bytes .../werkzeug/debug/shared/debugger.js | 344 + .../werkzeug/debug/shared/less.png | Bin 0 -> 191 bytes .../werkzeug/debug/shared/more.png | Bin 0 -> 200 bytes .../werkzeug/debug/shared/style.css | 150 + .../site-packages/werkzeug/debug/tbtools.py | 450 + .../site-packages/werkzeug/exceptions.py | 894 ++ .../site-packages/werkzeug/formparser.py | 430 + .../python3.12/site-packages/werkzeug/http.py | 1405 +++ .../site-packages/werkzeug/local.py | 653 ++ .../werkzeug/middleware/__init__.py | 0 .../__pycache__/__init__.cpython-312.pyc | Bin 0 -> 200 bytes .../__pycache__/dispatcher.cpython-312.pyc | Bin 0 -> 3318 bytes .../__pycache__/http_proxy.cpython-312.pyc | Bin 0 -> 9414 bytes .../__pycache__/lint.cpython-312.pyc | Bin 0 -> 17760 bytes .../__pycache__/profiler.cpython-312.pyc | Bin 0 -> 7204 bytes .../__pycache__/proxy_fix.cpython-312.pyc | Bin 0 -> 7201 bytes .../__pycache__/shared_data.cpython-312.pyc | Bin 0 -> 12736 bytes .../werkzeug/middleware/dispatcher.py | 81 + .../werkzeug/middleware/http_proxy.py | 236 + .../site-packages/werkzeug/middleware/lint.py | 439 + .../werkzeug/middleware/profiler.py | 155 + .../werkzeug/middleware/proxy_fix.py | 183 + .../werkzeug/middleware/shared_data.py | 283 + .../site-packages/werkzeug/py.typed | 0 .../werkzeug/routing/__init__.py | 134 + .../__pycache__/__init__.cpython-312.pyc | Bin 0 -> 4673 bytes .../__pycache__/converters.cpython-312.pyc | Bin 0 -> 10920 bytes .../__pycache__/exceptions.cpython-312.pyc | Bin 0 -> 7916 bytes .../routing/__pycache__/map.cpython-312.pyc | Bin 0 -> 39801 bytes .../__pycache__/matcher.cpython-312.pyc | Bin 0 -> 8239 bytes .../routing/__pycache__/rules.cpython-312.pyc | Bin 0 -> 39085 bytes .../werkzeug/routing/converters.py | 261 + .../werkzeug/routing/exceptions.py | 152 + .../site-packages/werkzeug/routing/map.py | 951 ++ .../site-packages/werkzeug/routing/matcher.py | 202 + .../site-packages/werkzeug/routing/rules.py | 928 ++ .../site-packages/werkzeug/sansio/__init__.py | 0 .../__pycache__/__init__.cpython-312.pyc | Bin 0 -> 196 bytes .../sansio/__pycache__/http.cpython-312.pyc | Bin 0 -> 5642 bytes .../__pycache__/multipart.cpython-312.pyc | Bin 0 -> 14045 bytes .../__pycache__/request.cpython-312.pyc | Bin 0 -> 21889 bytes .../__pycache__/response.cpython-312.pyc | Bin 0 -> 31733 bytes .../sansio/__pycache__/utils.cpython-312.pyc | Bin 0 -> 6181 bytes .../site-packages/werkzeug/sansio/http.py | 170 + .../werkzeug/sansio/multipart.py | 323 + .../site-packages/werkzeug/sansio/request.py | 534 + .../site-packages/werkzeug/sansio/response.py | 763 ++ .../site-packages/werkzeug/sansio/utils.py | 167 + .../site-packages/werkzeug/security.py | 166 + .../site-packages/werkzeug/serving.py | 1125 +++ .../python3.12/site-packages/werkzeug/test.py | 1464 +++ .../site-packages/werkzeug/testapp.py | 194 + .../python3.12/site-packages/werkzeug/urls.py | 203 + .../site-packages/werkzeug/user_agent.py | 47 + .../site-packages/werkzeug/utils.py | 691 ++ .../werkzeug/wrappers/__init__.py | 3 + .../__pycache__/__init__.cpython-312.pyc | Bin 0 -> 320 bytes .../__pycache__/request.cpython-312.pyc | Bin 0 -> 26129 bytes .../__pycache__/response.cpython-312.pyc | Bin 0 -> 34561 bytes .../werkzeug/wrappers/request.py | 650 ++ .../werkzeug/wrappers/response.py | 831 ++ .../python3.12/site-packages/werkzeug/wsgi.py | 595 ++ .../wheel-0.45.1.dist-info/INSTALLER | 1 + .../wheel-0.45.1.dist-info/LICENSE.txt | 21 + .../wheel-0.45.1.dist-info/METADATA | 66 + .../wheel-0.45.1.dist-info/RECORD | 67 + .../wheel-0.45.1.dist-info/WHEEL | 4 + .../wheel-0.45.1.dist-info/entry_points.txt | 6 + .../site-packages/wheel/__init__.py | 3 + .../site-packages/wheel/__main__.py | 23 + .../__pycache__/__init__.cpython-312.pyc | Bin 0 -> 265 bytes .../__pycache__/__main__.cpython-312.pyc | Bin 0 -> 1000 bytes .../__pycache__/_bdist_wheel.cpython-312.pyc | Bin 0 -> 25969 bytes .../_setuptools_logging.cpython-312.pyc | Bin 0 -> 1411 bytes .../__pycache__/bdist_wheel.cpython-312.pyc | Bin 0 -> 777 bytes .../macosx_libfile.cpython-312.pyc | Bin 0 -> 16219 bytes .../__pycache__/metadata.cpython-312.pyc | Bin 0 -> 8630 bytes .../wheel/__pycache__/util.cpython-312.pyc | Bin 0 -> 953 bytes .../__pycache__/wheelfile.cpython-312.pyc | Bin 0 -> 11457 bytes .../site-packages/wheel/_bdist_wheel.py | 613 ++ .../wheel/_setuptools_logging.py | 26 + .../site-packages/wheel/bdist_wheel.py | 26 + .../site-packages/wheel/cli/__init__.py | 155 + .../cli/__pycache__/__init__.cpython-312.pyc | Bin 0 -> 6928 bytes .../cli/__pycache__/convert.cpython-312.pyc | Bin 0 -> 16070 bytes .../cli/__pycache__/pack.cpython-312.pyc | Bin 0 -> 4451 bytes .../cli/__pycache__/tags.cpython-312.pyc | Bin 0 -> 6717 bytes .../cli/__pycache__/unpack.cpython-312.pyc | Bin 0 -> 1516 bytes .../site-packages/wheel/cli/convert.py | 332 + .../site-packages/wheel/cli/pack.py | 85 + .../site-packages/wheel/cli/tags.py | 139 + .../site-packages/wheel/cli/unpack.py | 30 + .../site-packages/wheel/macosx_libfile.py | 482 + .../site-packages/wheel/metadata.py | 183 + .../python3.12/site-packages/wheel/util.py | 17 + .../site-packages/wheel/vendored/__init__.py | 0 .../__pycache__/__init__.cpython-312.pyc | Bin 0 -> 195 bytes .../wheel/vendored/packaging/LICENSE | 3 + .../wheel/vendored/packaging/LICENSE.APACHE | 177 + .../wheel/vendored/packaging/LICENSE.BSD | 23 + .../wheel/vendored/packaging/__init__.py | 0 .../__pycache__/__init__.cpython-312.pyc | Bin 0 -> 205 bytes .../__pycache__/_elffile.cpython-312.pyc | Bin 0 -> 5031 bytes .../__pycache__/_manylinux.cpython-312.pyc | Bin 0 -> 9858 bytes .../__pycache__/_musllinux.cpython-312.pyc | Bin 0 -> 4571 bytes .../__pycache__/_parser.cpython-312.pyc | Bin 0 -> 14061 bytes .../__pycache__/_structures.cpython-312.pyc | Bin 0 -> 3253 bytes .../__pycache__/_tokenizer.cpython-312.pyc | Bin 0 -> 7953 bytes .../__pycache__/markers.cpython-312.pyc | Bin 0 -> 10524 bytes .../__pycache__/requirements.cpython-312.pyc | Bin 0 -> 4466 bytes .../__pycache__/specifiers.cpython-312.pyc | Bin 0 -> 39536 bytes .../__pycache__/tags.cpython-312.pyc | Bin 0 -> 21664 bytes .../__pycache__/utils.cpython-312.pyc | Bin 0 -> 7298 bytes .../__pycache__/version.cpython-312.pyc | Bin 0 -> 20014 bytes .../wheel/vendored/packaging/_elffile.py | 108 + .../wheel/vendored/packaging/_manylinux.py | 260 + .../wheel/vendored/packaging/_musllinux.py | 83 + .../wheel/vendored/packaging/_parser.py | 356 + .../wheel/vendored/packaging/_structures.py | 61 + .../wheel/vendored/packaging/_tokenizer.py | 192 + .../wheel/vendored/packaging/markers.py | 253 + .../wheel/vendored/packaging/requirements.py | 90 + .../wheel/vendored/packaging/specifiers.py | 1011 ++ .../wheel/vendored/packaging/tags.py | 571 ++ .../wheel/vendored/packaging/utils.py | 172 + .../wheel/vendored/packaging/version.py | 561 ++ .../site-packages/wheel/vendored/vendor.txt | 1 + .../site-packages/wheel/wheelfile.py | 227 + psets/9/finance/env/lib64 | 1 + psets/9/finance/env/pyvenv.cfg | 5 + psets/9/finance/finance.db | Bin 24576 -> 24576 bytes .../2029240f6d1128be89ddc32729463129 | Bin 9 -> 9 bytes .../497876a3b151a6b60f167574a809af69 | Bin 0 -> 46 bytes 2992 files changed, 532618 insertions(+), 11 deletions(-) create mode 100644 psets/9/finance/.idea/dataSources.xml create mode 100644 psets/9/finance/.idea/misc.xml create mode 100644 psets/9/finance/.idea/vcs.xml create mode 100644 psets/9/finance/Dockerfile create mode 100644 psets/9/finance/__pycache__/app.cpython-312.pyc create mode 100644 psets/9/finance/__pycache__/helpers.cpython-312.pyc create mode 100644 psets/9/finance/docker-compose.yml create mode 100644 psets/9/finance/env/bin/Activate.ps1 create mode 100644 psets/9/finance/env/bin/activate create mode 100644 psets/9/finance/env/bin/activate.csh create mode 100644 psets/9/finance/env/bin/activate.fish create mode 100644 psets/9/finance/env/bin/automat-visualize create mode 100644 psets/9/finance/env/bin/flask create mode 100644 psets/9/finance/env/bin/normalizer create mode 100644 psets/9/finance/env/bin/pip create mode 100644 psets/9/finance/env/bin/pip3 create mode 100644 psets/9/finance/env/bin/pip3.12 create mode 120000 psets/9/finance/env/bin/python create mode 120000 psets/9/finance/env/bin/python3 create mode 120000 psets/9/finance/env/bin/python3.12 create mode 100644 psets/9/finance/env/bin/sqlformat create mode 100644 psets/9/finance/env/bin/wheel create mode 100644 psets/9/finance/env/include/site/python3.12/greenlet/greenlet.h create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/Automat-24.8.1.dist-info/INSTALLER create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/Automat-24.8.1.dist-info/LICENSE create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/Automat-24.8.1.dist-info/METADATA create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/Automat-24.8.1.dist-info/RECORD create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/Automat-24.8.1.dist-info/REQUESTED create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/Automat-24.8.1.dist-info/WHEEL create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/Automat-24.8.1.dist-info/entry_points.txt create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/Automat-24.8.1.dist-info/top_level.txt create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/MarkupSafe-3.0.2.dist-info/INSTALLER create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/MarkupSafe-3.0.2.dist-info/LICENSE.txt create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/MarkupSafe-3.0.2.dist-info/METADATA create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/MarkupSafe-3.0.2.dist-info/RECORD create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/MarkupSafe-3.0.2.dist-info/WHEEL create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/MarkupSafe-3.0.2.dist-info/top_level.txt create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/SQLAlchemy-2.0.36.dist-info/INSTALLER create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/SQLAlchemy-2.0.36.dist-info/LICENSE create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/SQLAlchemy-2.0.36.dist-info/METADATA create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/SQLAlchemy-2.0.36.dist-info/RECORD create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/SQLAlchemy-2.0.36.dist-info/REQUESTED create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/SQLAlchemy-2.0.36.dist-info/WHEEL create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/SQLAlchemy-2.0.36.dist-info/top_level.txt create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/__pycache__/typing_extensions.cpython-312.pyc create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/automat/__init__.py create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/automat/__pycache__/__init__.cpython-312.pyc create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/automat/__pycache__/_core.cpython-312.pyc create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/automat/__pycache__/_discover.cpython-312.pyc create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/automat/__pycache__/_introspection.cpython-312.pyc create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/automat/__pycache__/_methodical.cpython-312.pyc create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/automat/__pycache__/_runtimeproto.cpython-312.pyc create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/automat/__pycache__/_typed.cpython-312.pyc create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/automat/__pycache__/_visualize.cpython-312.pyc create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/automat/_core.py create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/automat/_discover.py create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/automat/_introspection.py create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/automat/_methodical.py create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/automat/_runtimeproto.py create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/automat/_test/__init__.py create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/automat/_test/__pycache__/__init__.cpython-312.pyc create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/automat/_test/__pycache__/test_core.cpython-312.pyc create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/automat/_test/__pycache__/test_discover.cpython-312.pyc create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/automat/_test/__pycache__/test_methodical.cpython-312.pyc create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/automat/_test/__pycache__/test_trace.cpython-312.pyc create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/automat/_test/__pycache__/test_type_based.cpython-312.pyc create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/automat/_test/__pycache__/test_visualize.cpython-312.pyc create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/automat/_test/test_core.py create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/automat/_test/test_discover.py create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/automat/_test/test_methodical.py create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/automat/_test/test_trace.py create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/automat/_test/test_type_based.py create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/automat/_test/test_visualize.py create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/automat/_typed.py create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/automat/_visualize.py create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/automat/py.typed create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/blinker-1.9.0.dist-info/INSTALLER create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/blinker-1.9.0.dist-info/LICENSE.txt create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/blinker-1.9.0.dist-info/METADATA create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/blinker-1.9.0.dist-info/RECORD create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/blinker-1.9.0.dist-info/WHEEL create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/blinker/__init__.py create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/blinker/__pycache__/__init__.cpython-312.pyc create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/blinker/__pycache__/_utilities.cpython-312.pyc create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/blinker/__pycache__/base.cpython-312.pyc create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/blinker/_utilities.py create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/blinker/base.py create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/blinker/py.typed create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/cachelib-0.13.0.dist-info/INSTALLER create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/cachelib-0.13.0.dist-info/LICENSE.rst create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/cachelib-0.13.0.dist-info/METADATA create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/cachelib-0.13.0.dist-info/RECORD create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/cachelib-0.13.0.dist-info/WHEEL create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/cachelib-0.13.0.dist-info/top_level.txt create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/cachelib/__init__.py create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/cachelib/__pycache__/__init__.cpython-312.pyc create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/cachelib/__pycache__/base.cpython-312.pyc create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/cachelib/__pycache__/dynamodb.cpython-312.pyc create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/cachelib/__pycache__/file.cpython-312.pyc create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/cachelib/__pycache__/memcached.cpython-312.pyc create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/cachelib/__pycache__/mongodb.cpython-312.pyc create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/cachelib/__pycache__/redis.cpython-312.pyc create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/cachelib/__pycache__/serializers.cpython-312.pyc create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/cachelib/__pycache__/simple.cpython-312.pyc create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/cachelib/__pycache__/uwsgi.cpython-312.pyc create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/cachelib/base.py create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/cachelib/dynamodb.py create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/cachelib/file.py create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/cachelib/memcached.py create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/cachelib/mongodb.py create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/cachelib/py.typed create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/cachelib/redis.py create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/cachelib/serializers.py create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/cachelib/simple.py create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/cachelib/uwsgi.py create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/certifi-2024.8.30.dist-info/INSTALLER create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/certifi-2024.8.30.dist-info/LICENSE create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/certifi-2024.8.30.dist-info/METADATA create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/certifi-2024.8.30.dist-info/RECORD create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/certifi-2024.8.30.dist-info/WHEEL create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/certifi-2024.8.30.dist-info/top_level.txt create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/certifi/__init__.py create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/certifi/__main__.py create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/certifi/__pycache__/__init__.cpython-312.pyc create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/certifi/__pycache__/__main__.cpython-312.pyc create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/certifi/__pycache__/core.cpython-312.pyc create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/certifi/cacert.pem create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/certifi/core.py create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/certifi/py.typed create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/charset_normalizer-3.4.0.dist-info/INSTALLER create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/charset_normalizer-3.4.0.dist-info/LICENSE create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/charset_normalizer-3.4.0.dist-info/METADATA create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/charset_normalizer-3.4.0.dist-info/RECORD create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/charset_normalizer-3.4.0.dist-info/WHEEL create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/charset_normalizer-3.4.0.dist-info/entry_points.txt create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/charset_normalizer-3.4.0.dist-info/top_level.txt create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/charset_normalizer/__init__.py create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/charset_normalizer/__main__.py create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/charset_normalizer/__pycache__/__init__.cpython-312.pyc create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/charset_normalizer/__pycache__/__main__.cpython-312.pyc create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/charset_normalizer/__pycache__/api.cpython-312.pyc create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/charset_normalizer/__pycache__/cd.cpython-312.pyc create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/charset_normalizer/__pycache__/constant.cpython-312.pyc create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/charset_normalizer/__pycache__/legacy.cpython-312.pyc create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/charset_normalizer/__pycache__/md.cpython-312.pyc create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/charset_normalizer/__pycache__/models.cpython-312.pyc create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/charset_normalizer/__pycache__/utils.cpython-312.pyc create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/charset_normalizer/__pycache__/version.cpython-312.pyc create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/charset_normalizer/api.py create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/charset_normalizer/cd.py create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/charset_normalizer/cli/__init__.py create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/charset_normalizer/cli/__main__.py create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/charset_normalizer/cli/__pycache__/__init__.cpython-312.pyc create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/charset_normalizer/cli/__pycache__/__main__.cpython-312.pyc create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/charset_normalizer/constant.py create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/charset_normalizer/legacy.py create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/charset_normalizer/md.cpython-312-x86_64-linux-gnu.so create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/charset_normalizer/md.py create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/charset_normalizer/md__mypyc.cpython-312-x86_64-linux-gnu.so create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/charset_normalizer/models.py create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/charset_normalizer/py.typed create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/charset_normalizer/utils.py create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/charset_normalizer/version.py create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/click-8.1.7.dist-info/INSTALLER create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/click-8.1.7.dist-info/LICENSE.rst create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/click-8.1.7.dist-info/METADATA create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/click-8.1.7.dist-info/RECORD create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/click-8.1.7.dist-info/WHEEL create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/click-8.1.7.dist-info/top_level.txt create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/click/__init__.py create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/click/__pycache__/__init__.cpython-312.pyc create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/click/__pycache__/_compat.cpython-312.pyc create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/click/__pycache__/_termui_impl.cpython-312.pyc create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/click/__pycache__/_textwrap.cpython-312.pyc create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/click/__pycache__/_winconsole.cpython-312.pyc create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/click/__pycache__/core.cpython-312.pyc create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/click/__pycache__/decorators.cpython-312.pyc create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/click/__pycache__/exceptions.cpython-312.pyc create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/click/__pycache__/formatting.cpython-312.pyc create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/click/__pycache__/globals.cpython-312.pyc create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/click/__pycache__/parser.cpython-312.pyc create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/click/__pycache__/shell_completion.cpython-312.pyc create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/click/__pycache__/termui.cpython-312.pyc create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/click/__pycache__/testing.cpython-312.pyc create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/click/__pycache__/types.cpython-312.pyc create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/click/__pycache__/utils.cpython-312.pyc create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/click/_compat.py create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/click/_termui_impl.py create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/click/_textwrap.py create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/click/_winconsole.py create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/click/core.py create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/click/decorators.py create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/click/exceptions.py create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/click/formatting.py create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/click/globals.py create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/click/parser.py create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/click/py.typed create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/click/shell_completion.py create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/click/termui.py create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/click/testing.py create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/click/types.py create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/click/utils.py create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/cs50-9.4.0.dist-info/INSTALLER create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/cs50-9.4.0.dist-info/LICENSE create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/cs50-9.4.0.dist-info/METADATA create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/cs50-9.4.0.dist-info/RECORD create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/cs50-9.4.0.dist-info/REQUESTED create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/cs50-9.4.0.dist-info/WHEEL create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/cs50-9.4.0.dist-info/top_level.txt create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/cs50/__init__.py create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/cs50/__pycache__/__init__.cpython-312.pyc create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/cs50/__pycache__/cs50.cpython-312.pyc create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/cs50/__pycache__/flask.cpython-312.pyc create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/cs50/__pycache__/sql.cpython-312.pyc create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/cs50/cs50.py create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/cs50/flask.py create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/cs50/sql.py create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/flask-3.1.0.dist-info/INSTALLER create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/flask-3.1.0.dist-info/LICENSE.txt create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/flask-3.1.0.dist-info/METADATA create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/flask-3.1.0.dist-info/RECORD create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/flask-3.1.0.dist-info/WHEEL create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/flask-3.1.0.dist-info/entry_points.txt create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/flask/__init__.py create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/flask/__main__.py create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/flask/__pycache__/__init__.cpython-312.pyc create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/flask/__pycache__/__main__.cpython-312.pyc create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/flask/__pycache__/app.cpython-312.pyc create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/flask/__pycache__/blueprints.cpython-312.pyc create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/flask/__pycache__/cli.cpython-312.pyc create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/flask/__pycache__/config.cpython-312.pyc create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/flask/__pycache__/ctx.cpython-312.pyc create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/flask/__pycache__/debughelpers.cpython-312.pyc create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/flask/__pycache__/globals.cpython-312.pyc create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/flask/__pycache__/helpers.cpython-312.pyc create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/flask/__pycache__/logging.cpython-312.pyc create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/flask/__pycache__/sessions.cpython-312.pyc create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/flask/__pycache__/signals.cpython-312.pyc create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/flask/__pycache__/templating.cpython-312.pyc create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/flask/__pycache__/testing.cpython-312.pyc create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/flask/__pycache__/typing.cpython-312.pyc create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/flask/__pycache__/views.cpython-312.pyc create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/flask/__pycache__/wrappers.cpython-312.pyc create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/flask/app.py create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/flask/blueprints.py create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/flask/cli.py create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/flask/config.py create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/flask/ctx.py create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/flask/debughelpers.py create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/flask/globals.py create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/flask/helpers.py create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/flask/json/__init__.py create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/flask/json/__pycache__/__init__.cpython-312.pyc create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/flask/json/__pycache__/provider.cpython-312.pyc create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/flask/json/__pycache__/tag.cpython-312.pyc create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/flask/json/provider.py create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/flask/json/tag.py create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/flask/logging.py create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/flask/py.typed create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/flask/sansio/README.md create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/flask/sansio/__pycache__/app.cpython-312.pyc create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/flask/sansio/__pycache__/blueprints.cpython-312.pyc create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/flask/sansio/__pycache__/scaffold.cpython-312.pyc create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/flask/sansio/app.py create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/flask/sansio/blueprints.py create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/flask/sansio/scaffold.py create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/flask/sessions.py create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/flask/signals.py create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/flask/templating.py create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/flask/testing.py create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/flask/typing.py create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/flask/views.py create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/flask/wrappers.py create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/flask_session-0.8.0.dist-info/INSTALLER create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/flask_session-0.8.0.dist-info/LICENSE.rst create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/flask_session-0.8.0.dist-info/METADATA create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/flask_session-0.8.0.dist-info/RECORD create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/flask_session-0.8.0.dist-info/REQUESTED create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/flask_session-0.8.0.dist-info/WHEEL create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/flask_session/__init__.py create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/flask_session/__pycache__/__init__.cpython-312.pyc create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/flask_session/__pycache__/_utils.cpython-312.pyc create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/flask_session/__pycache__/base.cpython-312.pyc create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/flask_session/__pycache__/defaults.cpython-312.pyc create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/flask_session/_utils.py create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/flask_session/base.py create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/flask_session/cachelib/__init__.py create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/flask_session/cachelib/__pycache__/__init__.cpython-312.pyc create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/flask_session/cachelib/__pycache__/cachelib.cpython-312.pyc create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/flask_session/cachelib/cachelib.py create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/flask_session/defaults.py create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/flask_session/dynamodb/__init__.py create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/flask_session/dynamodb/__pycache__/__init__.cpython-312.pyc create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/flask_session/dynamodb/__pycache__/dynamodb.cpython-312.pyc create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/flask_session/dynamodb/dynamodb.py create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/flask_session/filesystem/__init__.py create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/flask_session/filesystem/__pycache__/__init__.cpython-312.pyc create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/flask_session/filesystem/__pycache__/filesystem.cpython-312.pyc create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/flask_session/filesystem/filesystem.py create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/flask_session/memcached/__init__.py create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/flask_session/memcached/__pycache__/__init__.cpython-312.pyc create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/flask_session/memcached/__pycache__/memcached.cpython-312.pyc create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/flask_session/memcached/memcached.py create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/flask_session/mongodb/__init__.py create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/flask_session/mongodb/__pycache__/__init__.cpython-312.pyc create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/flask_session/mongodb/__pycache__/mongodb.cpython-312.pyc create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/flask_session/mongodb/mongodb.py create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/flask_session/redis/__init__.py create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/flask_session/redis/__pycache__/__init__.cpython-312.pyc create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/flask_session/redis/__pycache__/redis.cpython-312.pyc create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/flask_session/redis/redis.py create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/flask_session/sqlalchemy/__init__.py create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/flask_session/sqlalchemy/__pycache__/__init__.cpython-312.pyc create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/flask_session/sqlalchemy/__pycache__/sqlalchemy.cpython-312.pyc create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/flask_session/sqlalchemy/sqlalchemy.py create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/greenlet-3.1.1.dist-info/AUTHORS create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/greenlet-3.1.1.dist-info/INSTALLER create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/greenlet-3.1.1.dist-info/LICENSE create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/greenlet-3.1.1.dist-info/LICENSE.PSF create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/greenlet-3.1.1.dist-info/METADATA create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/greenlet-3.1.1.dist-info/RECORD create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/greenlet-3.1.1.dist-info/WHEEL create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/greenlet-3.1.1.dist-info/top_level.txt create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/greenlet/CObjects.cpp create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/greenlet/PyGreenlet.cpp create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/greenlet/PyGreenlet.hpp create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/greenlet/PyGreenletUnswitchable.cpp create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/greenlet/PyModule.cpp create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/greenlet/TBrokenGreenlet.cpp create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/greenlet/TExceptionState.cpp create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/greenlet/TGreenlet.cpp create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/greenlet/TGreenlet.hpp create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/greenlet/TGreenletGlobals.cpp create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/greenlet/TMainGreenlet.cpp create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/greenlet/TPythonState.cpp create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/greenlet/TStackState.cpp create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/greenlet/TThreadState.hpp create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/greenlet/TThreadStateCreator.hpp create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/greenlet/TThreadStateDestroy.cpp create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/greenlet/TUserGreenlet.cpp create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/greenlet/__init__.py create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/greenlet/__pycache__/__init__.cpython-312.pyc create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/greenlet/_greenlet.cpython-312-x86_64-linux-gnu.so create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/greenlet/greenlet.cpp create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/greenlet/greenlet.h create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/greenlet/greenlet_allocator.hpp create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/greenlet/greenlet_compiler_compat.hpp create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/greenlet/greenlet_cpython_add_pending.hpp create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/greenlet/greenlet_cpython_compat.hpp create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/greenlet/greenlet_exceptions.hpp create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/greenlet/greenlet_internal.hpp create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/greenlet/greenlet_refs.hpp create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/greenlet/greenlet_slp_switch.hpp create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/greenlet/greenlet_thread_support.hpp create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/greenlet/platform/__init__.py create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/greenlet/platform/__pycache__/__init__.cpython-312.pyc create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/greenlet/platform/setup_switch_x64_masm.cmd create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/greenlet/platform/switch_aarch64_gcc.h create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/greenlet/platform/switch_alpha_unix.h create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/greenlet/platform/switch_amd64_unix.h create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/greenlet/platform/switch_arm32_gcc.h create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/greenlet/platform/switch_arm32_ios.h create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/greenlet/platform/switch_arm64_masm.asm create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/greenlet/platform/switch_arm64_masm.obj create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/greenlet/platform/switch_arm64_msvc.h create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/greenlet/platform/switch_csky_gcc.h create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/greenlet/platform/switch_loongarch64_linux.h create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/greenlet/platform/switch_m68k_gcc.h create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/greenlet/platform/switch_mips_unix.h create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/greenlet/platform/switch_ppc64_aix.h create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/greenlet/platform/switch_ppc64_linux.h create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/greenlet/platform/switch_ppc_aix.h create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/greenlet/platform/switch_ppc_linux.h create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/greenlet/platform/switch_ppc_macosx.h create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/greenlet/platform/switch_ppc_unix.h create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/greenlet/platform/switch_riscv_unix.h create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/greenlet/platform/switch_s390_unix.h create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/greenlet/platform/switch_sh_gcc.h create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/greenlet/platform/switch_sparc_sun_gcc.h create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/greenlet/platform/switch_x32_unix.h create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/greenlet/platform/switch_x64_masm.asm create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/greenlet/platform/switch_x64_masm.obj create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/greenlet/platform/switch_x64_msvc.h create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/greenlet/platform/switch_x86_msvc.h create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/greenlet/platform/switch_x86_unix.h create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/greenlet/slp_platformselect.h create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/greenlet/tests/__init__.py create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/greenlet/tests/__pycache__/__init__.cpython-312.pyc create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/greenlet/tests/__pycache__/fail_clearing_run_switches.cpython-312.pyc create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/greenlet/tests/__pycache__/fail_cpp_exception.cpython-312.pyc create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/greenlet/tests/__pycache__/fail_initialstub_already_started.cpython-312.pyc create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/greenlet/tests/__pycache__/fail_slp_switch.cpython-312.pyc create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/greenlet/tests/__pycache__/fail_switch_three_greenlets.cpython-312.pyc create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/greenlet/tests/__pycache__/fail_switch_three_greenlets2.cpython-312.pyc create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/greenlet/tests/__pycache__/fail_switch_two_greenlets.cpython-312.pyc create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/greenlet/tests/__pycache__/leakcheck.cpython-312.pyc create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/greenlet/tests/__pycache__/test_contextvars.cpython-312.pyc create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/greenlet/tests/__pycache__/test_cpp.cpython-312.pyc create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/greenlet/tests/__pycache__/test_extension_interface.cpython-312.pyc create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/greenlet/tests/__pycache__/test_gc.cpython-312.pyc create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/greenlet/tests/__pycache__/test_generator.cpython-312.pyc create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/greenlet/tests/__pycache__/test_generator_nested.cpython-312.pyc create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/greenlet/tests/__pycache__/test_greenlet.cpython-312.pyc create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/greenlet/tests/__pycache__/test_greenlet_trash.cpython-312.pyc create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/greenlet/tests/__pycache__/test_leaks.cpython-312.pyc create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/greenlet/tests/__pycache__/test_stack_saved.cpython-312.pyc create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/greenlet/tests/__pycache__/test_throw.cpython-312.pyc create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/greenlet/tests/__pycache__/test_tracing.cpython-312.pyc create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/greenlet/tests/__pycache__/test_version.cpython-312.pyc create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/greenlet/tests/__pycache__/test_weakref.cpython-312.pyc create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/greenlet/tests/_test_extension.c create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/greenlet/tests/_test_extension.cpython-312-x86_64-linux-gnu.so create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/greenlet/tests/_test_extension_cpp.cpp create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/greenlet/tests/_test_extension_cpp.cpython-312-x86_64-linux-gnu.so create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/greenlet/tests/fail_clearing_run_switches.py create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/greenlet/tests/fail_cpp_exception.py create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/greenlet/tests/fail_initialstub_already_started.py create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/greenlet/tests/fail_slp_switch.py create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/greenlet/tests/fail_switch_three_greenlets.py create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/greenlet/tests/fail_switch_three_greenlets2.py create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/greenlet/tests/fail_switch_two_greenlets.py create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/greenlet/tests/leakcheck.py create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/greenlet/tests/test_contextvars.py create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/greenlet/tests/test_cpp.py create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/greenlet/tests/test_extension_interface.py create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/greenlet/tests/test_gc.py create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/greenlet/tests/test_generator.py create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/greenlet/tests/test_generator_nested.py create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/greenlet/tests/test_greenlet.py create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/greenlet/tests/test_greenlet_trash.py create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/greenlet/tests/test_leaks.py create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/greenlet/tests/test_stack_saved.py create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/greenlet/tests/test_throw.py create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/greenlet/tests/test_tracing.py create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/greenlet/tests/test_version.py create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/greenlet/tests/test_weakref.py create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/idna-3.10.dist-info/INSTALLER create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/idna-3.10.dist-info/LICENSE.md create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/idna-3.10.dist-info/METADATA create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/idna-3.10.dist-info/RECORD create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/idna-3.10.dist-info/WHEEL create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/idna/__init__.py create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/idna/__pycache__/__init__.cpython-312.pyc create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/idna/__pycache__/codec.cpython-312.pyc create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/idna/__pycache__/compat.cpython-312.pyc create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/idna/__pycache__/core.cpython-312.pyc create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/idna/__pycache__/idnadata.cpython-312.pyc create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/idna/__pycache__/intranges.cpython-312.pyc create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/idna/__pycache__/package_data.cpython-312.pyc create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/idna/__pycache__/uts46data.cpython-312.pyc create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/idna/codec.py create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/idna/compat.py create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/idna/core.py create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/idna/idnadata.py create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/idna/intranges.py create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/idna/package_data.py create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/idna/py.typed create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/idna/uts46data.py create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/itsdangerous-2.2.0.dist-info/INSTALLER create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/itsdangerous-2.2.0.dist-info/LICENSE.txt create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/itsdangerous-2.2.0.dist-info/METADATA create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/itsdangerous-2.2.0.dist-info/RECORD create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/itsdangerous-2.2.0.dist-info/WHEEL create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/itsdangerous/__init__.py create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/itsdangerous/__pycache__/__init__.cpython-312.pyc create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/itsdangerous/__pycache__/_json.cpython-312.pyc create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/itsdangerous/__pycache__/encoding.cpython-312.pyc create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/itsdangerous/__pycache__/exc.cpython-312.pyc create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/itsdangerous/__pycache__/serializer.cpython-312.pyc create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/itsdangerous/__pycache__/signer.cpython-312.pyc create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/itsdangerous/__pycache__/timed.cpython-312.pyc create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/itsdangerous/__pycache__/url_safe.cpython-312.pyc create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/itsdangerous/_json.py create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/itsdangerous/encoding.py create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/itsdangerous/exc.py create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/itsdangerous/py.typed create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/itsdangerous/serializer.py create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/itsdangerous/signer.py create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/itsdangerous/timed.py create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/itsdangerous/url_safe.py create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/jinja2-3.1.4.dist-info/INSTALLER create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/jinja2-3.1.4.dist-info/LICENSE.txt create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/jinja2-3.1.4.dist-info/METADATA create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/jinja2-3.1.4.dist-info/RECORD create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/jinja2-3.1.4.dist-info/WHEEL create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/jinja2-3.1.4.dist-info/entry_points.txt create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/jinja2/__init__.py create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/jinja2/__pycache__/__init__.cpython-312.pyc create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/jinja2/__pycache__/_identifier.cpython-312.pyc create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/jinja2/__pycache__/async_utils.cpython-312.pyc create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/jinja2/__pycache__/bccache.cpython-312.pyc create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/jinja2/__pycache__/compiler.cpython-312.pyc create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/jinja2/__pycache__/constants.cpython-312.pyc create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/jinja2/__pycache__/debug.cpython-312.pyc create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/jinja2/__pycache__/defaults.cpython-312.pyc create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/jinja2/__pycache__/environment.cpython-312.pyc create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/jinja2/__pycache__/exceptions.cpython-312.pyc create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/jinja2/__pycache__/ext.cpython-312.pyc create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/jinja2/__pycache__/filters.cpython-312.pyc create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/jinja2/__pycache__/idtracking.cpython-312.pyc create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/jinja2/__pycache__/lexer.cpython-312.pyc create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/jinja2/__pycache__/loaders.cpython-312.pyc create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/jinja2/__pycache__/meta.cpython-312.pyc create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/jinja2/__pycache__/nativetypes.cpython-312.pyc create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/jinja2/__pycache__/nodes.cpython-312.pyc create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/jinja2/__pycache__/optimizer.cpython-312.pyc create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/jinja2/__pycache__/parser.cpython-312.pyc create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/jinja2/__pycache__/runtime.cpython-312.pyc create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/jinja2/__pycache__/sandbox.cpython-312.pyc create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/jinja2/__pycache__/tests.cpython-312.pyc create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/jinja2/__pycache__/utils.cpython-312.pyc create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/jinja2/__pycache__/visitor.cpython-312.pyc create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/jinja2/_identifier.py create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/jinja2/async_utils.py create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/jinja2/bccache.py create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/jinja2/compiler.py create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/jinja2/constants.py create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/jinja2/debug.py create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/jinja2/defaults.py create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/jinja2/environment.py create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/jinja2/exceptions.py create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/jinja2/ext.py create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/jinja2/filters.py create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/jinja2/idtracking.py create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/jinja2/lexer.py create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/jinja2/loaders.py create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/jinja2/meta.py create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/jinja2/nativetypes.py create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/jinja2/nodes.py create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/jinja2/optimizer.py create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/jinja2/parser.py create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/jinja2/py.typed create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/jinja2/runtime.py create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/jinja2/sandbox.py create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/jinja2/tests.py create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/jinja2/utils.py create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/jinja2/visitor.py create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/markupsafe/__init__.py create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/markupsafe/__pycache__/__init__.cpython-312.pyc create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/markupsafe/__pycache__/_native.cpython-312.pyc create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/markupsafe/_native.py create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/markupsafe/_speedups.c create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/markupsafe/_speedups.cpython-312-x86_64-linux-gnu.so create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/markupsafe/_speedups.pyi create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/markupsafe/py.typed create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/msgspec-0.18.6.dist-info/INSTALLER create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/msgspec-0.18.6.dist-info/LICENSE create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/msgspec-0.18.6.dist-info/METADATA create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/msgspec-0.18.6.dist-info/RECORD create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/msgspec-0.18.6.dist-info/WHEEL create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/msgspec-0.18.6.dist-info/top_level.txt create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/msgspec/__init__.py create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/msgspec/__init__.pyi create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/msgspec/__pycache__/__init__.cpython-312.pyc create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/msgspec/__pycache__/_json_schema.cpython-312.pyc create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/msgspec/__pycache__/_utils.cpython-312.pyc create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/msgspec/__pycache__/_version.cpython-312.pyc create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/msgspec/__pycache__/inspect.cpython-312.pyc create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/msgspec/__pycache__/json.cpython-312.pyc create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/msgspec/__pycache__/msgpack.cpython-312.pyc create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/msgspec/__pycache__/structs.cpython-312.pyc create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/msgspec/__pycache__/toml.cpython-312.pyc create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/msgspec/__pycache__/yaml.cpython-312.pyc create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/msgspec/_core.cpython-312-x86_64-linux-gnu.so create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/msgspec/_json_schema.py create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/msgspec/_utils.py create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/msgspec/_version.py create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/msgspec/inspect.py create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/msgspec/json.py create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/msgspec/json.pyi create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/msgspec/msgpack.py create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/msgspec/msgpack.pyi create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/msgspec/py.typed create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/msgspec/structs.py create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/msgspec/structs.pyi create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/msgspec/toml.py create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/msgspec/yaml.py create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/packaging-24.2.dist-info/INSTALLER create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/packaging-24.2.dist-info/LICENSE create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/packaging-24.2.dist-info/LICENSE.APACHE create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/packaging-24.2.dist-info/LICENSE.BSD create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/packaging-24.2.dist-info/METADATA create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/packaging-24.2.dist-info/RECORD create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/packaging-24.2.dist-info/WHEEL create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/packaging/__init__.py create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/packaging/__pycache__/__init__.cpython-312.pyc create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/packaging/__pycache__/_elffile.cpython-312.pyc create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/packaging/__pycache__/_manylinux.cpython-312.pyc create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/packaging/__pycache__/_musllinux.cpython-312.pyc create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/packaging/__pycache__/_parser.cpython-312.pyc create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/packaging/__pycache__/_structures.cpython-312.pyc create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/packaging/__pycache__/_tokenizer.cpython-312.pyc create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/packaging/__pycache__/markers.cpython-312.pyc create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/packaging/__pycache__/metadata.cpython-312.pyc create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/packaging/__pycache__/requirements.cpython-312.pyc create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/packaging/__pycache__/specifiers.cpython-312.pyc create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/packaging/__pycache__/tags.cpython-312.pyc create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/packaging/__pycache__/utils.cpython-312.pyc create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/packaging/__pycache__/version.cpython-312.pyc create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/packaging/_elffile.py create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/packaging/_manylinux.py create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/packaging/_musllinux.py create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/packaging/_parser.py create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/packaging/_structures.py create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/packaging/_tokenizer.py create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/packaging/licenses/__init__.py create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/packaging/licenses/__pycache__/__init__.cpython-312.pyc create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/packaging/licenses/__pycache__/_spdx.cpython-312.pyc create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/packaging/licenses/_spdx.py create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/packaging/markers.py create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/packaging/metadata.py create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/packaging/py.typed create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/packaging/requirements.py create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/packaging/specifiers.py create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/packaging/tags.py create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/packaging/utils.py create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/packaging/version.py create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pip-24.3.1.dist-info/AUTHORS.txt create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pip-24.3.1.dist-info/INSTALLER create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pip-24.3.1.dist-info/LICENSE.txt create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pip-24.3.1.dist-info/METADATA create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pip-24.3.1.dist-info/RECORD create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pip-24.3.1.dist-info/REQUESTED create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pip-24.3.1.dist-info/WHEEL create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pip-24.3.1.dist-info/entry_points.txt create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pip-24.3.1.dist-info/top_level.txt create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pip/__init__.py create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pip/__main__.py create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pip/__pip-runner__.py create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pip/__pycache__/__init__.cpython-312.pyc create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pip/__pycache__/__main__.cpython-312.pyc create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pip/__pycache__/__pip-runner__.cpython-312.pyc create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pip/_internal/__init__.py create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pip/_internal/__pycache__/__init__.cpython-312.pyc create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pip/_internal/__pycache__/build_env.cpython-312.pyc create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pip/_internal/__pycache__/cache.cpython-312.pyc create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pip/_internal/__pycache__/configuration.cpython-312.pyc create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pip/_internal/__pycache__/exceptions.cpython-312.pyc create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pip/_internal/__pycache__/main.cpython-312.pyc create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pip/_internal/__pycache__/pyproject.cpython-312.pyc create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pip/_internal/__pycache__/self_outdated_check.cpython-312.pyc create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pip/_internal/__pycache__/wheel_builder.cpython-312.pyc create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pip/_internal/build_env.py create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pip/_internal/cache.py create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pip/_internal/cli/__init__.py create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pip/_internal/cli/__pycache__/__init__.cpython-312.pyc create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pip/_internal/cli/__pycache__/autocompletion.cpython-312.pyc create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pip/_internal/cli/__pycache__/base_command.cpython-312.pyc create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pip/_internal/cli/__pycache__/cmdoptions.cpython-312.pyc create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pip/_internal/cli/__pycache__/command_context.cpython-312.pyc create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pip/_internal/cli/__pycache__/index_command.cpython-312.pyc create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pip/_internal/cli/__pycache__/main.cpython-312.pyc create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pip/_internal/cli/__pycache__/main_parser.cpython-312.pyc create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pip/_internal/cli/__pycache__/parser.cpython-312.pyc create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pip/_internal/cli/__pycache__/progress_bars.cpython-312.pyc create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pip/_internal/cli/__pycache__/req_command.cpython-312.pyc create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pip/_internal/cli/__pycache__/spinners.cpython-312.pyc create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pip/_internal/cli/__pycache__/status_codes.cpython-312.pyc create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pip/_internal/cli/autocompletion.py create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pip/_internal/cli/base_command.py create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pip/_internal/cli/cmdoptions.py create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pip/_internal/cli/command_context.py create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pip/_internal/cli/index_command.py create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pip/_internal/cli/main.py create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pip/_internal/cli/main_parser.py create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pip/_internal/cli/parser.py create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pip/_internal/cli/progress_bars.py create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pip/_internal/cli/req_command.py create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pip/_internal/cli/spinners.py create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pip/_internal/cli/status_codes.py create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pip/_internal/commands/__init__.py create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pip/_internal/commands/__pycache__/__init__.cpython-312.pyc create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pip/_internal/commands/__pycache__/cache.cpython-312.pyc create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pip/_internal/commands/__pycache__/check.cpython-312.pyc create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pip/_internal/commands/__pycache__/completion.cpython-312.pyc create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pip/_internal/commands/__pycache__/configuration.cpython-312.pyc create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pip/_internal/commands/__pycache__/debug.cpython-312.pyc create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pip/_internal/commands/__pycache__/download.cpython-312.pyc create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pip/_internal/commands/__pycache__/freeze.cpython-312.pyc create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pip/_internal/commands/__pycache__/hash.cpython-312.pyc create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pip/_internal/commands/__pycache__/help.cpython-312.pyc create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pip/_internal/commands/__pycache__/index.cpython-312.pyc create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pip/_internal/commands/__pycache__/inspect.cpython-312.pyc create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pip/_internal/commands/__pycache__/install.cpython-312.pyc create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pip/_internal/commands/__pycache__/list.cpython-312.pyc create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pip/_internal/commands/__pycache__/search.cpython-312.pyc create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pip/_internal/commands/__pycache__/show.cpython-312.pyc create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pip/_internal/commands/__pycache__/uninstall.cpython-312.pyc create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pip/_internal/commands/__pycache__/wheel.cpython-312.pyc create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pip/_internal/commands/cache.py create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pip/_internal/commands/check.py create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pip/_internal/commands/completion.py create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pip/_internal/commands/configuration.py create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pip/_internal/commands/debug.py create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pip/_internal/commands/download.py create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pip/_internal/commands/freeze.py create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pip/_internal/commands/hash.py create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pip/_internal/commands/help.py create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pip/_internal/commands/index.py create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pip/_internal/commands/inspect.py create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pip/_internal/commands/install.py create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pip/_internal/commands/list.py create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pip/_internal/commands/search.py create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pip/_internal/commands/show.py create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pip/_internal/commands/uninstall.py create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pip/_internal/commands/wheel.py create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pip/_internal/configuration.py create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pip/_internal/distributions/__init__.py create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pip/_internal/distributions/__pycache__/__init__.cpython-312.pyc create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pip/_internal/distributions/__pycache__/base.cpython-312.pyc create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pip/_internal/distributions/__pycache__/installed.cpython-312.pyc create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pip/_internal/distributions/__pycache__/sdist.cpython-312.pyc create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pip/_internal/distributions/__pycache__/wheel.cpython-312.pyc create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pip/_internal/distributions/base.py create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pip/_internal/distributions/installed.py create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pip/_internal/distributions/sdist.py create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pip/_internal/distributions/wheel.py create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pip/_internal/exceptions.py create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pip/_internal/index/__init__.py create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pip/_internal/index/__pycache__/__init__.cpython-312.pyc create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pip/_internal/index/__pycache__/collector.cpython-312.pyc create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pip/_internal/index/__pycache__/package_finder.cpython-312.pyc create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pip/_internal/index/__pycache__/sources.cpython-312.pyc create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pip/_internal/index/collector.py create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pip/_internal/index/package_finder.py create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pip/_internal/index/sources.py create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pip/_internal/locations/__init__.py create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pip/_internal/locations/__pycache__/__init__.cpython-312.pyc create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pip/_internal/locations/__pycache__/_distutils.cpython-312.pyc create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pip/_internal/locations/__pycache__/_sysconfig.cpython-312.pyc create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pip/_internal/locations/__pycache__/base.cpython-312.pyc create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pip/_internal/locations/_distutils.py create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pip/_internal/locations/_sysconfig.py create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pip/_internal/locations/base.py create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pip/_internal/main.py create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pip/_internal/metadata/__init__.py create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pip/_internal/metadata/__pycache__/__init__.cpython-312.pyc create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pip/_internal/metadata/__pycache__/_json.cpython-312.pyc create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pip/_internal/metadata/__pycache__/base.cpython-312.pyc create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pip/_internal/metadata/__pycache__/pkg_resources.cpython-312.pyc create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pip/_internal/metadata/_json.py create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pip/_internal/metadata/base.py create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pip/_internal/metadata/importlib/__init__.py create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pip/_internal/metadata/importlib/__pycache__/__init__.cpython-312.pyc create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pip/_internal/metadata/importlib/__pycache__/_compat.cpython-312.pyc create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pip/_internal/metadata/importlib/__pycache__/_dists.cpython-312.pyc create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pip/_internal/metadata/importlib/__pycache__/_envs.cpython-312.pyc create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pip/_internal/metadata/importlib/_compat.py create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pip/_internal/metadata/importlib/_dists.py create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pip/_internal/metadata/importlib/_envs.py create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pip/_internal/metadata/pkg_resources.py create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pip/_internal/models/__init__.py create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pip/_internal/models/__pycache__/__init__.cpython-312.pyc create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pip/_internal/models/__pycache__/candidate.cpython-312.pyc create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pip/_internal/models/__pycache__/direct_url.cpython-312.pyc create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pip/_internal/models/__pycache__/format_control.cpython-312.pyc create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pip/_internal/models/__pycache__/index.cpython-312.pyc create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pip/_internal/models/__pycache__/installation_report.cpython-312.pyc create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pip/_internal/models/__pycache__/link.cpython-312.pyc create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pip/_internal/models/__pycache__/scheme.cpython-312.pyc create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pip/_internal/models/__pycache__/search_scope.cpython-312.pyc create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pip/_internal/models/__pycache__/selection_prefs.cpython-312.pyc create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pip/_internal/models/__pycache__/target_python.cpython-312.pyc create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pip/_internal/models/__pycache__/wheel.cpython-312.pyc create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pip/_internal/models/candidate.py create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pip/_internal/models/direct_url.py create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pip/_internal/models/format_control.py create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pip/_internal/models/index.py create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pip/_internal/models/installation_report.py create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pip/_internal/models/link.py create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pip/_internal/models/scheme.py create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pip/_internal/models/search_scope.py create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pip/_internal/models/selection_prefs.py create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pip/_internal/models/target_python.py create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pip/_internal/models/wheel.py create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pip/_internal/network/__init__.py create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pip/_internal/network/__pycache__/__init__.cpython-312.pyc create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pip/_internal/network/__pycache__/auth.cpython-312.pyc create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pip/_internal/network/__pycache__/cache.cpython-312.pyc create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pip/_internal/network/__pycache__/download.cpython-312.pyc create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pip/_internal/network/__pycache__/lazy_wheel.cpython-312.pyc create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pip/_internal/network/__pycache__/session.cpython-312.pyc create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pip/_internal/network/__pycache__/utils.cpython-312.pyc create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pip/_internal/network/__pycache__/xmlrpc.cpython-312.pyc create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pip/_internal/network/auth.py create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pip/_internal/network/cache.py create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pip/_internal/network/download.py create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pip/_internal/network/lazy_wheel.py create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pip/_internal/network/session.py create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pip/_internal/network/utils.py create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pip/_internal/network/xmlrpc.py create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pip/_internal/operations/__init__.py create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pip/_internal/operations/__pycache__/__init__.cpython-312.pyc create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pip/_internal/operations/__pycache__/check.cpython-312.pyc create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pip/_internal/operations/__pycache__/freeze.cpython-312.pyc create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pip/_internal/operations/__pycache__/prepare.cpython-312.pyc create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pip/_internal/operations/build/__init__.py create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pip/_internal/operations/build/__pycache__/__init__.cpython-312.pyc create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pip/_internal/operations/build/__pycache__/build_tracker.cpython-312.pyc create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pip/_internal/operations/build/__pycache__/metadata.cpython-312.pyc create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pip/_internal/operations/build/__pycache__/metadata_editable.cpython-312.pyc create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pip/_internal/operations/build/__pycache__/metadata_legacy.cpython-312.pyc create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pip/_internal/operations/build/__pycache__/wheel.cpython-312.pyc create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pip/_internal/operations/build/__pycache__/wheel_editable.cpython-312.pyc create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pip/_internal/operations/build/__pycache__/wheel_legacy.cpython-312.pyc create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pip/_internal/operations/build/build_tracker.py create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pip/_internal/operations/build/metadata.py create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pip/_internal/operations/build/metadata_editable.py create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pip/_internal/operations/build/metadata_legacy.py create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pip/_internal/operations/build/wheel.py create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pip/_internal/operations/build/wheel_editable.py create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pip/_internal/operations/build/wheel_legacy.py create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pip/_internal/operations/check.py create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pip/_internal/operations/freeze.py create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pip/_internal/operations/install/__init__.py create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pip/_internal/operations/install/__pycache__/__init__.cpython-312.pyc create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pip/_internal/operations/install/__pycache__/editable_legacy.cpython-312.pyc create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pip/_internal/operations/install/__pycache__/wheel.cpython-312.pyc create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pip/_internal/operations/install/editable_legacy.py create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pip/_internal/operations/install/wheel.py create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pip/_internal/operations/prepare.py create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pip/_internal/pyproject.py create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pip/_internal/req/__init__.py create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pip/_internal/req/__pycache__/__init__.cpython-312.pyc create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pip/_internal/req/__pycache__/constructors.cpython-312.pyc create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pip/_internal/req/__pycache__/req_file.cpython-312.pyc create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pip/_internal/req/__pycache__/req_install.cpython-312.pyc create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pip/_internal/req/__pycache__/req_set.cpython-312.pyc create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pip/_internal/req/__pycache__/req_uninstall.cpython-312.pyc create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pip/_internal/req/constructors.py create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pip/_internal/req/req_file.py create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pip/_internal/req/req_install.py create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pip/_internal/req/req_set.py create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pip/_internal/req/req_uninstall.py create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pip/_internal/resolution/__init__.py create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pip/_internal/resolution/__pycache__/__init__.cpython-312.pyc create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pip/_internal/resolution/__pycache__/base.cpython-312.pyc create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pip/_internal/resolution/base.py create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pip/_internal/resolution/legacy/__init__.py create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pip/_internal/resolution/legacy/__pycache__/__init__.cpython-312.pyc create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pip/_internal/resolution/legacy/__pycache__/resolver.cpython-312.pyc create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pip/_internal/resolution/legacy/resolver.py create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pip/_internal/resolution/resolvelib/__init__.py create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pip/_internal/resolution/resolvelib/__pycache__/__init__.cpython-312.pyc create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pip/_internal/resolution/resolvelib/__pycache__/base.cpython-312.pyc create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pip/_internal/resolution/resolvelib/__pycache__/candidates.cpython-312.pyc create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pip/_internal/resolution/resolvelib/__pycache__/factory.cpython-312.pyc create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pip/_internal/resolution/resolvelib/__pycache__/found_candidates.cpython-312.pyc create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pip/_internal/resolution/resolvelib/__pycache__/provider.cpython-312.pyc create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pip/_internal/resolution/resolvelib/__pycache__/reporter.cpython-312.pyc create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pip/_internal/resolution/resolvelib/__pycache__/requirements.cpython-312.pyc create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pip/_internal/resolution/resolvelib/__pycache__/resolver.cpython-312.pyc create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pip/_internal/resolution/resolvelib/base.py create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pip/_internal/resolution/resolvelib/candidates.py create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pip/_internal/resolution/resolvelib/factory.py create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pip/_internal/resolution/resolvelib/found_candidates.py create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pip/_internal/resolution/resolvelib/provider.py create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pip/_internal/resolution/resolvelib/reporter.py create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pip/_internal/resolution/resolvelib/requirements.py create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pip/_internal/resolution/resolvelib/resolver.py create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pip/_internal/self_outdated_check.py create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pip/_internal/utils/__init__.py create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pip/_internal/utils/__pycache__/__init__.cpython-312.pyc create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pip/_internal/utils/__pycache__/_jaraco_text.cpython-312.pyc create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pip/_internal/utils/__pycache__/_log.cpython-312.pyc create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pip/_internal/utils/__pycache__/appdirs.cpython-312.pyc create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pip/_internal/utils/__pycache__/compat.cpython-312.pyc create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pip/_internal/utils/__pycache__/compatibility_tags.cpython-312.pyc create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pip/_internal/utils/__pycache__/datetime.cpython-312.pyc create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pip/_internal/utils/__pycache__/deprecation.cpython-312.pyc create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pip/_internal/utils/__pycache__/direct_url_helpers.cpython-312.pyc create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pip/_internal/utils/__pycache__/egg_link.cpython-312.pyc create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pip/_internal/utils/__pycache__/encoding.cpython-312.pyc create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pip/_internal/utils/__pycache__/entrypoints.cpython-312.pyc create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pip/_internal/utils/__pycache__/filesystem.cpython-312.pyc create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pip/_internal/utils/__pycache__/filetypes.cpython-312.pyc create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pip/_internal/utils/__pycache__/glibc.cpython-312.pyc create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pip/_internal/utils/__pycache__/hashes.cpython-312.pyc create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pip/_internal/utils/__pycache__/logging.cpython-312.pyc create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pip/_internal/utils/__pycache__/misc.cpython-312.pyc create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pip/_internal/utils/__pycache__/packaging.cpython-312.pyc create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pip/_internal/utils/__pycache__/retry.cpython-312.pyc create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pip/_internal/utils/__pycache__/setuptools_build.cpython-312.pyc create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pip/_internal/utils/__pycache__/subprocess.cpython-312.pyc create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pip/_internal/utils/__pycache__/temp_dir.cpython-312.pyc create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pip/_internal/utils/__pycache__/unpacking.cpython-312.pyc create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pip/_internal/utils/__pycache__/urls.cpython-312.pyc create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pip/_internal/utils/__pycache__/virtualenv.cpython-312.pyc create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pip/_internal/utils/__pycache__/wheel.cpython-312.pyc create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pip/_internal/utils/_jaraco_text.py create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pip/_internal/utils/_log.py create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pip/_internal/utils/appdirs.py create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pip/_internal/utils/compat.py create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pip/_internal/utils/compatibility_tags.py create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pip/_internal/utils/datetime.py create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pip/_internal/utils/deprecation.py create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pip/_internal/utils/direct_url_helpers.py create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pip/_internal/utils/egg_link.py create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pip/_internal/utils/encoding.py create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pip/_internal/utils/entrypoints.py create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pip/_internal/utils/filesystem.py create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pip/_internal/utils/filetypes.py create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pip/_internal/utils/glibc.py create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pip/_internal/utils/hashes.py create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pip/_internal/utils/logging.py create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pip/_internal/utils/misc.py create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pip/_internal/utils/packaging.py create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pip/_internal/utils/retry.py create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pip/_internal/utils/setuptools_build.py create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pip/_internal/utils/subprocess.py create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pip/_internal/utils/temp_dir.py create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pip/_internal/utils/unpacking.py create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pip/_internal/utils/urls.py create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pip/_internal/utils/virtualenv.py create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pip/_internal/utils/wheel.py create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pip/_internal/vcs/__init__.py create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pip/_internal/vcs/__pycache__/__init__.cpython-312.pyc create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pip/_internal/vcs/__pycache__/bazaar.cpython-312.pyc create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pip/_internal/vcs/__pycache__/git.cpython-312.pyc create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pip/_internal/vcs/__pycache__/mercurial.cpython-312.pyc create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pip/_internal/vcs/__pycache__/subversion.cpython-312.pyc create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pip/_internal/vcs/__pycache__/versioncontrol.cpython-312.pyc create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pip/_internal/vcs/bazaar.py create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pip/_internal/vcs/git.py create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pip/_internal/vcs/mercurial.py create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pip/_internal/vcs/subversion.py create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pip/_internal/vcs/versioncontrol.py create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pip/_internal/wheel_builder.py create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pip/_vendor/__init__.py create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pip/_vendor/__pycache__/__init__.cpython-312.pyc create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pip/_vendor/__pycache__/typing_extensions.cpython-312.pyc create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pip/_vendor/cachecontrol/__init__.py create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pip/_vendor/cachecontrol/__pycache__/__init__.cpython-312.pyc create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pip/_vendor/cachecontrol/__pycache__/_cmd.cpython-312.pyc create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pip/_vendor/cachecontrol/__pycache__/adapter.cpython-312.pyc create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pip/_vendor/cachecontrol/__pycache__/cache.cpython-312.pyc create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pip/_vendor/cachecontrol/__pycache__/controller.cpython-312.pyc create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pip/_vendor/cachecontrol/__pycache__/filewrapper.cpython-312.pyc create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pip/_vendor/cachecontrol/__pycache__/heuristics.cpython-312.pyc create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pip/_vendor/cachecontrol/__pycache__/serialize.cpython-312.pyc create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pip/_vendor/cachecontrol/__pycache__/wrapper.cpython-312.pyc create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pip/_vendor/cachecontrol/_cmd.py create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pip/_vendor/cachecontrol/adapter.py create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pip/_vendor/cachecontrol/cache.py create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pip/_vendor/cachecontrol/caches/__init__.py create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pip/_vendor/cachecontrol/caches/__pycache__/__init__.cpython-312.pyc create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pip/_vendor/cachecontrol/caches/__pycache__/file_cache.cpython-312.pyc create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pip/_vendor/cachecontrol/caches/__pycache__/redis_cache.cpython-312.pyc create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pip/_vendor/cachecontrol/caches/file_cache.py create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pip/_vendor/cachecontrol/caches/redis_cache.py create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pip/_vendor/cachecontrol/controller.py create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pip/_vendor/cachecontrol/filewrapper.py create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pip/_vendor/cachecontrol/heuristics.py create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pip/_vendor/cachecontrol/py.typed create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pip/_vendor/cachecontrol/serialize.py create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pip/_vendor/cachecontrol/wrapper.py create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pip/_vendor/certifi/__init__.py create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pip/_vendor/certifi/__main__.py create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pip/_vendor/certifi/__pycache__/__init__.cpython-312.pyc create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pip/_vendor/certifi/__pycache__/__main__.cpython-312.pyc create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pip/_vendor/certifi/__pycache__/core.cpython-312.pyc create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pip/_vendor/certifi/cacert.pem create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pip/_vendor/certifi/core.py create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pip/_vendor/certifi/py.typed create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pip/_vendor/distlib/__init__.py create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pip/_vendor/distlib/__pycache__/__init__.cpython-312.pyc create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pip/_vendor/distlib/__pycache__/compat.cpython-312.pyc create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pip/_vendor/distlib/__pycache__/database.cpython-312.pyc create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pip/_vendor/distlib/__pycache__/index.cpython-312.pyc create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pip/_vendor/distlib/__pycache__/locators.cpython-312.pyc create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pip/_vendor/distlib/__pycache__/manifest.cpython-312.pyc create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pip/_vendor/distlib/__pycache__/markers.cpython-312.pyc create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pip/_vendor/distlib/__pycache__/metadata.cpython-312.pyc create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pip/_vendor/distlib/__pycache__/resources.cpython-312.pyc create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pip/_vendor/distlib/__pycache__/scripts.cpython-312.pyc create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pip/_vendor/distlib/__pycache__/util.cpython-312.pyc create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pip/_vendor/distlib/__pycache__/version.cpython-312.pyc create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pip/_vendor/distlib/__pycache__/wheel.cpython-312.pyc create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pip/_vendor/distlib/compat.py create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pip/_vendor/distlib/database.py create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pip/_vendor/distlib/index.py create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pip/_vendor/distlib/locators.py create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pip/_vendor/distlib/manifest.py create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pip/_vendor/distlib/markers.py create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pip/_vendor/distlib/metadata.py create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pip/_vendor/distlib/resources.py create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pip/_vendor/distlib/scripts.py create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pip/_vendor/distlib/t32.exe create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pip/_vendor/distlib/t64-arm.exe create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pip/_vendor/distlib/t64.exe create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pip/_vendor/distlib/util.py create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pip/_vendor/distlib/version.py create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pip/_vendor/distlib/w32.exe create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pip/_vendor/distlib/w64-arm.exe create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pip/_vendor/distlib/w64.exe create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pip/_vendor/distlib/wheel.py create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pip/_vendor/distro/__init__.py create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pip/_vendor/distro/__main__.py create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pip/_vendor/distro/__pycache__/__init__.cpython-312.pyc create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pip/_vendor/distro/__pycache__/__main__.cpython-312.pyc create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pip/_vendor/distro/__pycache__/distro.cpython-312.pyc create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pip/_vendor/distro/distro.py create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pip/_vendor/distro/py.typed create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pip/_vendor/idna/__init__.py create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pip/_vendor/idna/__pycache__/__init__.cpython-312.pyc create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pip/_vendor/idna/__pycache__/codec.cpython-312.pyc create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pip/_vendor/idna/__pycache__/compat.cpython-312.pyc create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pip/_vendor/idna/__pycache__/core.cpython-312.pyc create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pip/_vendor/idna/__pycache__/idnadata.cpython-312.pyc create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pip/_vendor/idna/__pycache__/intranges.cpython-312.pyc create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pip/_vendor/idna/__pycache__/package_data.cpython-312.pyc create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pip/_vendor/idna/__pycache__/uts46data.cpython-312.pyc create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pip/_vendor/idna/codec.py create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pip/_vendor/idna/compat.py create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pip/_vendor/idna/core.py create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pip/_vendor/idna/idnadata.py create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pip/_vendor/idna/intranges.py create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pip/_vendor/idna/package_data.py create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pip/_vendor/idna/py.typed create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pip/_vendor/idna/uts46data.py create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pip/_vendor/msgpack/__init__.py create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pip/_vendor/msgpack/__pycache__/__init__.cpython-312.pyc create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pip/_vendor/msgpack/__pycache__/exceptions.cpython-312.pyc create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pip/_vendor/msgpack/__pycache__/ext.cpython-312.pyc create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pip/_vendor/msgpack/__pycache__/fallback.cpython-312.pyc create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pip/_vendor/msgpack/exceptions.py create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pip/_vendor/msgpack/ext.py create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pip/_vendor/msgpack/fallback.py create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pip/_vendor/packaging/__init__.py create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pip/_vendor/packaging/__pycache__/__init__.cpython-312.pyc create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pip/_vendor/packaging/__pycache__/_elffile.cpython-312.pyc create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pip/_vendor/packaging/__pycache__/_manylinux.cpython-312.pyc create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pip/_vendor/packaging/__pycache__/_musllinux.cpython-312.pyc create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pip/_vendor/packaging/__pycache__/_parser.cpython-312.pyc create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pip/_vendor/packaging/__pycache__/_structures.cpython-312.pyc create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pip/_vendor/packaging/__pycache__/_tokenizer.cpython-312.pyc create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pip/_vendor/packaging/__pycache__/markers.cpython-312.pyc create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pip/_vendor/packaging/__pycache__/metadata.cpython-312.pyc create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pip/_vendor/packaging/__pycache__/requirements.cpython-312.pyc create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pip/_vendor/packaging/__pycache__/specifiers.cpython-312.pyc create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pip/_vendor/packaging/__pycache__/tags.cpython-312.pyc create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pip/_vendor/packaging/__pycache__/utils.cpython-312.pyc create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pip/_vendor/packaging/__pycache__/version.cpython-312.pyc create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pip/_vendor/packaging/_elffile.py create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pip/_vendor/packaging/_manylinux.py create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pip/_vendor/packaging/_musllinux.py create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pip/_vendor/packaging/_parser.py create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pip/_vendor/packaging/_structures.py create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pip/_vendor/packaging/_tokenizer.py create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pip/_vendor/packaging/markers.py create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pip/_vendor/packaging/metadata.py create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pip/_vendor/packaging/py.typed create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pip/_vendor/packaging/requirements.py create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pip/_vendor/packaging/specifiers.py create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pip/_vendor/packaging/tags.py create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pip/_vendor/packaging/utils.py create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pip/_vendor/packaging/version.py create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pip/_vendor/pkg_resources/__init__.py create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pip/_vendor/pkg_resources/__pycache__/__init__.cpython-312.pyc create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pip/_vendor/platformdirs/__init__.py create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pip/_vendor/platformdirs/__main__.py create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pip/_vendor/platformdirs/__pycache__/__init__.cpython-312.pyc create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pip/_vendor/platformdirs/__pycache__/__main__.cpython-312.pyc create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pip/_vendor/platformdirs/__pycache__/android.cpython-312.pyc create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pip/_vendor/platformdirs/__pycache__/api.cpython-312.pyc create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pip/_vendor/platformdirs/__pycache__/macos.cpython-312.pyc create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pip/_vendor/platformdirs/__pycache__/unix.cpython-312.pyc create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pip/_vendor/platformdirs/__pycache__/version.cpython-312.pyc create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pip/_vendor/platformdirs/__pycache__/windows.cpython-312.pyc create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pip/_vendor/platformdirs/android.py create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pip/_vendor/platformdirs/api.py create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pip/_vendor/platformdirs/macos.py create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pip/_vendor/platformdirs/py.typed create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pip/_vendor/platformdirs/unix.py create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pip/_vendor/platformdirs/version.py create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pip/_vendor/platformdirs/windows.py create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pip/_vendor/pygments/__init__.py create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pip/_vendor/pygments/__main__.py create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pip/_vendor/pygments/__pycache__/__init__.cpython-312.pyc create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pip/_vendor/pygments/__pycache__/__main__.cpython-312.pyc create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pip/_vendor/pygments/__pycache__/cmdline.cpython-312.pyc create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pip/_vendor/pygments/__pycache__/console.cpython-312.pyc create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pip/_vendor/pygments/__pycache__/filter.cpython-312.pyc create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pip/_vendor/pygments/__pycache__/formatter.cpython-312.pyc create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pip/_vendor/pygments/__pycache__/lexer.cpython-312.pyc create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pip/_vendor/pygments/__pycache__/modeline.cpython-312.pyc create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pip/_vendor/pygments/__pycache__/plugin.cpython-312.pyc create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pip/_vendor/pygments/__pycache__/regexopt.cpython-312.pyc create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pip/_vendor/pygments/__pycache__/scanner.cpython-312.pyc create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pip/_vendor/pygments/__pycache__/sphinxext.cpython-312.pyc create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pip/_vendor/pygments/__pycache__/style.cpython-312.pyc create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pip/_vendor/pygments/__pycache__/token.cpython-312.pyc create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pip/_vendor/pygments/__pycache__/unistring.cpython-312.pyc create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pip/_vendor/pygments/__pycache__/util.cpython-312.pyc create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pip/_vendor/pygments/cmdline.py create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pip/_vendor/pygments/console.py create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pip/_vendor/pygments/filter.py create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pip/_vendor/pygments/filters/__init__.py create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pip/_vendor/pygments/filters/__pycache__/__init__.cpython-312.pyc create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pip/_vendor/pygments/formatter.py create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pip/_vendor/pygments/formatters/__init__.py create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pip/_vendor/pygments/formatters/__pycache__/__init__.cpython-312.pyc create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pip/_vendor/pygments/formatters/__pycache__/_mapping.cpython-312.pyc create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pip/_vendor/pygments/formatters/__pycache__/bbcode.cpython-312.pyc create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pip/_vendor/pygments/formatters/__pycache__/groff.cpython-312.pyc create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pip/_vendor/pygments/formatters/__pycache__/html.cpython-312.pyc create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pip/_vendor/pygments/formatters/__pycache__/img.cpython-312.pyc create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pip/_vendor/pygments/formatters/__pycache__/irc.cpython-312.pyc create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pip/_vendor/pygments/formatters/__pycache__/latex.cpython-312.pyc create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pip/_vendor/pygments/formatters/__pycache__/other.cpython-312.pyc create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pip/_vendor/pygments/formatters/__pycache__/pangomarkup.cpython-312.pyc create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pip/_vendor/pygments/formatters/__pycache__/rtf.cpython-312.pyc create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pip/_vendor/pygments/formatters/__pycache__/svg.cpython-312.pyc create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pip/_vendor/pygments/formatters/__pycache__/terminal.cpython-312.pyc create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pip/_vendor/pygments/formatters/__pycache__/terminal256.cpython-312.pyc create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pip/_vendor/pygments/formatters/_mapping.py create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pip/_vendor/pygments/formatters/bbcode.py create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pip/_vendor/pygments/formatters/groff.py create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pip/_vendor/pygments/formatters/html.py create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pip/_vendor/pygments/formatters/img.py create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pip/_vendor/pygments/formatters/irc.py create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pip/_vendor/pygments/formatters/latex.py create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pip/_vendor/pygments/formatters/other.py create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pip/_vendor/pygments/formatters/pangomarkup.py create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pip/_vendor/pygments/formatters/rtf.py create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pip/_vendor/pygments/formatters/svg.py create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pip/_vendor/pygments/formatters/terminal.py create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pip/_vendor/pygments/formatters/terminal256.py create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pip/_vendor/pygments/lexer.py create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pip/_vendor/pygments/lexers/__init__.py create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pip/_vendor/pygments/lexers/__pycache__/__init__.cpython-312.pyc create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pip/_vendor/pygments/lexers/__pycache__/_mapping.cpython-312.pyc create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pip/_vendor/pygments/lexers/__pycache__/python.cpython-312.pyc create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pip/_vendor/pygments/lexers/_mapping.py create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pip/_vendor/pygments/lexers/python.py create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pip/_vendor/pygments/modeline.py create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pip/_vendor/pygments/plugin.py create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pip/_vendor/pygments/regexopt.py create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pip/_vendor/pygments/scanner.py create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pip/_vendor/pygments/sphinxext.py create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pip/_vendor/pygments/style.py create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pip/_vendor/pygments/styles/__init__.py create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pip/_vendor/pygments/styles/__pycache__/__init__.cpython-312.pyc create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pip/_vendor/pygments/styles/__pycache__/_mapping.cpython-312.pyc create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pip/_vendor/pygments/styles/_mapping.py create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pip/_vendor/pygments/token.py create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pip/_vendor/pygments/unistring.py create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pip/_vendor/pygments/util.py create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pip/_vendor/pyproject_hooks/__init__.py create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pip/_vendor/pyproject_hooks/__pycache__/__init__.cpython-312.pyc create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pip/_vendor/pyproject_hooks/__pycache__/_compat.cpython-312.pyc create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pip/_vendor/pyproject_hooks/__pycache__/_impl.cpython-312.pyc create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pip/_vendor/pyproject_hooks/_compat.py create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pip/_vendor/pyproject_hooks/_impl.py create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pip/_vendor/pyproject_hooks/_in_process/__init__.py create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pip/_vendor/pyproject_hooks/_in_process/__pycache__/__init__.cpython-312.pyc create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pip/_vendor/pyproject_hooks/_in_process/__pycache__/_in_process.cpython-312.pyc create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pip/_vendor/pyproject_hooks/_in_process/_in_process.py create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pip/_vendor/requests/__init__.py create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pip/_vendor/requests/__pycache__/__init__.cpython-312.pyc create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pip/_vendor/requests/__pycache__/__version__.cpython-312.pyc create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pip/_vendor/requests/__pycache__/_internal_utils.cpython-312.pyc create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pip/_vendor/requests/__pycache__/adapters.cpython-312.pyc create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pip/_vendor/requests/__pycache__/api.cpython-312.pyc create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pip/_vendor/requests/__pycache__/auth.cpython-312.pyc create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pip/_vendor/requests/__pycache__/certs.cpython-312.pyc create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pip/_vendor/requests/__pycache__/compat.cpython-312.pyc create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pip/_vendor/requests/__pycache__/cookies.cpython-312.pyc create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pip/_vendor/requests/__pycache__/exceptions.cpython-312.pyc create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pip/_vendor/requests/__pycache__/help.cpython-312.pyc create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pip/_vendor/requests/__pycache__/hooks.cpython-312.pyc create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pip/_vendor/requests/__pycache__/models.cpython-312.pyc create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pip/_vendor/requests/__pycache__/packages.cpython-312.pyc create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pip/_vendor/requests/__pycache__/sessions.cpython-312.pyc create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pip/_vendor/requests/__pycache__/status_codes.cpython-312.pyc create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pip/_vendor/requests/__pycache__/structures.cpython-312.pyc create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pip/_vendor/requests/__pycache__/utils.cpython-312.pyc create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pip/_vendor/requests/__version__.py create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pip/_vendor/requests/_internal_utils.py create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pip/_vendor/requests/adapters.py create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pip/_vendor/requests/api.py create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pip/_vendor/requests/auth.py create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pip/_vendor/requests/certs.py create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pip/_vendor/requests/compat.py create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pip/_vendor/requests/cookies.py create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pip/_vendor/requests/exceptions.py create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pip/_vendor/requests/help.py create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pip/_vendor/requests/hooks.py create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pip/_vendor/requests/models.py create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pip/_vendor/requests/packages.py create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pip/_vendor/requests/sessions.py create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pip/_vendor/requests/status_codes.py create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pip/_vendor/requests/structures.py create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pip/_vendor/requests/utils.py create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pip/_vendor/resolvelib/__init__.py create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pip/_vendor/resolvelib/__pycache__/__init__.cpython-312.pyc create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pip/_vendor/resolvelib/__pycache__/providers.cpython-312.pyc create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pip/_vendor/resolvelib/__pycache__/reporters.cpython-312.pyc create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pip/_vendor/resolvelib/__pycache__/resolvers.cpython-312.pyc create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pip/_vendor/resolvelib/__pycache__/structs.cpython-312.pyc create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pip/_vendor/resolvelib/compat/__init__.py create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pip/_vendor/resolvelib/compat/__pycache__/__init__.cpython-312.pyc create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pip/_vendor/resolvelib/compat/__pycache__/collections_abc.cpython-312.pyc create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pip/_vendor/resolvelib/compat/collections_abc.py create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pip/_vendor/resolvelib/providers.py create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pip/_vendor/resolvelib/py.typed create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pip/_vendor/resolvelib/reporters.py create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pip/_vendor/resolvelib/resolvers.py create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pip/_vendor/resolvelib/structs.py create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pip/_vendor/rich/__init__.py create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pip/_vendor/rich/__main__.py create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pip/_vendor/rich/__pycache__/__init__.cpython-312.pyc create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pip/_vendor/rich/__pycache__/__main__.cpython-312.pyc create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pip/_vendor/rich/__pycache__/_cell_widths.cpython-312.pyc create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pip/_vendor/rich/__pycache__/_emoji_codes.cpython-312.pyc create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pip/_vendor/rich/__pycache__/_emoji_replace.cpython-312.pyc create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pip/_vendor/rich/__pycache__/_export_format.cpython-312.pyc create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pip/_vendor/rich/__pycache__/_extension.cpython-312.pyc create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pip/_vendor/rich/__pycache__/_fileno.cpython-312.pyc create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pip/_vendor/rich/__pycache__/_inspect.cpython-312.pyc create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pip/_vendor/rich/__pycache__/_log_render.cpython-312.pyc create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pip/_vendor/rich/__pycache__/_loop.cpython-312.pyc create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pip/_vendor/rich/__pycache__/_null_file.cpython-312.pyc create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pip/_vendor/rich/__pycache__/_palettes.cpython-312.pyc create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pip/_vendor/rich/__pycache__/_pick.cpython-312.pyc create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pip/_vendor/rich/__pycache__/_ratio.cpython-312.pyc create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pip/_vendor/rich/__pycache__/_spinners.cpython-312.pyc create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pip/_vendor/rich/__pycache__/_stack.cpython-312.pyc create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pip/_vendor/rich/__pycache__/_timer.cpython-312.pyc create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pip/_vendor/rich/__pycache__/_win32_console.cpython-312.pyc create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pip/_vendor/rich/__pycache__/_windows.cpython-312.pyc create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pip/_vendor/rich/__pycache__/_windows_renderer.cpython-312.pyc create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pip/_vendor/rich/__pycache__/_wrap.cpython-312.pyc create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pip/_vendor/rich/__pycache__/abc.cpython-312.pyc create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pip/_vendor/rich/__pycache__/align.cpython-312.pyc create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pip/_vendor/rich/__pycache__/ansi.cpython-312.pyc create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pip/_vendor/rich/__pycache__/bar.cpython-312.pyc create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pip/_vendor/rich/__pycache__/box.cpython-312.pyc create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pip/_vendor/rich/__pycache__/cells.cpython-312.pyc create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pip/_vendor/rich/__pycache__/color.cpython-312.pyc create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pip/_vendor/rich/__pycache__/color_triplet.cpython-312.pyc create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pip/_vendor/rich/__pycache__/columns.cpython-312.pyc create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pip/_vendor/rich/__pycache__/console.cpython-312.pyc create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pip/_vendor/rich/__pycache__/constrain.cpython-312.pyc create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pip/_vendor/rich/__pycache__/containers.cpython-312.pyc create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pip/_vendor/rich/__pycache__/control.cpython-312.pyc create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pip/_vendor/rich/__pycache__/default_styles.cpython-312.pyc create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pip/_vendor/rich/__pycache__/diagnose.cpython-312.pyc create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pip/_vendor/rich/__pycache__/emoji.cpython-312.pyc create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pip/_vendor/rich/__pycache__/errors.cpython-312.pyc create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pip/_vendor/rich/__pycache__/file_proxy.cpython-312.pyc create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pip/_vendor/rich/__pycache__/filesize.cpython-312.pyc create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pip/_vendor/rich/__pycache__/highlighter.cpython-312.pyc create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pip/_vendor/rich/__pycache__/json.cpython-312.pyc create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pip/_vendor/rich/__pycache__/jupyter.cpython-312.pyc create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pip/_vendor/rich/__pycache__/layout.cpython-312.pyc create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pip/_vendor/rich/__pycache__/live.cpython-312.pyc create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pip/_vendor/rich/__pycache__/live_render.cpython-312.pyc create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pip/_vendor/rich/__pycache__/logging.cpython-312.pyc create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pip/_vendor/rich/__pycache__/markup.cpython-312.pyc create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pip/_vendor/rich/__pycache__/measure.cpython-312.pyc create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pip/_vendor/rich/__pycache__/padding.cpython-312.pyc create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pip/_vendor/rich/__pycache__/pager.cpython-312.pyc create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pip/_vendor/rich/__pycache__/palette.cpython-312.pyc create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pip/_vendor/rich/__pycache__/panel.cpython-312.pyc create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pip/_vendor/rich/__pycache__/pretty.cpython-312.pyc create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pip/_vendor/rich/__pycache__/progress.cpython-312.pyc create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pip/_vendor/rich/__pycache__/progress_bar.cpython-312.pyc create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pip/_vendor/rich/__pycache__/prompt.cpython-312.pyc create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pip/_vendor/rich/__pycache__/protocol.cpython-312.pyc create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pip/_vendor/rich/__pycache__/region.cpython-312.pyc create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pip/_vendor/rich/__pycache__/repr.cpython-312.pyc create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pip/_vendor/rich/__pycache__/rule.cpython-312.pyc create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pip/_vendor/rich/__pycache__/scope.cpython-312.pyc create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pip/_vendor/rich/__pycache__/screen.cpython-312.pyc create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pip/_vendor/rich/__pycache__/segment.cpython-312.pyc create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pip/_vendor/rich/__pycache__/spinner.cpython-312.pyc create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pip/_vendor/rich/__pycache__/status.cpython-312.pyc create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pip/_vendor/rich/__pycache__/style.cpython-312.pyc create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pip/_vendor/rich/__pycache__/styled.cpython-312.pyc create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pip/_vendor/rich/__pycache__/syntax.cpython-312.pyc create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pip/_vendor/rich/__pycache__/table.cpython-312.pyc create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pip/_vendor/rich/__pycache__/terminal_theme.cpython-312.pyc create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pip/_vendor/rich/__pycache__/text.cpython-312.pyc create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pip/_vendor/rich/__pycache__/theme.cpython-312.pyc create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pip/_vendor/rich/__pycache__/themes.cpython-312.pyc create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pip/_vendor/rich/__pycache__/traceback.cpython-312.pyc create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pip/_vendor/rich/__pycache__/tree.cpython-312.pyc create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pip/_vendor/rich/_cell_widths.py create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pip/_vendor/rich/_emoji_codes.py create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pip/_vendor/rich/_emoji_replace.py create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pip/_vendor/rich/_export_format.py create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pip/_vendor/rich/_extension.py create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pip/_vendor/rich/_fileno.py create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pip/_vendor/rich/_inspect.py create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pip/_vendor/rich/_log_render.py create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pip/_vendor/rich/_loop.py create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pip/_vendor/rich/_null_file.py create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pip/_vendor/rich/_palettes.py create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pip/_vendor/rich/_pick.py create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pip/_vendor/rich/_ratio.py create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pip/_vendor/rich/_spinners.py create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pip/_vendor/rich/_stack.py create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pip/_vendor/rich/_timer.py create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pip/_vendor/rich/_win32_console.py create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pip/_vendor/rich/_windows.py create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pip/_vendor/rich/_windows_renderer.py create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pip/_vendor/rich/_wrap.py create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pip/_vendor/rich/abc.py create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pip/_vendor/rich/align.py create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pip/_vendor/rich/ansi.py create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pip/_vendor/rich/bar.py create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pip/_vendor/rich/box.py create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pip/_vendor/rich/cells.py create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pip/_vendor/rich/color.py create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pip/_vendor/rich/color_triplet.py create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pip/_vendor/rich/columns.py create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pip/_vendor/rich/console.py create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pip/_vendor/rich/constrain.py create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pip/_vendor/rich/containers.py create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pip/_vendor/rich/control.py create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pip/_vendor/rich/default_styles.py create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pip/_vendor/rich/diagnose.py create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pip/_vendor/rich/emoji.py create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pip/_vendor/rich/errors.py create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pip/_vendor/rich/file_proxy.py create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pip/_vendor/rich/filesize.py create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pip/_vendor/rich/highlighter.py create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pip/_vendor/rich/json.py create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pip/_vendor/rich/jupyter.py create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pip/_vendor/rich/layout.py create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pip/_vendor/rich/live.py create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pip/_vendor/rich/live_render.py create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pip/_vendor/rich/logging.py create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pip/_vendor/rich/markup.py create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pip/_vendor/rich/measure.py create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pip/_vendor/rich/padding.py create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pip/_vendor/rich/pager.py create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pip/_vendor/rich/palette.py create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pip/_vendor/rich/panel.py create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pip/_vendor/rich/pretty.py create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pip/_vendor/rich/progress.py create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pip/_vendor/rich/progress_bar.py create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pip/_vendor/rich/prompt.py create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pip/_vendor/rich/protocol.py create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pip/_vendor/rich/py.typed create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pip/_vendor/rich/region.py create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pip/_vendor/rich/repr.py create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pip/_vendor/rich/rule.py create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pip/_vendor/rich/scope.py create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pip/_vendor/rich/screen.py create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pip/_vendor/rich/segment.py create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pip/_vendor/rich/spinner.py create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pip/_vendor/rich/status.py create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pip/_vendor/rich/style.py create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pip/_vendor/rich/styled.py create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pip/_vendor/rich/syntax.py create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pip/_vendor/rich/table.py create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pip/_vendor/rich/terminal_theme.py create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pip/_vendor/rich/text.py create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pip/_vendor/rich/theme.py create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pip/_vendor/rich/themes.py create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pip/_vendor/rich/traceback.py create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pip/_vendor/rich/tree.py create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pip/_vendor/tomli/__init__.py create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pip/_vendor/tomli/__pycache__/__init__.cpython-312.pyc create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pip/_vendor/tomli/__pycache__/_parser.cpython-312.pyc create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pip/_vendor/tomli/__pycache__/_re.cpython-312.pyc create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pip/_vendor/tomli/__pycache__/_types.cpython-312.pyc create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pip/_vendor/tomli/_parser.py create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pip/_vendor/tomli/_re.py create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pip/_vendor/tomli/_types.py create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pip/_vendor/tomli/py.typed create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pip/_vendor/truststore/__init__.py create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pip/_vendor/truststore/__pycache__/__init__.cpython-312.pyc create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pip/_vendor/truststore/__pycache__/_api.cpython-312.pyc create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pip/_vendor/truststore/__pycache__/_macos.cpython-312.pyc create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pip/_vendor/truststore/__pycache__/_openssl.cpython-312.pyc create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pip/_vendor/truststore/__pycache__/_ssl_constants.cpython-312.pyc create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pip/_vendor/truststore/__pycache__/_windows.cpython-312.pyc create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pip/_vendor/truststore/_api.py create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pip/_vendor/truststore/_macos.py create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pip/_vendor/truststore/_openssl.py create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pip/_vendor/truststore/_ssl_constants.py create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pip/_vendor/truststore/_windows.py create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pip/_vendor/truststore/py.typed create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pip/_vendor/typing_extensions.py create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pip/_vendor/urllib3/__init__.py create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pip/_vendor/urllib3/__pycache__/__init__.cpython-312.pyc create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pip/_vendor/urllib3/__pycache__/_collections.cpython-312.pyc create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pip/_vendor/urllib3/__pycache__/_version.cpython-312.pyc create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pip/_vendor/urllib3/__pycache__/connection.cpython-312.pyc create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pip/_vendor/urllib3/__pycache__/connectionpool.cpython-312.pyc create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pip/_vendor/urllib3/__pycache__/exceptions.cpython-312.pyc create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pip/_vendor/urllib3/__pycache__/fields.cpython-312.pyc create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pip/_vendor/urllib3/__pycache__/filepost.cpython-312.pyc create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pip/_vendor/urllib3/__pycache__/poolmanager.cpython-312.pyc create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pip/_vendor/urllib3/__pycache__/request.cpython-312.pyc create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pip/_vendor/urllib3/__pycache__/response.cpython-312.pyc create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pip/_vendor/urllib3/_collections.py create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pip/_vendor/urllib3/_version.py create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pip/_vendor/urllib3/connection.py create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pip/_vendor/urllib3/connectionpool.py create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pip/_vendor/urllib3/contrib/__init__.py create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pip/_vendor/urllib3/contrib/__pycache__/__init__.cpython-312.pyc create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pip/_vendor/urllib3/contrib/__pycache__/_appengine_environ.cpython-312.pyc create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pip/_vendor/urllib3/contrib/__pycache__/appengine.cpython-312.pyc create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pip/_vendor/urllib3/contrib/__pycache__/ntlmpool.cpython-312.pyc create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pip/_vendor/urllib3/contrib/__pycache__/pyopenssl.cpython-312.pyc create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pip/_vendor/urllib3/contrib/__pycache__/securetransport.cpython-312.pyc create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pip/_vendor/urllib3/contrib/__pycache__/socks.cpython-312.pyc create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pip/_vendor/urllib3/contrib/_appengine_environ.py create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pip/_vendor/urllib3/contrib/_securetransport/__init__.py create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pip/_vendor/urllib3/contrib/_securetransport/__pycache__/__init__.cpython-312.pyc create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pip/_vendor/urllib3/contrib/_securetransport/__pycache__/bindings.cpython-312.pyc create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pip/_vendor/urllib3/contrib/_securetransport/__pycache__/low_level.cpython-312.pyc create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pip/_vendor/urllib3/contrib/_securetransport/bindings.py create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pip/_vendor/urllib3/contrib/_securetransport/low_level.py create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pip/_vendor/urllib3/contrib/appengine.py create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pip/_vendor/urllib3/contrib/ntlmpool.py create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pip/_vendor/urllib3/contrib/pyopenssl.py create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pip/_vendor/urllib3/contrib/securetransport.py create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pip/_vendor/urllib3/contrib/socks.py create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pip/_vendor/urllib3/exceptions.py create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pip/_vendor/urllib3/fields.py create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pip/_vendor/urllib3/filepost.py create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pip/_vendor/urllib3/packages/__init__.py create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pip/_vendor/urllib3/packages/__pycache__/__init__.cpython-312.pyc create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pip/_vendor/urllib3/packages/__pycache__/six.cpython-312.pyc create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pip/_vendor/urllib3/packages/backports/__init__.py create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pip/_vendor/urllib3/packages/backports/__pycache__/__init__.cpython-312.pyc create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pip/_vendor/urllib3/packages/backports/__pycache__/makefile.cpython-312.pyc create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pip/_vendor/urllib3/packages/backports/__pycache__/weakref_finalize.cpython-312.pyc create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pip/_vendor/urllib3/packages/backports/makefile.py create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pip/_vendor/urllib3/packages/backports/weakref_finalize.py create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pip/_vendor/urllib3/packages/six.py create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pip/_vendor/urllib3/poolmanager.py create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pip/_vendor/urllib3/request.py create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pip/_vendor/urllib3/response.py create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pip/_vendor/urllib3/util/__init__.py create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pip/_vendor/urllib3/util/__pycache__/__init__.cpython-312.pyc create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pip/_vendor/urllib3/util/__pycache__/connection.cpython-312.pyc create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pip/_vendor/urllib3/util/__pycache__/proxy.cpython-312.pyc create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pip/_vendor/urllib3/util/__pycache__/queue.cpython-312.pyc create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pip/_vendor/urllib3/util/__pycache__/request.cpython-312.pyc create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pip/_vendor/urllib3/util/__pycache__/response.cpython-312.pyc create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pip/_vendor/urllib3/util/__pycache__/retry.cpython-312.pyc create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pip/_vendor/urllib3/util/__pycache__/ssl_.cpython-312.pyc create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pip/_vendor/urllib3/util/__pycache__/ssl_match_hostname.cpython-312.pyc create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pip/_vendor/urllib3/util/__pycache__/ssltransport.cpython-312.pyc create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pip/_vendor/urllib3/util/__pycache__/timeout.cpython-312.pyc create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pip/_vendor/urllib3/util/__pycache__/url.cpython-312.pyc create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pip/_vendor/urllib3/util/__pycache__/wait.cpython-312.pyc create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pip/_vendor/urllib3/util/connection.py create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pip/_vendor/urllib3/util/proxy.py create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pip/_vendor/urllib3/util/queue.py create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pip/_vendor/urllib3/util/request.py create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pip/_vendor/urllib3/util/response.py create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pip/_vendor/urllib3/util/retry.py create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pip/_vendor/urllib3/util/ssl_.py create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pip/_vendor/urllib3/util/ssl_match_hostname.py create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pip/_vendor/urllib3/util/ssltransport.py create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pip/_vendor/urllib3/util/timeout.py create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pip/_vendor/urllib3/util/url.py create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pip/_vendor/urllib3/util/wait.py create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pip/_vendor/vendor.txt create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pip/py.typed create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pytz-2024.2.dist-info/INSTALLER create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pytz-2024.2.dist-info/LICENSE.txt create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pytz-2024.2.dist-info/METADATA create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pytz-2024.2.dist-info/RECORD create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pytz-2024.2.dist-info/REQUESTED create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pytz-2024.2.dist-info/WHEEL create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pytz-2024.2.dist-info/top_level.txt create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pytz-2024.2.dist-info/zip-safe create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pytz/__init__.py create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pytz/__pycache__/__init__.cpython-312.pyc create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pytz/__pycache__/exceptions.cpython-312.pyc create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pytz/__pycache__/lazy.cpython-312.pyc create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pytz/__pycache__/reference.cpython-312.pyc create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pytz/__pycache__/tzfile.cpython-312.pyc create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pytz/__pycache__/tzinfo.cpython-312.pyc create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pytz/exceptions.py create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pytz/lazy.py create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pytz/reference.py create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pytz/tzfile.py create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pytz/tzinfo.py create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pytz/zoneinfo/Africa/Abidjan create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pytz/zoneinfo/Africa/Accra create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pytz/zoneinfo/Africa/Addis_Ababa create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pytz/zoneinfo/Africa/Algiers create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pytz/zoneinfo/Africa/Asmara create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pytz/zoneinfo/Africa/Asmera create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pytz/zoneinfo/Africa/Bamako create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pytz/zoneinfo/Africa/Bangui create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pytz/zoneinfo/Africa/Banjul create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pytz/zoneinfo/Africa/Bissau create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pytz/zoneinfo/Africa/Blantyre create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pytz/zoneinfo/Africa/Brazzaville create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pytz/zoneinfo/Africa/Bujumbura create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pytz/zoneinfo/Africa/Cairo create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pytz/zoneinfo/Africa/Casablanca create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pytz/zoneinfo/Africa/Ceuta create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pytz/zoneinfo/Africa/Conakry create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pytz/zoneinfo/Africa/Dakar create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pytz/zoneinfo/Africa/Dar_es_Salaam create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pytz/zoneinfo/Africa/Djibouti create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pytz/zoneinfo/Africa/Douala create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pytz/zoneinfo/Africa/El_Aaiun create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pytz/zoneinfo/Africa/Freetown create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pytz/zoneinfo/Africa/Gaborone create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pytz/zoneinfo/Africa/Harare create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pytz/zoneinfo/Africa/Johannesburg create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pytz/zoneinfo/Africa/Juba create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pytz/zoneinfo/Africa/Kampala create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pytz/zoneinfo/Africa/Khartoum create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pytz/zoneinfo/Africa/Kigali create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pytz/zoneinfo/Africa/Kinshasa create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pytz/zoneinfo/Africa/Lagos create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pytz/zoneinfo/Africa/Libreville create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pytz/zoneinfo/Africa/Lome create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pytz/zoneinfo/Africa/Luanda create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pytz/zoneinfo/Africa/Lubumbashi create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pytz/zoneinfo/Africa/Lusaka create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pytz/zoneinfo/Africa/Malabo create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pytz/zoneinfo/Africa/Maputo create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pytz/zoneinfo/Africa/Maseru create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pytz/zoneinfo/Africa/Mbabane create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pytz/zoneinfo/Africa/Mogadishu create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pytz/zoneinfo/Africa/Monrovia create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pytz/zoneinfo/Africa/Nairobi create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pytz/zoneinfo/Africa/Ndjamena create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pytz/zoneinfo/Africa/Niamey create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pytz/zoneinfo/Africa/Nouakchott create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pytz/zoneinfo/Africa/Ouagadougou create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pytz/zoneinfo/Africa/Porto-Novo create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pytz/zoneinfo/Africa/Sao_Tome create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pytz/zoneinfo/Africa/Timbuktu create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pytz/zoneinfo/Africa/Tripoli create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pytz/zoneinfo/Africa/Tunis create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pytz/zoneinfo/Africa/Windhoek create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pytz/zoneinfo/America/Adak create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pytz/zoneinfo/America/Anchorage create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pytz/zoneinfo/America/Anguilla create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pytz/zoneinfo/America/Antigua create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pytz/zoneinfo/America/Araguaina create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pytz/zoneinfo/America/Argentina/Buenos_Aires create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pytz/zoneinfo/America/Argentina/Catamarca create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pytz/zoneinfo/America/Argentina/ComodRivadavia create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pytz/zoneinfo/America/Argentina/Cordoba create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pytz/zoneinfo/America/Argentina/Jujuy create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pytz/zoneinfo/America/Argentina/La_Rioja create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pytz/zoneinfo/America/Argentina/Mendoza create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pytz/zoneinfo/America/Argentina/Rio_Gallegos create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pytz/zoneinfo/America/Argentina/Salta create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pytz/zoneinfo/America/Argentina/San_Juan create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pytz/zoneinfo/America/Argentina/San_Luis create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pytz/zoneinfo/America/Argentina/Tucuman create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pytz/zoneinfo/America/Argentina/Ushuaia create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pytz/zoneinfo/America/Aruba create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pytz/zoneinfo/America/Asuncion create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pytz/zoneinfo/America/Atikokan create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pytz/zoneinfo/America/Atka create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pytz/zoneinfo/America/Bahia create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pytz/zoneinfo/America/Bahia_Banderas create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pytz/zoneinfo/America/Barbados create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pytz/zoneinfo/America/Belem create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pytz/zoneinfo/America/Belize create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pytz/zoneinfo/America/Blanc-Sablon create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pytz/zoneinfo/America/Boa_Vista create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pytz/zoneinfo/America/Bogota create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pytz/zoneinfo/America/Boise create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pytz/zoneinfo/America/Buenos_Aires create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pytz/zoneinfo/America/Cambridge_Bay create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pytz/zoneinfo/America/Campo_Grande create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pytz/zoneinfo/America/Cancun create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pytz/zoneinfo/America/Caracas create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pytz/zoneinfo/America/Catamarca create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pytz/zoneinfo/America/Cayenne create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pytz/zoneinfo/America/Cayman create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pytz/zoneinfo/America/Chicago create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pytz/zoneinfo/America/Chihuahua create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pytz/zoneinfo/America/Ciudad_Juarez create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pytz/zoneinfo/America/Coral_Harbour create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pytz/zoneinfo/America/Cordoba create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pytz/zoneinfo/America/Costa_Rica create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pytz/zoneinfo/America/Creston create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pytz/zoneinfo/America/Cuiaba create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pytz/zoneinfo/America/Curacao create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pytz/zoneinfo/America/Danmarkshavn create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pytz/zoneinfo/America/Dawson create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pytz/zoneinfo/America/Dawson_Creek create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pytz/zoneinfo/America/Denver create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pytz/zoneinfo/America/Detroit create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pytz/zoneinfo/America/Dominica create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pytz/zoneinfo/America/Edmonton create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pytz/zoneinfo/America/Eirunepe create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pytz/zoneinfo/America/El_Salvador create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pytz/zoneinfo/America/Ensenada create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pytz/zoneinfo/America/Fort_Nelson create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pytz/zoneinfo/America/Fort_Wayne create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pytz/zoneinfo/America/Fortaleza create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pytz/zoneinfo/America/Glace_Bay create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pytz/zoneinfo/America/Godthab create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pytz/zoneinfo/America/Goose_Bay create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pytz/zoneinfo/America/Grand_Turk create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pytz/zoneinfo/America/Grenada create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pytz/zoneinfo/America/Guadeloupe create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pytz/zoneinfo/America/Guatemala create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pytz/zoneinfo/America/Guayaquil create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pytz/zoneinfo/America/Guyana create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pytz/zoneinfo/America/Halifax create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pytz/zoneinfo/America/Havana create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pytz/zoneinfo/America/Hermosillo create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pytz/zoneinfo/America/Indiana/Indianapolis create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pytz/zoneinfo/America/Indiana/Knox create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pytz/zoneinfo/America/Indiana/Marengo create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pytz/zoneinfo/America/Indiana/Petersburg create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pytz/zoneinfo/America/Indiana/Tell_City create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pytz/zoneinfo/America/Indiana/Vevay create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pytz/zoneinfo/America/Indiana/Vincennes create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pytz/zoneinfo/America/Indiana/Winamac create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pytz/zoneinfo/America/Indianapolis create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pytz/zoneinfo/America/Inuvik create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pytz/zoneinfo/America/Iqaluit create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pytz/zoneinfo/America/Jamaica create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pytz/zoneinfo/America/Jujuy create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pytz/zoneinfo/America/Juneau create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pytz/zoneinfo/America/Kentucky/Louisville create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pytz/zoneinfo/America/Kentucky/Monticello create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pytz/zoneinfo/America/Knox_IN create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pytz/zoneinfo/America/Kralendijk create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pytz/zoneinfo/America/La_Paz create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pytz/zoneinfo/America/Lima create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pytz/zoneinfo/America/Los_Angeles create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pytz/zoneinfo/America/Louisville create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pytz/zoneinfo/America/Lower_Princes create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pytz/zoneinfo/America/Maceio create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pytz/zoneinfo/America/Managua create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pytz/zoneinfo/America/Manaus create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pytz/zoneinfo/America/Marigot create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pytz/zoneinfo/America/Martinique create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pytz/zoneinfo/America/Matamoros create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pytz/zoneinfo/America/Mazatlan create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pytz/zoneinfo/America/Mendoza create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pytz/zoneinfo/America/Menominee create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pytz/zoneinfo/America/Merida create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pytz/zoneinfo/America/Metlakatla create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pytz/zoneinfo/America/Mexico_City create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pytz/zoneinfo/America/Miquelon create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pytz/zoneinfo/America/Moncton create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pytz/zoneinfo/America/Monterrey create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pytz/zoneinfo/America/Montevideo create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pytz/zoneinfo/America/Montreal create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pytz/zoneinfo/America/Montserrat create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pytz/zoneinfo/America/Nassau create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pytz/zoneinfo/America/New_York create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pytz/zoneinfo/America/Nipigon create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pytz/zoneinfo/America/Nome create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pytz/zoneinfo/America/Noronha create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pytz/zoneinfo/America/North_Dakota/Beulah create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pytz/zoneinfo/America/North_Dakota/Center create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pytz/zoneinfo/America/North_Dakota/New_Salem create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pytz/zoneinfo/America/Nuuk create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pytz/zoneinfo/America/Ojinaga create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pytz/zoneinfo/America/Panama create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pytz/zoneinfo/America/Pangnirtung create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pytz/zoneinfo/America/Paramaribo create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pytz/zoneinfo/America/Phoenix create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pytz/zoneinfo/America/Port-au-Prince create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pytz/zoneinfo/America/Port_of_Spain create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pytz/zoneinfo/America/Porto_Acre create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pytz/zoneinfo/America/Porto_Velho create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pytz/zoneinfo/America/Puerto_Rico create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pytz/zoneinfo/America/Punta_Arenas create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pytz/zoneinfo/America/Rainy_River create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pytz/zoneinfo/America/Rankin_Inlet create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pytz/zoneinfo/America/Recife create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pytz/zoneinfo/America/Regina create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pytz/zoneinfo/America/Resolute create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pytz/zoneinfo/America/Rio_Branco create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pytz/zoneinfo/America/Rosario create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pytz/zoneinfo/America/Santa_Isabel create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pytz/zoneinfo/America/Santarem create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pytz/zoneinfo/America/Santiago create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pytz/zoneinfo/America/Santo_Domingo create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pytz/zoneinfo/America/Sao_Paulo create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pytz/zoneinfo/America/Scoresbysund create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pytz/zoneinfo/America/Shiprock create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pytz/zoneinfo/America/Sitka create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pytz/zoneinfo/America/St_Barthelemy create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pytz/zoneinfo/America/St_Johns create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pytz/zoneinfo/America/St_Kitts create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pytz/zoneinfo/America/St_Lucia create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pytz/zoneinfo/America/St_Thomas create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pytz/zoneinfo/America/St_Vincent create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pytz/zoneinfo/America/Swift_Current create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pytz/zoneinfo/America/Tegucigalpa create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pytz/zoneinfo/America/Thule create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pytz/zoneinfo/America/Thunder_Bay create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pytz/zoneinfo/America/Tijuana create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pytz/zoneinfo/America/Toronto create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pytz/zoneinfo/America/Tortola create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pytz/zoneinfo/America/Vancouver create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pytz/zoneinfo/America/Virgin create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pytz/zoneinfo/America/Whitehorse create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pytz/zoneinfo/America/Winnipeg create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pytz/zoneinfo/America/Yakutat create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pytz/zoneinfo/America/Yellowknife create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pytz/zoneinfo/Antarctica/Casey create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pytz/zoneinfo/Antarctica/Davis create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pytz/zoneinfo/Antarctica/DumontDUrville create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pytz/zoneinfo/Antarctica/Macquarie create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pytz/zoneinfo/Antarctica/Mawson create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pytz/zoneinfo/Antarctica/McMurdo create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pytz/zoneinfo/Antarctica/Palmer create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pytz/zoneinfo/Antarctica/Rothera create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pytz/zoneinfo/Antarctica/South_Pole create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pytz/zoneinfo/Antarctica/Syowa create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pytz/zoneinfo/Antarctica/Troll create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pytz/zoneinfo/Antarctica/Vostok create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pytz/zoneinfo/Arctic/Longyearbyen create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pytz/zoneinfo/Asia/Aden create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pytz/zoneinfo/Asia/Almaty create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pytz/zoneinfo/Asia/Amman create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pytz/zoneinfo/Asia/Anadyr create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pytz/zoneinfo/Asia/Aqtau create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pytz/zoneinfo/Asia/Aqtobe create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pytz/zoneinfo/Asia/Ashgabat create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pytz/zoneinfo/Asia/Ashkhabad create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pytz/zoneinfo/Asia/Atyrau create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pytz/zoneinfo/Asia/Baghdad create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pytz/zoneinfo/Asia/Bahrain create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pytz/zoneinfo/Asia/Baku create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pytz/zoneinfo/Asia/Bangkok create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pytz/zoneinfo/Asia/Barnaul create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pytz/zoneinfo/Asia/Beirut create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pytz/zoneinfo/Asia/Bishkek create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pytz/zoneinfo/Asia/Brunei create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pytz/zoneinfo/Asia/Calcutta create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pytz/zoneinfo/Asia/Chita create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pytz/zoneinfo/Asia/Choibalsan create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pytz/zoneinfo/Asia/Chongqing create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pytz/zoneinfo/Asia/Chungking create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pytz/zoneinfo/Asia/Colombo create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pytz/zoneinfo/Asia/Dacca create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pytz/zoneinfo/Asia/Damascus create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pytz/zoneinfo/Asia/Dhaka create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pytz/zoneinfo/Asia/Dili create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pytz/zoneinfo/Asia/Dubai create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pytz/zoneinfo/Asia/Dushanbe create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pytz/zoneinfo/Asia/Famagusta create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pytz/zoneinfo/Asia/Gaza create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pytz/zoneinfo/Asia/Harbin create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pytz/zoneinfo/Asia/Hebron create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pytz/zoneinfo/Asia/Ho_Chi_Minh create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pytz/zoneinfo/Asia/Hong_Kong create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pytz/zoneinfo/Asia/Hovd create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pytz/zoneinfo/Asia/Irkutsk create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pytz/zoneinfo/Asia/Istanbul create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pytz/zoneinfo/Asia/Jakarta create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pytz/zoneinfo/Asia/Jayapura create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pytz/zoneinfo/Asia/Jerusalem create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pytz/zoneinfo/Asia/Kabul create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pytz/zoneinfo/Asia/Kamchatka create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pytz/zoneinfo/Asia/Karachi create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pytz/zoneinfo/Asia/Kashgar create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pytz/zoneinfo/Asia/Kathmandu create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pytz/zoneinfo/Asia/Katmandu create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pytz/zoneinfo/Asia/Khandyga create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pytz/zoneinfo/Asia/Kolkata create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pytz/zoneinfo/Asia/Krasnoyarsk create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pytz/zoneinfo/Asia/Kuala_Lumpur create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pytz/zoneinfo/Asia/Kuching create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pytz/zoneinfo/Asia/Kuwait create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pytz/zoneinfo/Asia/Macao create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pytz/zoneinfo/Asia/Macau create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pytz/zoneinfo/Asia/Magadan create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pytz/zoneinfo/Asia/Makassar create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pytz/zoneinfo/Asia/Manila create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pytz/zoneinfo/Asia/Muscat create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pytz/zoneinfo/Asia/Nicosia create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pytz/zoneinfo/Asia/Novokuznetsk create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pytz/zoneinfo/Asia/Novosibirsk create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pytz/zoneinfo/Asia/Omsk create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pytz/zoneinfo/Asia/Oral create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pytz/zoneinfo/Asia/Phnom_Penh create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pytz/zoneinfo/Asia/Pontianak create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pytz/zoneinfo/Asia/Pyongyang create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pytz/zoneinfo/Asia/Qatar create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pytz/zoneinfo/Asia/Qostanay create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pytz/zoneinfo/Asia/Qyzylorda create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pytz/zoneinfo/Asia/Rangoon create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pytz/zoneinfo/Asia/Riyadh create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pytz/zoneinfo/Asia/Saigon create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pytz/zoneinfo/Asia/Sakhalin create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pytz/zoneinfo/Asia/Samarkand create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pytz/zoneinfo/Asia/Seoul create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pytz/zoneinfo/Asia/Shanghai create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pytz/zoneinfo/Asia/Singapore create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pytz/zoneinfo/Asia/Srednekolymsk create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pytz/zoneinfo/Asia/Taipei create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pytz/zoneinfo/Asia/Tashkent create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pytz/zoneinfo/Asia/Tbilisi create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pytz/zoneinfo/Asia/Tehran create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pytz/zoneinfo/Asia/Tel_Aviv create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pytz/zoneinfo/Asia/Thimbu create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pytz/zoneinfo/Asia/Thimphu create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pytz/zoneinfo/Asia/Tokyo create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pytz/zoneinfo/Asia/Tomsk create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pytz/zoneinfo/Asia/Ujung_Pandang create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pytz/zoneinfo/Asia/Ulaanbaatar create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pytz/zoneinfo/Asia/Ulan_Bator create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pytz/zoneinfo/Asia/Urumqi create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pytz/zoneinfo/Asia/Ust-Nera create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pytz/zoneinfo/Asia/Vientiane create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pytz/zoneinfo/Asia/Vladivostok create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pytz/zoneinfo/Asia/Yakutsk create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pytz/zoneinfo/Asia/Yangon create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pytz/zoneinfo/Asia/Yekaterinburg create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pytz/zoneinfo/Asia/Yerevan create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pytz/zoneinfo/Atlantic/Azores create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pytz/zoneinfo/Atlantic/Bermuda create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pytz/zoneinfo/Atlantic/Canary create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pytz/zoneinfo/Atlantic/Cape_Verde create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pytz/zoneinfo/Atlantic/Faeroe create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pytz/zoneinfo/Atlantic/Faroe create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pytz/zoneinfo/Atlantic/Jan_Mayen create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pytz/zoneinfo/Atlantic/Madeira create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pytz/zoneinfo/Atlantic/Reykjavik create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pytz/zoneinfo/Atlantic/South_Georgia create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pytz/zoneinfo/Atlantic/St_Helena create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pytz/zoneinfo/Atlantic/Stanley create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pytz/zoneinfo/Australia/ACT create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pytz/zoneinfo/Australia/Adelaide create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pytz/zoneinfo/Australia/Brisbane create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pytz/zoneinfo/Australia/Broken_Hill create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pytz/zoneinfo/Australia/Canberra create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pytz/zoneinfo/Australia/Currie create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pytz/zoneinfo/Australia/Darwin create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pytz/zoneinfo/Australia/Eucla create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pytz/zoneinfo/Australia/Hobart create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pytz/zoneinfo/Australia/LHI create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pytz/zoneinfo/Australia/Lindeman create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pytz/zoneinfo/Australia/Lord_Howe create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pytz/zoneinfo/Australia/Melbourne create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pytz/zoneinfo/Australia/NSW create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pytz/zoneinfo/Australia/North create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pytz/zoneinfo/Australia/Perth create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pytz/zoneinfo/Australia/Queensland create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pytz/zoneinfo/Australia/South create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pytz/zoneinfo/Australia/Sydney create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pytz/zoneinfo/Australia/Tasmania create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pytz/zoneinfo/Australia/Victoria create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pytz/zoneinfo/Australia/West create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pytz/zoneinfo/Australia/Yancowinna create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pytz/zoneinfo/Brazil/Acre create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pytz/zoneinfo/Brazil/DeNoronha create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pytz/zoneinfo/Brazil/East create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pytz/zoneinfo/Brazil/West create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pytz/zoneinfo/CET create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pytz/zoneinfo/CST6CDT create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pytz/zoneinfo/Canada/Atlantic create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pytz/zoneinfo/Canada/Central create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pytz/zoneinfo/Canada/Eastern create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pytz/zoneinfo/Canada/Mountain create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pytz/zoneinfo/Canada/Newfoundland create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pytz/zoneinfo/Canada/Pacific create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pytz/zoneinfo/Canada/Saskatchewan create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pytz/zoneinfo/Canada/Yukon create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pytz/zoneinfo/Chile/Continental create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pytz/zoneinfo/Chile/EasterIsland create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pytz/zoneinfo/Cuba create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pytz/zoneinfo/EET create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pytz/zoneinfo/EST create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pytz/zoneinfo/EST5EDT create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pytz/zoneinfo/Egypt create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pytz/zoneinfo/Eire create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pytz/zoneinfo/Etc/GMT create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pytz/zoneinfo/Etc/GMT+0 create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pytz/zoneinfo/Etc/GMT+1 create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pytz/zoneinfo/Etc/GMT+10 create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pytz/zoneinfo/Etc/GMT+11 create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pytz/zoneinfo/Etc/GMT+12 create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pytz/zoneinfo/Etc/GMT+2 create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pytz/zoneinfo/Etc/GMT+3 create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pytz/zoneinfo/Etc/GMT+4 create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pytz/zoneinfo/Etc/GMT+5 create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pytz/zoneinfo/Etc/GMT+6 create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pytz/zoneinfo/Etc/GMT+7 create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pytz/zoneinfo/Etc/GMT+8 create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pytz/zoneinfo/Etc/GMT+9 create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pytz/zoneinfo/Etc/GMT-0 create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pytz/zoneinfo/Etc/GMT-1 create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pytz/zoneinfo/Etc/GMT-10 create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pytz/zoneinfo/Etc/GMT-11 create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pytz/zoneinfo/Etc/GMT-12 create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pytz/zoneinfo/Etc/GMT-13 create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pytz/zoneinfo/Etc/GMT-14 create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pytz/zoneinfo/Etc/GMT-2 create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pytz/zoneinfo/Etc/GMT-3 create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pytz/zoneinfo/Etc/GMT-4 create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pytz/zoneinfo/Etc/GMT-5 create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pytz/zoneinfo/Etc/GMT-6 create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pytz/zoneinfo/Etc/GMT-7 create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pytz/zoneinfo/Etc/GMT-8 create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pytz/zoneinfo/Etc/GMT-9 create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pytz/zoneinfo/Etc/GMT0 create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pytz/zoneinfo/Etc/Greenwich create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pytz/zoneinfo/Etc/UCT create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pytz/zoneinfo/Etc/UTC create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pytz/zoneinfo/Etc/Universal create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pytz/zoneinfo/Etc/Zulu create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pytz/zoneinfo/Europe/Amsterdam create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pytz/zoneinfo/Europe/Andorra create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pytz/zoneinfo/Europe/Astrakhan create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pytz/zoneinfo/Europe/Athens create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pytz/zoneinfo/Europe/Belfast create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pytz/zoneinfo/Europe/Belgrade create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pytz/zoneinfo/Europe/Berlin create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pytz/zoneinfo/Europe/Bratislava create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pytz/zoneinfo/Europe/Brussels create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pytz/zoneinfo/Europe/Bucharest create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pytz/zoneinfo/Europe/Budapest create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pytz/zoneinfo/Europe/Busingen create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pytz/zoneinfo/Europe/Chisinau create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pytz/zoneinfo/Europe/Copenhagen create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pytz/zoneinfo/Europe/Dublin create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pytz/zoneinfo/Europe/Gibraltar create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pytz/zoneinfo/Europe/Guernsey create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pytz/zoneinfo/Europe/Helsinki create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pytz/zoneinfo/Europe/Isle_of_Man create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pytz/zoneinfo/Europe/Istanbul create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pytz/zoneinfo/Europe/Jersey create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pytz/zoneinfo/Europe/Kaliningrad create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pytz/zoneinfo/Europe/Kiev create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pytz/zoneinfo/Europe/Kirov create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pytz/zoneinfo/Europe/Kyiv create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pytz/zoneinfo/Europe/Lisbon create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pytz/zoneinfo/Europe/Ljubljana create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pytz/zoneinfo/Europe/London create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pytz/zoneinfo/Europe/Luxembourg create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pytz/zoneinfo/Europe/Madrid create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pytz/zoneinfo/Europe/Malta create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pytz/zoneinfo/Europe/Mariehamn create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pytz/zoneinfo/Europe/Minsk create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pytz/zoneinfo/Europe/Monaco create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pytz/zoneinfo/Europe/Moscow create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pytz/zoneinfo/Europe/Nicosia create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pytz/zoneinfo/Europe/Oslo create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pytz/zoneinfo/Europe/Paris create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pytz/zoneinfo/Europe/Podgorica create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pytz/zoneinfo/Europe/Prague create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pytz/zoneinfo/Europe/Riga create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pytz/zoneinfo/Europe/Rome create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pytz/zoneinfo/Europe/Samara create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pytz/zoneinfo/Europe/San_Marino create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pytz/zoneinfo/Europe/Sarajevo create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pytz/zoneinfo/Europe/Saratov create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pytz/zoneinfo/Europe/Simferopol create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pytz/zoneinfo/Europe/Skopje create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pytz/zoneinfo/Europe/Sofia create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pytz/zoneinfo/Europe/Stockholm create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pytz/zoneinfo/Europe/Tallinn create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pytz/zoneinfo/Europe/Tirane create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pytz/zoneinfo/Europe/Tiraspol create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pytz/zoneinfo/Europe/Ulyanovsk create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pytz/zoneinfo/Europe/Uzhgorod create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pytz/zoneinfo/Europe/Vaduz create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pytz/zoneinfo/Europe/Vatican create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pytz/zoneinfo/Europe/Vienna create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pytz/zoneinfo/Europe/Vilnius create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pytz/zoneinfo/Europe/Volgograd create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pytz/zoneinfo/Europe/Warsaw create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pytz/zoneinfo/Europe/Zagreb create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pytz/zoneinfo/Europe/Zaporozhye create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pytz/zoneinfo/Europe/Zurich create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pytz/zoneinfo/Factory create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pytz/zoneinfo/GB create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pytz/zoneinfo/GB-Eire create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pytz/zoneinfo/GMT create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pytz/zoneinfo/GMT+0 create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pytz/zoneinfo/GMT-0 create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pytz/zoneinfo/GMT0 create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pytz/zoneinfo/Greenwich create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pytz/zoneinfo/HST create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pytz/zoneinfo/Hongkong create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pytz/zoneinfo/Iceland create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pytz/zoneinfo/Indian/Antananarivo create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pytz/zoneinfo/Indian/Chagos create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pytz/zoneinfo/Indian/Christmas create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pytz/zoneinfo/Indian/Cocos create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pytz/zoneinfo/Indian/Comoro create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pytz/zoneinfo/Indian/Kerguelen create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pytz/zoneinfo/Indian/Mahe create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pytz/zoneinfo/Indian/Maldives create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pytz/zoneinfo/Indian/Mauritius create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pytz/zoneinfo/Indian/Mayotte create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pytz/zoneinfo/Indian/Reunion create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pytz/zoneinfo/Iran create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pytz/zoneinfo/Israel create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pytz/zoneinfo/Jamaica create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pytz/zoneinfo/Japan create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pytz/zoneinfo/Kwajalein create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pytz/zoneinfo/Libya create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pytz/zoneinfo/MET create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pytz/zoneinfo/MST create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pytz/zoneinfo/MST7MDT create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pytz/zoneinfo/Mexico/BajaNorte create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pytz/zoneinfo/Mexico/BajaSur create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pytz/zoneinfo/Mexico/General create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pytz/zoneinfo/NZ create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pytz/zoneinfo/NZ-CHAT create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pytz/zoneinfo/Navajo create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pytz/zoneinfo/PRC create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pytz/zoneinfo/PST8PDT create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pytz/zoneinfo/Pacific/Apia create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pytz/zoneinfo/Pacific/Auckland create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pytz/zoneinfo/Pacific/Bougainville create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pytz/zoneinfo/Pacific/Chatham create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pytz/zoneinfo/Pacific/Chuuk create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pytz/zoneinfo/Pacific/Easter create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pytz/zoneinfo/Pacific/Efate create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pytz/zoneinfo/Pacific/Enderbury create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pytz/zoneinfo/Pacific/Fakaofo create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pytz/zoneinfo/Pacific/Fiji create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pytz/zoneinfo/Pacific/Funafuti create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pytz/zoneinfo/Pacific/Galapagos create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pytz/zoneinfo/Pacific/Gambier create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pytz/zoneinfo/Pacific/Guadalcanal create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pytz/zoneinfo/Pacific/Guam create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pytz/zoneinfo/Pacific/Honolulu create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pytz/zoneinfo/Pacific/Johnston create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pytz/zoneinfo/Pacific/Kanton create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pytz/zoneinfo/Pacific/Kiritimati create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pytz/zoneinfo/Pacific/Kosrae create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pytz/zoneinfo/Pacific/Kwajalein create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pytz/zoneinfo/Pacific/Majuro create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pytz/zoneinfo/Pacific/Marquesas create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pytz/zoneinfo/Pacific/Midway create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pytz/zoneinfo/Pacific/Nauru create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pytz/zoneinfo/Pacific/Niue create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pytz/zoneinfo/Pacific/Norfolk create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pytz/zoneinfo/Pacific/Noumea create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pytz/zoneinfo/Pacific/Pago_Pago create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pytz/zoneinfo/Pacific/Palau create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pytz/zoneinfo/Pacific/Pitcairn create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pytz/zoneinfo/Pacific/Pohnpei create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pytz/zoneinfo/Pacific/Ponape create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pytz/zoneinfo/Pacific/Port_Moresby create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pytz/zoneinfo/Pacific/Rarotonga create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pytz/zoneinfo/Pacific/Saipan create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pytz/zoneinfo/Pacific/Samoa create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pytz/zoneinfo/Pacific/Tahiti create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pytz/zoneinfo/Pacific/Tarawa create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pytz/zoneinfo/Pacific/Tongatapu create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pytz/zoneinfo/Pacific/Truk create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pytz/zoneinfo/Pacific/Wake create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pytz/zoneinfo/Pacific/Wallis create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pytz/zoneinfo/Pacific/Yap create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pytz/zoneinfo/Poland create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pytz/zoneinfo/Portugal create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pytz/zoneinfo/ROC create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pytz/zoneinfo/ROK create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pytz/zoneinfo/Singapore create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pytz/zoneinfo/Turkey create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pytz/zoneinfo/UCT create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pytz/zoneinfo/US/Alaska create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pytz/zoneinfo/US/Aleutian create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pytz/zoneinfo/US/Arizona create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pytz/zoneinfo/US/Central create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pytz/zoneinfo/US/East-Indiana create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pytz/zoneinfo/US/Eastern create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pytz/zoneinfo/US/Hawaii create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pytz/zoneinfo/US/Indiana-Starke create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pytz/zoneinfo/US/Michigan create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pytz/zoneinfo/US/Mountain create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pytz/zoneinfo/US/Pacific create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pytz/zoneinfo/US/Samoa create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pytz/zoneinfo/UTC create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pytz/zoneinfo/Universal create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pytz/zoneinfo/W-SU create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pytz/zoneinfo/WET create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pytz/zoneinfo/Zulu create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pytz/zoneinfo/iso3166.tab create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pytz/zoneinfo/leapseconds create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pytz/zoneinfo/tzdata.zi create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pytz/zoneinfo/zone.tab create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pytz/zoneinfo/zone1970.tab create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/pytz/zoneinfo/zonenow.tab create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/requests-2.32.3.dist-info/INSTALLER create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/requests-2.32.3.dist-info/LICENSE create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/requests-2.32.3.dist-info/METADATA create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/requests-2.32.3.dist-info/RECORD create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/requests-2.32.3.dist-info/REQUESTED create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/requests-2.32.3.dist-info/WHEEL create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/requests-2.32.3.dist-info/top_level.txt create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/requests/__init__.py create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/requests/__pycache__/__init__.cpython-312.pyc create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/requests/__pycache__/__version__.cpython-312.pyc create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/requests/__pycache__/_internal_utils.cpython-312.pyc create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/requests/__pycache__/adapters.cpython-312.pyc create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/requests/__pycache__/api.cpython-312.pyc create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/requests/__pycache__/auth.cpython-312.pyc create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/requests/__pycache__/certs.cpython-312.pyc create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/requests/__pycache__/compat.cpython-312.pyc create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/requests/__pycache__/cookies.cpython-312.pyc create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/requests/__pycache__/exceptions.cpython-312.pyc create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/requests/__pycache__/help.cpython-312.pyc create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/requests/__pycache__/hooks.cpython-312.pyc create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/requests/__pycache__/models.cpython-312.pyc create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/requests/__pycache__/packages.cpython-312.pyc create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/requests/__pycache__/sessions.cpython-312.pyc create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/requests/__pycache__/status_codes.cpython-312.pyc create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/requests/__pycache__/structures.cpython-312.pyc create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/requests/__pycache__/utils.cpython-312.pyc create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/requests/__version__.py create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/requests/_internal_utils.py create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/requests/adapters.py create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/requests/api.py create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/requests/auth.py create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/requests/certs.py create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/requests/compat.py create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/requests/cookies.py create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/requests/exceptions.py create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/requests/help.py create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/requests/hooks.py create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/requests/models.py create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/requests/packages.py create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/requests/sessions.py create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/requests/status_codes.py create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/requests/structures.py create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/requests/utils.py create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/sqlalchemy/__init__.py create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/sqlalchemy/__pycache__/__init__.cpython-312.pyc create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/sqlalchemy/__pycache__/events.cpython-312.pyc create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/sqlalchemy/__pycache__/exc.cpython-312.pyc create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/sqlalchemy/__pycache__/inspection.cpython-312.pyc create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/sqlalchemy/__pycache__/log.cpython-312.pyc create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/sqlalchemy/__pycache__/schema.cpython-312.pyc create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/sqlalchemy/__pycache__/types.cpython-312.pyc create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/sqlalchemy/connectors/__init__.py create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/sqlalchemy/connectors/__pycache__/__init__.cpython-312.pyc create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/sqlalchemy/connectors/__pycache__/aioodbc.cpython-312.pyc create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/sqlalchemy/connectors/__pycache__/asyncio.cpython-312.pyc create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/sqlalchemy/connectors/__pycache__/pyodbc.cpython-312.pyc create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/sqlalchemy/connectors/aioodbc.py create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/sqlalchemy/connectors/asyncio.py create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/sqlalchemy/connectors/pyodbc.py create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/sqlalchemy/cyextension/__init__.py create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/sqlalchemy/cyextension/__pycache__/__init__.cpython-312.pyc create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/sqlalchemy/cyextension/collections.cpython-312-x86_64-linux-gnu.so create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/sqlalchemy/cyextension/collections.pyx create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/sqlalchemy/cyextension/immutabledict.cpython-312-x86_64-linux-gnu.so create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/sqlalchemy/cyextension/immutabledict.pxd create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/sqlalchemy/cyextension/immutabledict.pyx create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/sqlalchemy/cyextension/processors.cpython-312-x86_64-linux-gnu.so create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/sqlalchemy/cyextension/processors.pyx create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/sqlalchemy/cyextension/resultproxy.cpython-312-x86_64-linux-gnu.so create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/sqlalchemy/cyextension/resultproxy.pyx create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/sqlalchemy/cyextension/util.cpython-312-x86_64-linux-gnu.so create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/sqlalchemy/cyextension/util.pyx create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/sqlalchemy/dialects/__init__.py create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/sqlalchemy/dialects/__pycache__/__init__.cpython-312.pyc create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/sqlalchemy/dialects/__pycache__/_typing.cpython-312.pyc create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/sqlalchemy/dialects/_typing.py create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/sqlalchemy/dialects/mssql/__init__.py create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/sqlalchemy/dialects/mssql/__pycache__/__init__.cpython-312.pyc create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/sqlalchemy/dialects/mssql/__pycache__/aioodbc.cpython-312.pyc create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/sqlalchemy/dialects/mssql/__pycache__/base.cpython-312.pyc create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/sqlalchemy/dialects/mssql/__pycache__/information_schema.cpython-312.pyc create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/sqlalchemy/dialects/mssql/__pycache__/json.cpython-312.pyc create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/sqlalchemy/dialects/mssql/__pycache__/provision.cpython-312.pyc create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/sqlalchemy/dialects/mssql/__pycache__/pymssql.cpython-312.pyc create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/sqlalchemy/dialects/mssql/__pycache__/pyodbc.cpython-312.pyc create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/sqlalchemy/dialects/mssql/aioodbc.py create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/sqlalchemy/dialects/mssql/base.py create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/sqlalchemy/dialects/mssql/information_schema.py create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/sqlalchemy/dialects/mssql/json.py create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/sqlalchemy/dialects/mssql/provision.py create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/sqlalchemy/dialects/mssql/pymssql.py create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/sqlalchemy/dialects/mssql/pyodbc.py create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/sqlalchemy/dialects/mysql/__init__.py create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/sqlalchemy/dialects/mysql/__pycache__/__init__.cpython-312.pyc create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/sqlalchemy/dialects/mysql/__pycache__/aiomysql.cpython-312.pyc create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/sqlalchemy/dialects/mysql/__pycache__/asyncmy.cpython-312.pyc create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/sqlalchemy/dialects/mysql/__pycache__/base.cpython-312.pyc create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/sqlalchemy/dialects/mysql/__pycache__/cymysql.cpython-312.pyc create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/sqlalchemy/dialects/mysql/__pycache__/dml.cpython-312.pyc create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/sqlalchemy/dialects/mysql/__pycache__/enumerated.cpython-312.pyc create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/sqlalchemy/dialects/mysql/__pycache__/expression.cpython-312.pyc create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/sqlalchemy/dialects/mysql/__pycache__/json.cpython-312.pyc create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/sqlalchemy/dialects/mysql/__pycache__/mariadb.cpython-312.pyc create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/sqlalchemy/dialects/mysql/__pycache__/mariadbconnector.cpython-312.pyc create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/sqlalchemy/dialects/mysql/__pycache__/mysqlconnector.cpython-312.pyc create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/sqlalchemy/dialects/mysql/__pycache__/mysqldb.cpython-312.pyc create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/sqlalchemy/dialects/mysql/__pycache__/provision.cpython-312.pyc create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/sqlalchemy/dialects/mysql/__pycache__/pymysql.cpython-312.pyc create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/sqlalchemy/dialects/mysql/__pycache__/pyodbc.cpython-312.pyc create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/sqlalchemy/dialects/mysql/__pycache__/reflection.cpython-312.pyc create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/sqlalchemy/dialects/mysql/__pycache__/reserved_words.cpython-312.pyc create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/sqlalchemy/dialects/mysql/__pycache__/types.cpython-312.pyc create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/sqlalchemy/dialects/mysql/aiomysql.py create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/sqlalchemy/dialects/mysql/asyncmy.py create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/sqlalchemy/dialects/mysql/base.py create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/sqlalchemy/dialects/mysql/cymysql.py create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/sqlalchemy/dialects/mysql/dml.py create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/sqlalchemy/dialects/mysql/enumerated.py create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/sqlalchemy/dialects/mysql/expression.py create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/sqlalchemy/dialects/mysql/json.py create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/sqlalchemy/dialects/mysql/mariadb.py create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/sqlalchemy/dialects/mysql/mariadbconnector.py create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/sqlalchemy/dialects/mysql/mysqlconnector.py create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/sqlalchemy/dialects/mysql/mysqldb.py create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/sqlalchemy/dialects/mysql/provision.py create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/sqlalchemy/dialects/mysql/pymysql.py create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/sqlalchemy/dialects/mysql/pyodbc.py create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/sqlalchemy/dialects/mysql/reflection.py create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/sqlalchemy/dialects/mysql/reserved_words.py create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/sqlalchemy/dialects/mysql/types.py create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/sqlalchemy/dialects/oracle/__init__.py create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/sqlalchemy/dialects/oracle/__pycache__/__init__.cpython-312.pyc create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/sqlalchemy/dialects/oracle/__pycache__/base.cpython-312.pyc create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/sqlalchemy/dialects/oracle/__pycache__/cx_oracle.cpython-312.pyc create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/sqlalchemy/dialects/oracle/__pycache__/dictionary.cpython-312.pyc create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/sqlalchemy/dialects/oracle/__pycache__/oracledb.cpython-312.pyc create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/sqlalchemy/dialects/oracle/__pycache__/provision.cpython-312.pyc create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/sqlalchemy/dialects/oracle/__pycache__/types.cpython-312.pyc create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/sqlalchemy/dialects/oracle/base.py create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/sqlalchemy/dialects/oracle/cx_oracle.py create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/sqlalchemy/dialects/oracle/dictionary.py create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/sqlalchemy/dialects/oracle/oracledb.py create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/sqlalchemy/dialects/oracle/provision.py create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/sqlalchemy/dialects/oracle/types.py create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/sqlalchemy/dialects/postgresql/__init__.py create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/sqlalchemy/dialects/postgresql/__pycache__/__init__.cpython-312.pyc create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/sqlalchemy/dialects/postgresql/__pycache__/_psycopg_common.cpython-312.pyc create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/sqlalchemy/dialects/postgresql/__pycache__/array.cpython-312.pyc create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/sqlalchemy/dialects/postgresql/__pycache__/asyncpg.cpython-312.pyc create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/sqlalchemy/dialects/postgresql/__pycache__/base.cpython-312.pyc create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/sqlalchemy/dialects/postgresql/__pycache__/dml.cpython-312.pyc create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/sqlalchemy/dialects/postgresql/__pycache__/ext.cpython-312.pyc create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/sqlalchemy/dialects/postgresql/__pycache__/hstore.cpython-312.pyc create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/sqlalchemy/dialects/postgresql/__pycache__/json.cpython-312.pyc create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/sqlalchemy/dialects/postgresql/__pycache__/named_types.cpython-312.pyc create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/sqlalchemy/dialects/postgresql/__pycache__/operators.cpython-312.pyc create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/sqlalchemy/dialects/postgresql/__pycache__/pg8000.cpython-312.pyc create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/sqlalchemy/dialects/postgresql/__pycache__/pg_catalog.cpython-312.pyc create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/sqlalchemy/dialects/postgresql/__pycache__/provision.cpython-312.pyc create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/sqlalchemy/dialects/postgresql/__pycache__/psycopg.cpython-312.pyc create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/sqlalchemy/dialects/postgresql/__pycache__/psycopg2.cpython-312.pyc create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/sqlalchemy/dialects/postgresql/__pycache__/psycopg2cffi.cpython-312.pyc create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/sqlalchemy/dialects/postgresql/__pycache__/ranges.cpython-312.pyc create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/sqlalchemy/dialects/postgresql/__pycache__/types.cpython-312.pyc create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/sqlalchemy/dialects/postgresql/_psycopg_common.py create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/sqlalchemy/dialects/postgresql/array.py create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/sqlalchemy/dialects/postgresql/asyncpg.py create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/sqlalchemy/dialects/postgresql/base.py create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/sqlalchemy/dialects/postgresql/dml.py create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/sqlalchemy/dialects/postgresql/ext.py create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/sqlalchemy/dialects/postgresql/hstore.py create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/sqlalchemy/dialects/postgresql/json.py create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/sqlalchemy/dialects/postgresql/named_types.py create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/sqlalchemy/dialects/postgresql/operators.py create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/sqlalchemy/dialects/postgresql/pg8000.py create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/sqlalchemy/dialects/postgresql/pg_catalog.py create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/sqlalchemy/dialects/postgresql/provision.py create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/sqlalchemy/dialects/postgresql/psycopg.py create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/sqlalchemy/dialects/postgresql/psycopg2.py create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/sqlalchemy/dialects/postgresql/psycopg2cffi.py create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/sqlalchemy/dialects/postgresql/ranges.py create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/sqlalchemy/dialects/postgresql/types.py create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/sqlalchemy/dialects/sqlite/__init__.py create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/sqlalchemy/dialects/sqlite/__pycache__/__init__.cpython-312.pyc create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/sqlalchemy/dialects/sqlite/__pycache__/aiosqlite.cpython-312.pyc create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/sqlalchemy/dialects/sqlite/__pycache__/base.cpython-312.pyc create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/sqlalchemy/dialects/sqlite/__pycache__/dml.cpython-312.pyc create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/sqlalchemy/dialects/sqlite/__pycache__/json.cpython-312.pyc create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/sqlalchemy/dialects/sqlite/__pycache__/provision.cpython-312.pyc create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/sqlalchemy/dialects/sqlite/__pycache__/pysqlcipher.cpython-312.pyc create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/sqlalchemy/dialects/sqlite/__pycache__/pysqlite.cpython-312.pyc create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/sqlalchemy/dialects/sqlite/aiosqlite.py create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/sqlalchemy/dialects/sqlite/base.py create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/sqlalchemy/dialects/sqlite/dml.py create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/sqlalchemy/dialects/sqlite/json.py create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/sqlalchemy/dialects/sqlite/provision.py create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/sqlalchemy/dialects/sqlite/pysqlcipher.py create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/sqlalchemy/dialects/sqlite/pysqlite.py create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/sqlalchemy/dialects/type_migration_guidelines.txt create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/sqlalchemy/engine/__init__.py create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/sqlalchemy/engine/__pycache__/__init__.cpython-312.pyc create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/sqlalchemy/engine/__pycache__/_py_processors.cpython-312.pyc create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/sqlalchemy/engine/__pycache__/_py_row.cpython-312.pyc create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/sqlalchemy/engine/__pycache__/_py_util.cpython-312.pyc create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/sqlalchemy/engine/__pycache__/base.cpython-312.pyc create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/sqlalchemy/engine/__pycache__/characteristics.cpython-312.pyc create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/sqlalchemy/engine/__pycache__/create.cpython-312.pyc create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/sqlalchemy/engine/__pycache__/cursor.cpython-312.pyc create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/sqlalchemy/engine/__pycache__/default.cpython-312.pyc create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/sqlalchemy/engine/__pycache__/events.cpython-312.pyc create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/sqlalchemy/engine/__pycache__/interfaces.cpython-312.pyc create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/sqlalchemy/engine/__pycache__/mock.cpython-312.pyc create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/sqlalchemy/engine/__pycache__/processors.cpython-312.pyc create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/sqlalchemy/engine/__pycache__/reflection.cpython-312.pyc create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/sqlalchemy/engine/__pycache__/result.cpython-312.pyc create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/sqlalchemy/engine/__pycache__/row.cpython-312.pyc create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/sqlalchemy/engine/__pycache__/strategies.cpython-312.pyc create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/sqlalchemy/engine/__pycache__/url.cpython-312.pyc create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/sqlalchemy/engine/__pycache__/util.cpython-312.pyc create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/sqlalchemy/engine/_py_processors.py create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/sqlalchemy/engine/_py_row.py create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/sqlalchemy/engine/_py_util.py create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/sqlalchemy/engine/base.py create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/sqlalchemy/engine/characteristics.py create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/sqlalchemy/engine/create.py create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/sqlalchemy/engine/cursor.py create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/sqlalchemy/engine/default.py create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/sqlalchemy/engine/events.py create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/sqlalchemy/engine/interfaces.py create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/sqlalchemy/engine/mock.py create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/sqlalchemy/engine/processors.py create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/sqlalchemy/engine/reflection.py create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/sqlalchemy/engine/result.py create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/sqlalchemy/engine/row.py create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/sqlalchemy/engine/strategies.py create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/sqlalchemy/engine/url.py create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/sqlalchemy/engine/util.py create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/sqlalchemy/event/__init__.py create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/sqlalchemy/event/__pycache__/__init__.cpython-312.pyc create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/sqlalchemy/event/__pycache__/api.cpython-312.pyc create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/sqlalchemy/event/__pycache__/attr.cpython-312.pyc create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/sqlalchemy/event/__pycache__/base.cpython-312.pyc create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/sqlalchemy/event/__pycache__/legacy.cpython-312.pyc create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/sqlalchemy/event/__pycache__/registry.cpython-312.pyc create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/sqlalchemy/event/api.py create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/sqlalchemy/event/attr.py create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/sqlalchemy/event/base.py create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/sqlalchemy/event/legacy.py create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/sqlalchemy/event/registry.py create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/sqlalchemy/events.py create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/sqlalchemy/exc.py create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/sqlalchemy/ext/__init__.py create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/sqlalchemy/ext/__pycache__/__init__.cpython-312.pyc create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/sqlalchemy/ext/__pycache__/associationproxy.cpython-312.pyc create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/sqlalchemy/ext/__pycache__/automap.cpython-312.pyc create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/sqlalchemy/ext/__pycache__/baked.cpython-312.pyc create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/sqlalchemy/ext/__pycache__/compiler.cpython-312.pyc create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/sqlalchemy/ext/__pycache__/horizontal_shard.cpython-312.pyc create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/sqlalchemy/ext/__pycache__/hybrid.cpython-312.pyc create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/sqlalchemy/ext/__pycache__/indexable.cpython-312.pyc create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/sqlalchemy/ext/__pycache__/instrumentation.cpython-312.pyc create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/sqlalchemy/ext/__pycache__/mutable.cpython-312.pyc create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/sqlalchemy/ext/__pycache__/orderinglist.cpython-312.pyc create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/sqlalchemy/ext/__pycache__/serializer.cpython-312.pyc create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/sqlalchemy/ext/associationproxy.py create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/sqlalchemy/ext/asyncio/__init__.py create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/sqlalchemy/ext/asyncio/__pycache__/__init__.cpython-312.pyc create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/sqlalchemy/ext/asyncio/__pycache__/base.cpython-312.pyc create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/sqlalchemy/ext/asyncio/__pycache__/engine.cpython-312.pyc create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/sqlalchemy/ext/asyncio/__pycache__/exc.cpython-312.pyc create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/sqlalchemy/ext/asyncio/__pycache__/result.cpython-312.pyc create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/sqlalchemy/ext/asyncio/__pycache__/scoping.cpython-312.pyc create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/sqlalchemy/ext/asyncio/__pycache__/session.cpython-312.pyc create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/sqlalchemy/ext/asyncio/base.py create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/sqlalchemy/ext/asyncio/engine.py create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/sqlalchemy/ext/asyncio/exc.py create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/sqlalchemy/ext/asyncio/result.py create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/sqlalchemy/ext/asyncio/scoping.py create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/sqlalchemy/ext/asyncio/session.py create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/sqlalchemy/ext/automap.py create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/sqlalchemy/ext/baked.py create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/sqlalchemy/ext/compiler.py create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/sqlalchemy/ext/declarative/__init__.py create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/sqlalchemy/ext/declarative/__pycache__/__init__.cpython-312.pyc create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/sqlalchemy/ext/declarative/__pycache__/extensions.cpython-312.pyc create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/sqlalchemy/ext/declarative/extensions.py create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/sqlalchemy/ext/horizontal_shard.py create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/sqlalchemy/ext/hybrid.py create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/sqlalchemy/ext/indexable.py create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/sqlalchemy/ext/instrumentation.py create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/sqlalchemy/ext/mutable.py create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/sqlalchemy/ext/mypy/__init__.py create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/sqlalchemy/ext/mypy/__pycache__/__init__.cpython-312.pyc create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/sqlalchemy/ext/mypy/__pycache__/apply.cpython-312.pyc create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/sqlalchemy/ext/mypy/__pycache__/decl_class.cpython-312.pyc create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/sqlalchemy/ext/mypy/__pycache__/infer.cpython-312.pyc create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/sqlalchemy/ext/mypy/__pycache__/names.cpython-312.pyc create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/sqlalchemy/ext/mypy/__pycache__/plugin.cpython-312.pyc create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/sqlalchemy/ext/mypy/__pycache__/util.cpython-312.pyc create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/sqlalchemy/ext/mypy/apply.py create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/sqlalchemy/ext/mypy/decl_class.py create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/sqlalchemy/ext/mypy/infer.py create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/sqlalchemy/ext/mypy/names.py create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/sqlalchemy/ext/mypy/plugin.py create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/sqlalchemy/ext/mypy/util.py create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/sqlalchemy/ext/orderinglist.py create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/sqlalchemy/ext/serializer.py create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/sqlalchemy/future/__init__.py create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/sqlalchemy/future/__pycache__/__init__.cpython-312.pyc create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/sqlalchemy/future/__pycache__/engine.cpython-312.pyc create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/sqlalchemy/future/engine.py create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/sqlalchemy/inspection.py create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/sqlalchemy/log.py create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/sqlalchemy/orm/__init__.py create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/sqlalchemy/orm/__pycache__/__init__.cpython-312.pyc create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/sqlalchemy/orm/__pycache__/_orm_constructors.cpython-312.pyc create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/sqlalchemy/orm/__pycache__/_typing.cpython-312.pyc create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/sqlalchemy/orm/__pycache__/attributes.cpython-312.pyc create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/sqlalchemy/orm/__pycache__/base.cpython-312.pyc create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/sqlalchemy/orm/__pycache__/bulk_persistence.cpython-312.pyc create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/sqlalchemy/orm/__pycache__/clsregistry.cpython-312.pyc create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/sqlalchemy/orm/__pycache__/collections.cpython-312.pyc create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/sqlalchemy/orm/__pycache__/context.cpython-312.pyc create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/sqlalchemy/orm/__pycache__/decl_api.cpython-312.pyc create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/sqlalchemy/orm/__pycache__/decl_base.cpython-312.pyc create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/sqlalchemy/orm/__pycache__/dependency.cpython-312.pyc create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/sqlalchemy/orm/__pycache__/descriptor_props.cpython-312.pyc create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/sqlalchemy/orm/__pycache__/dynamic.cpython-312.pyc create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/sqlalchemy/orm/__pycache__/evaluator.cpython-312.pyc create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/sqlalchemy/orm/__pycache__/events.cpython-312.pyc create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/sqlalchemy/orm/__pycache__/exc.cpython-312.pyc create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/sqlalchemy/orm/__pycache__/identity.cpython-312.pyc create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/sqlalchemy/orm/__pycache__/instrumentation.cpython-312.pyc create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/sqlalchemy/orm/__pycache__/interfaces.cpython-312.pyc create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/sqlalchemy/orm/__pycache__/loading.cpython-312.pyc create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/sqlalchemy/orm/__pycache__/mapped_collection.cpython-312.pyc create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/sqlalchemy/orm/__pycache__/mapper.cpython-312.pyc create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/sqlalchemy/orm/__pycache__/path_registry.cpython-312.pyc create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/sqlalchemy/orm/__pycache__/persistence.cpython-312.pyc create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/sqlalchemy/orm/__pycache__/properties.cpython-312.pyc create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/sqlalchemy/orm/__pycache__/query.cpython-312.pyc create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/sqlalchemy/orm/__pycache__/relationships.cpython-312.pyc create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/sqlalchemy/orm/__pycache__/scoping.cpython-312.pyc create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/sqlalchemy/orm/__pycache__/session.cpython-312.pyc create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/sqlalchemy/orm/__pycache__/state.cpython-312.pyc create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/sqlalchemy/orm/__pycache__/state_changes.cpython-312.pyc create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/sqlalchemy/orm/__pycache__/strategies.cpython-312.pyc create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/sqlalchemy/orm/__pycache__/strategy_options.cpython-312.pyc create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/sqlalchemy/orm/__pycache__/sync.cpython-312.pyc create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/sqlalchemy/orm/__pycache__/unitofwork.cpython-312.pyc create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/sqlalchemy/orm/__pycache__/util.cpython-312.pyc create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/sqlalchemy/orm/__pycache__/writeonly.cpython-312.pyc create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/sqlalchemy/orm/_orm_constructors.py create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/sqlalchemy/orm/_typing.py create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/sqlalchemy/orm/attributes.py create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/sqlalchemy/orm/base.py create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/sqlalchemy/orm/bulk_persistence.py create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/sqlalchemy/orm/clsregistry.py create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/sqlalchemy/orm/collections.py create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/sqlalchemy/orm/context.py create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/sqlalchemy/orm/decl_api.py create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/sqlalchemy/orm/decl_base.py create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/sqlalchemy/orm/dependency.py create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/sqlalchemy/orm/descriptor_props.py create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/sqlalchemy/orm/dynamic.py create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/sqlalchemy/orm/evaluator.py create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/sqlalchemy/orm/events.py create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/sqlalchemy/orm/exc.py create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/sqlalchemy/orm/identity.py create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/sqlalchemy/orm/instrumentation.py create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/sqlalchemy/orm/interfaces.py create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/sqlalchemy/orm/loading.py create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/sqlalchemy/orm/mapped_collection.py create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/sqlalchemy/orm/mapper.py create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/sqlalchemy/orm/path_registry.py create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/sqlalchemy/orm/persistence.py create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/sqlalchemy/orm/properties.py create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/sqlalchemy/orm/query.py create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/sqlalchemy/orm/relationships.py create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/sqlalchemy/orm/scoping.py create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/sqlalchemy/orm/session.py create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/sqlalchemy/orm/state.py create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/sqlalchemy/orm/state_changes.py create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/sqlalchemy/orm/strategies.py create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/sqlalchemy/orm/strategy_options.py create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/sqlalchemy/orm/sync.py create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/sqlalchemy/orm/unitofwork.py create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/sqlalchemy/orm/util.py create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/sqlalchemy/orm/writeonly.py create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/sqlalchemy/pool/__init__.py create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/sqlalchemy/pool/__pycache__/__init__.cpython-312.pyc create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/sqlalchemy/pool/__pycache__/base.cpython-312.pyc create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/sqlalchemy/pool/__pycache__/events.cpython-312.pyc create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/sqlalchemy/pool/__pycache__/impl.cpython-312.pyc create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/sqlalchemy/pool/base.py create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/sqlalchemy/pool/events.py create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/sqlalchemy/pool/impl.py create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/sqlalchemy/py.typed create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/sqlalchemy/schema.py create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/sqlalchemy/sql/__init__.py create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/sqlalchemy/sql/__pycache__/__init__.cpython-312.pyc create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/sqlalchemy/sql/__pycache__/_dml_constructors.cpython-312.pyc create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/sqlalchemy/sql/__pycache__/_elements_constructors.cpython-312.pyc create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/sqlalchemy/sql/__pycache__/_orm_types.cpython-312.pyc create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/sqlalchemy/sql/__pycache__/_py_util.cpython-312.pyc create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/sqlalchemy/sql/__pycache__/_selectable_constructors.cpython-312.pyc create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/sqlalchemy/sql/__pycache__/_typing.cpython-312.pyc create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/sqlalchemy/sql/__pycache__/annotation.cpython-312.pyc create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/sqlalchemy/sql/__pycache__/base.cpython-312.pyc create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/sqlalchemy/sql/__pycache__/cache_key.cpython-312.pyc create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/sqlalchemy/sql/__pycache__/coercions.cpython-312.pyc create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/sqlalchemy/sql/__pycache__/compiler.cpython-312.pyc create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/sqlalchemy/sql/__pycache__/crud.cpython-312.pyc create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/sqlalchemy/sql/__pycache__/ddl.cpython-312.pyc create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/sqlalchemy/sql/__pycache__/default_comparator.cpython-312.pyc create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/sqlalchemy/sql/__pycache__/dml.cpython-312.pyc create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/sqlalchemy/sql/__pycache__/elements.cpython-312.pyc create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/sqlalchemy/sql/__pycache__/events.cpython-312.pyc create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/sqlalchemy/sql/__pycache__/expression.cpython-312.pyc create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/sqlalchemy/sql/__pycache__/functions.cpython-312.pyc create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/sqlalchemy/sql/__pycache__/lambdas.cpython-312.pyc create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/sqlalchemy/sql/__pycache__/naming.cpython-312.pyc create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/sqlalchemy/sql/__pycache__/operators.cpython-312.pyc create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/sqlalchemy/sql/__pycache__/roles.cpython-312.pyc create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/sqlalchemy/sql/__pycache__/schema.cpython-312.pyc create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/sqlalchemy/sql/__pycache__/selectable.cpython-312.pyc create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/sqlalchemy/sql/__pycache__/sqltypes.cpython-312.pyc create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/sqlalchemy/sql/__pycache__/traversals.cpython-312.pyc create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/sqlalchemy/sql/__pycache__/type_api.cpython-312.pyc create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/sqlalchemy/sql/__pycache__/util.cpython-312.pyc create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/sqlalchemy/sql/__pycache__/visitors.cpython-312.pyc create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/sqlalchemy/sql/_dml_constructors.py create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/sqlalchemy/sql/_elements_constructors.py create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/sqlalchemy/sql/_orm_types.py create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/sqlalchemy/sql/_py_util.py create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/sqlalchemy/sql/_selectable_constructors.py create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/sqlalchemy/sql/_typing.py create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/sqlalchemy/sql/annotation.py create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/sqlalchemy/sql/base.py create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/sqlalchemy/sql/cache_key.py create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/sqlalchemy/sql/coercions.py create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/sqlalchemy/sql/compiler.py create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/sqlalchemy/sql/crud.py create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/sqlalchemy/sql/ddl.py create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/sqlalchemy/sql/default_comparator.py create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/sqlalchemy/sql/dml.py create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/sqlalchemy/sql/elements.py create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/sqlalchemy/sql/events.py create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/sqlalchemy/sql/expression.py create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/sqlalchemy/sql/functions.py create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/sqlalchemy/sql/lambdas.py create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/sqlalchemy/sql/naming.py create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/sqlalchemy/sql/operators.py create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/sqlalchemy/sql/roles.py create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/sqlalchemy/sql/schema.py create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/sqlalchemy/sql/selectable.py create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/sqlalchemy/sql/sqltypes.py create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/sqlalchemy/sql/traversals.py create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/sqlalchemy/sql/type_api.py create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/sqlalchemy/sql/util.py create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/sqlalchemy/sql/visitors.py create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/sqlalchemy/testing/__init__.py create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/sqlalchemy/testing/__pycache__/__init__.cpython-312.pyc create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/sqlalchemy/testing/__pycache__/assertions.cpython-312.pyc create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/sqlalchemy/testing/__pycache__/assertsql.cpython-312.pyc create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/sqlalchemy/testing/__pycache__/asyncio.cpython-312.pyc create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/sqlalchemy/testing/__pycache__/config.cpython-312.pyc create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/sqlalchemy/testing/__pycache__/engines.cpython-312.pyc create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/sqlalchemy/testing/__pycache__/entities.cpython-312.pyc create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/sqlalchemy/testing/__pycache__/exclusions.cpython-312.pyc create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/sqlalchemy/testing/__pycache__/pickleable.cpython-312.pyc create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/sqlalchemy/testing/__pycache__/profiling.cpython-312.pyc create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/sqlalchemy/testing/__pycache__/provision.cpython-312.pyc create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/sqlalchemy/testing/__pycache__/requirements.cpython-312.pyc create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/sqlalchemy/testing/__pycache__/schema.cpython-312.pyc create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/sqlalchemy/testing/__pycache__/util.cpython-312.pyc create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/sqlalchemy/testing/__pycache__/warnings.cpython-312.pyc create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/sqlalchemy/testing/assertions.py create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/sqlalchemy/testing/assertsql.py create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/sqlalchemy/testing/asyncio.py create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/sqlalchemy/testing/config.py create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/sqlalchemy/testing/engines.py create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/sqlalchemy/testing/entities.py create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/sqlalchemy/testing/exclusions.py create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/sqlalchemy/testing/fixtures/__init__.py create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/sqlalchemy/testing/fixtures/__pycache__/__init__.cpython-312.pyc create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/sqlalchemy/testing/fixtures/__pycache__/base.cpython-312.pyc create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/sqlalchemy/testing/fixtures/__pycache__/mypy.cpython-312.pyc create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/sqlalchemy/testing/fixtures/__pycache__/orm.cpython-312.pyc create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/sqlalchemy/testing/fixtures/__pycache__/sql.cpython-312.pyc create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/sqlalchemy/testing/fixtures/base.py create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/sqlalchemy/testing/fixtures/mypy.py create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/sqlalchemy/testing/fixtures/orm.py create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/sqlalchemy/testing/fixtures/sql.py create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/sqlalchemy/testing/pickleable.py create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/sqlalchemy/testing/plugin/__init__.py create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/sqlalchemy/testing/plugin/__pycache__/__init__.cpython-312.pyc create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/sqlalchemy/testing/plugin/__pycache__/bootstrap.cpython-312.pyc create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/sqlalchemy/testing/plugin/__pycache__/plugin_base.cpython-312.pyc create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/sqlalchemy/testing/plugin/__pycache__/pytestplugin.cpython-312.pyc create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/sqlalchemy/testing/plugin/bootstrap.py create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/sqlalchemy/testing/plugin/plugin_base.py create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/sqlalchemy/testing/plugin/pytestplugin.py create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/sqlalchemy/testing/profiling.py create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/sqlalchemy/testing/provision.py create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/sqlalchemy/testing/requirements.py create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/sqlalchemy/testing/schema.py create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/sqlalchemy/testing/suite/__init__.py create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/sqlalchemy/testing/suite/__pycache__/__init__.cpython-312.pyc create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/sqlalchemy/testing/suite/__pycache__/test_cte.cpython-312.pyc create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/sqlalchemy/testing/suite/__pycache__/test_ddl.cpython-312.pyc create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/sqlalchemy/testing/suite/__pycache__/test_deprecations.cpython-312.pyc create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/sqlalchemy/testing/suite/__pycache__/test_dialect.cpython-312.pyc create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/sqlalchemy/testing/suite/__pycache__/test_insert.cpython-312.pyc create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/sqlalchemy/testing/suite/__pycache__/test_reflection.cpython-312.pyc create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/sqlalchemy/testing/suite/__pycache__/test_results.cpython-312.pyc create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/sqlalchemy/testing/suite/__pycache__/test_rowcount.cpython-312.pyc create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/sqlalchemy/testing/suite/__pycache__/test_select.cpython-312.pyc create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/sqlalchemy/testing/suite/__pycache__/test_sequence.cpython-312.pyc create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/sqlalchemy/testing/suite/__pycache__/test_types.cpython-312.pyc create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/sqlalchemy/testing/suite/__pycache__/test_unicode_ddl.cpython-312.pyc create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/sqlalchemy/testing/suite/__pycache__/test_update_delete.cpython-312.pyc create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/sqlalchemy/testing/suite/test_cte.py create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/sqlalchemy/testing/suite/test_ddl.py create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/sqlalchemy/testing/suite/test_deprecations.py create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/sqlalchemy/testing/suite/test_dialect.py create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/sqlalchemy/testing/suite/test_insert.py create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/sqlalchemy/testing/suite/test_reflection.py create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/sqlalchemy/testing/suite/test_results.py create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/sqlalchemy/testing/suite/test_rowcount.py create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/sqlalchemy/testing/suite/test_select.py create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/sqlalchemy/testing/suite/test_sequence.py create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/sqlalchemy/testing/suite/test_types.py create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/sqlalchemy/testing/suite/test_unicode_ddl.py create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/sqlalchemy/testing/suite/test_update_delete.py create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/sqlalchemy/testing/util.py create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/sqlalchemy/testing/warnings.py create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/sqlalchemy/types.py create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/sqlalchemy/util/__init__.py create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/sqlalchemy/util/__pycache__/__init__.cpython-312.pyc create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/sqlalchemy/util/__pycache__/_collections.cpython-312.pyc create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/sqlalchemy/util/__pycache__/_concurrency_py3k.cpython-312.pyc create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/sqlalchemy/util/__pycache__/_has_cy.cpython-312.pyc create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/sqlalchemy/util/__pycache__/_py_collections.cpython-312.pyc create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/sqlalchemy/util/__pycache__/compat.cpython-312.pyc create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/sqlalchemy/util/__pycache__/concurrency.cpython-312.pyc create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/sqlalchemy/util/__pycache__/deprecations.cpython-312.pyc create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/sqlalchemy/util/__pycache__/langhelpers.cpython-312.pyc create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/sqlalchemy/util/__pycache__/preloaded.cpython-312.pyc create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/sqlalchemy/util/__pycache__/queue.cpython-312.pyc create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/sqlalchemy/util/__pycache__/tool_support.cpython-312.pyc create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/sqlalchemy/util/__pycache__/topological.cpython-312.pyc create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/sqlalchemy/util/__pycache__/typing.cpython-312.pyc create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/sqlalchemy/util/_collections.py create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/sqlalchemy/util/_concurrency_py3k.py create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/sqlalchemy/util/_has_cy.py create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/sqlalchemy/util/_py_collections.py create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/sqlalchemy/util/compat.py create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/sqlalchemy/util/concurrency.py create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/sqlalchemy/util/deprecations.py create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/sqlalchemy/util/langhelpers.py create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/sqlalchemy/util/preloaded.py create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/sqlalchemy/util/queue.py create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/sqlalchemy/util/tool_support.py create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/sqlalchemy/util/topological.py create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/sqlalchemy/util/typing.py create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/sqlparse-0.5.3.dist-info/INSTALLER create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/sqlparse-0.5.3.dist-info/METADATA create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/sqlparse-0.5.3.dist-info/RECORD create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/sqlparse-0.5.3.dist-info/WHEEL create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/sqlparse-0.5.3.dist-info/entry_points.txt create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/sqlparse-0.5.3.dist-info/licenses/AUTHORS create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/sqlparse-0.5.3.dist-info/licenses/LICENSE create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/sqlparse/__init__.py create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/sqlparse/__main__.py create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/sqlparse/__pycache__/__init__.cpython-312.pyc create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/sqlparse/__pycache__/__main__.cpython-312.pyc create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/sqlparse/__pycache__/cli.cpython-312.pyc create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/sqlparse/__pycache__/exceptions.cpython-312.pyc create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/sqlparse/__pycache__/formatter.cpython-312.pyc create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/sqlparse/__pycache__/keywords.cpython-312.pyc create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/sqlparse/__pycache__/lexer.cpython-312.pyc create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/sqlparse/__pycache__/sql.cpython-312.pyc create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/sqlparse/__pycache__/tokens.cpython-312.pyc create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/sqlparse/__pycache__/utils.cpython-312.pyc create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/sqlparse/cli.py create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/sqlparse/engine/__init__.py create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/sqlparse/engine/__pycache__/__init__.cpython-312.pyc create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/sqlparse/engine/__pycache__/filter_stack.cpython-312.pyc create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/sqlparse/engine/__pycache__/grouping.cpython-312.pyc create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/sqlparse/engine/__pycache__/statement_splitter.cpython-312.pyc create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/sqlparse/engine/filter_stack.py create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/sqlparse/engine/grouping.py create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/sqlparse/engine/statement_splitter.py create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/sqlparse/exceptions.py create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/sqlparse/filters/__init__.py create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/sqlparse/filters/__pycache__/__init__.cpython-312.pyc create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/sqlparse/filters/__pycache__/aligned_indent.cpython-312.pyc create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/sqlparse/filters/__pycache__/others.cpython-312.pyc create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/sqlparse/filters/__pycache__/output.cpython-312.pyc create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/sqlparse/filters/__pycache__/reindent.cpython-312.pyc create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/sqlparse/filters/__pycache__/right_margin.cpython-312.pyc create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/sqlparse/filters/__pycache__/tokens.cpython-312.pyc create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/sqlparse/filters/aligned_indent.py create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/sqlparse/filters/others.py create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/sqlparse/filters/output.py create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/sqlparse/filters/reindent.py create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/sqlparse/filters/right_margin.py create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/sqlparse/filters/tokens.py create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/sqlparse/formatter.py create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/sqlparse/keywords.py create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/sqlparse/lexer.py create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/sqlparse/sql.py create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/sqlparse/tokens.py create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/sqlparse/utils.py create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/termcolor-2.5.0.dist-info/INSTALLER create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/termcolor-2.5.0.dist-info/METADATA create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/termcolor-2.5.0.dist-info/RECORD create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/termcolor-2.5.0.dist-info/WHEEL create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/termcolor-2.5.0.dist-info/licenses/COPYING.txt create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/termcolor/__init__.py create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/termcolor/__main__.py create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/termcolor/__pycache__/__init__.cpython-312.pyc create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/termcolor/__pycache__/__main__.cpython-312.pyc create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/termcolor/__pycache__/_types.cpython-312.pyc create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/termcolor/__pycache__/termcolor.cpython-312.pyc create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/termcolor/_types.py create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/termcolor/py.typed create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/termcolor/termcolor.py create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/typing_extensions-4.12.2.dist-info/INSTALLER create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/typing_extensions-4.12.2.dist-info/LICENSE create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/typing_extensions-4.12.2.dist-info/METADATA create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/typing_extensions-4.12.2.dist-info/RECORD create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/typing_extensions-4.12.2.dist-info/WHEEL create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/typing_extensions.py create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/urllib3-2.2.3.dist-info/INSTALLER create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/urllib3-2.2.3.dist-info/METADATA create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/urllib3-2.2.3.dist-info/RECORD create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/urllib3-2.2.3.dist-info/WHEEL create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/urllib3-2.2.3.dist-info/licenses/LICENSE.txt create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/urllib3/__init__.py create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/urllib3/__pycache__/__init__.cpython-312.pyc create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/urllib3/__pycache__/_base_connection.cpython-312.pyc create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/urllib3/__pycache__/_collections.cpython-312.pyc create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/urllib3/__pycache__/_request_methods.cpython-312.pyc create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/urllib3/__pycache__/_version.cpython-312.pyc create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/urllib3/__pycache__/connection.cpython-312.pyc create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/urllib3/__pycache__/connectionpool.cpython-312.pyc create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/urllib3/__pycache__/exceptions.cpython-312.pyc create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/urllib3/__pycache__/fields.cpython-312.pyc create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/urllib3/__pycache__/filepost.cpython-312.pyc create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/urllib3/__pycache__/poolmanager.cpython-312.pyc create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/urllib3/__pycache__/response.cpython-312.pyc create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/urllib3/_base_connection.py create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/urllib3/_collections.py create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/urllib3/_request_methods.py create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/urllib3/_version.py create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/urllib3/connection.py create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/urllib3/connectionpool.py create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/urllib3/contrib/__init__.py create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/urllib3/contrib/__pycache__/__init__.cpython-312.pyc create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/urllib3/contrib/__pycache__/pyopenssl.cpython-312.pyc create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/urllib3/contrib/__pycache__/socks.cpython-312.pyc create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/urllib3/contrib/emscripten/__init__.py create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/urllib3/contrib/emscripten/__pycache__/__init__.cpython-312.pyc create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/urllib3/contrib/emscripten/__pycache__/connection.cpython-312.pyc create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/urllib3/contrib/emscripten/__pycache__/fetch.cpython-312.pyc create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/urllib3/contrib/emscripten/__pycache__/request.cpython-312.pyc create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/urllib3/contrib/emscripten/__pycache__/response.cpython-312.pyc create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/urllib3/contrib/emscripten/connection.py create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/urllib3/contrib/emscripten/emscripten_fetch_worker.js create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/urllib3/contrib/emscripten/fetch.py create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/urllib3/contrib/emscripten/request.py create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/urllib3/contrib/emscripten/response.py create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/urllib3/contrib/pyopenssl.py create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/urllib3/contrib/socks.py create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/urllib3/exceptions.py create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/urllib3/fields.py create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/urllib3/filepost.py create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/urllib3/http2/__init__.py create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/urllib3/http2/__pycache__/__init__.cpython-312.pyc create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/urllib3/http2/__pycache__/connection.cpython-312.pyc create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/urllib3/http2/__pycache__/probe.cpython-312.pyc create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/urllib3/http2/connection.py create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/urllib3/http2/probe.py create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/urllib3/poolmanager.py create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/urllib3/py.typed create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/urllib3/response.py create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/urllib3/util/__init__.py create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/urllib3/util/__pycache__/__init__.cpython-312.pyc create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/urllib3/util/__pycache__/connection.cpython-312.pyc create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/urllib3/util/__pycache__/proxy.cpython-312.pyc create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/urllib3/util/__pycache__/request.cpython-312.pyc create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/urllib3/util/__pycache__/response.cpython-312.pyc create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/urllib3/util/__pycache__/retry.cpython-312.pyc create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/urllib3/util/__pycache__/ssl_.cpython-312.pyc create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/urllib3/util/__pycache__/ssl_match_hostname.cpython-312.pyc create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/urllib3/util/__pycache__/ssltransport.cpython-312.pyc create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/urllib3/util/__pycache__/timeout.cpython-312.pyc create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/urllib3/util/__pycache__/url.cpython-312.pyc create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/urllib3/util/__pycache__/util.cpython-312.pyc create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/urllib3/util/__pycache__/wait.cpython-312.pyc create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/urllib3/util/connection.py create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/urllib3/util/proxy.py create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/urllib3/util/request.py create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/urllib3/util/response.py create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/urllib3/util/retry.py create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/urllib3/util/ssl_.py create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/urllib3/util/ssl_match_hostname.py create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/urllib3/util/ssltransport.py create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/urllib3/util/timeout.py create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/urllib3/util/url.py create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/urllib3/util/util.py create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/urllib3/util/wait.py create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/werkzeug-3.1.3.dist-info/INSTALLER create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/werkzeug-3.1.3.dist-info/LICENSE.txt create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/werkzeug-3.1.3.dist-info/METADATA create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/werkzeug-3.1.3.dist-info/RECORD create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/werkzeug-3.1.3.dist-info/WHEEL create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/werkzeug/__init__.py create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/werkzeug/__pycache__/__init__.cpython-312.pyc create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/werkzeug/__pycache__/_internal.cpython-312.pyc create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/werkzeug/__pycache__/_reloader.cpython-312.pyc create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/werkzeug/__pycache__/exceptions.cpython-312.pyc create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/werkzeug/__pycache__/formparser.cpython-312.pyc create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/werkzeug/__pycache__/http.cpython-312.pyc create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/werkzeug/__pycache__/local.cpython-312.pyc create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/werkzeug/__pycache__/security.cpython-312.pyc create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/werkzeug/__pycache__/serving.cpython-312.pyc create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/werkzeug/__pycache__/test.cpython-312.pyc create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/werkzeug/__pycache__/testapp.cpython-312.pyc create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/werkzeug/__pycache__/urls.cpython-312.pyc create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/werkzeug/__pycache__/user_agent.cpython-312.pyc create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/werkzeug/__pycache__/utils.cpython-312.pyc create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/werkzeug/__pycache__/wsgi.cpython-312.pyc create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/werkzeug/_internal.py create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/werkzeug/_reloader.py create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/werkzeug/datastructures/__init__.py create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/werkzeug/datastructures/__pycache__/__init__.cpython-312.pyc create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/werkzeug/datastructures/__pycache__/accept.cpython-312.pyc create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/werkzeug/datastructures/__pycache__/auth.cpython-312.pyc create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/werkzeug/datastructures/__pycache__/cache_control.cpython-312.pyc create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/werkzeug/datastructures/__pycache__/csp.cpython-312.pyc create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/werkzeug/datastructures/__pycache__/etag.cpython-312.pyc create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/werkzeug/datastructures/__pycache__/file_storage.cpython-312.pyc create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/werkzeug/datastructures/__pycache__/headers.cpython-312.pyc create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/werkzeug/datastructures/__pycache__/mixins.cpython-312.pyc create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/werkzeug/datastructures/__pycache__/range.cpython-312.pyc create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/werkzeug/datastructures/__pycache__/structures.cpython-312.pyc create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/werkzeug/datastructures/accept.py create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/werkzeug/datastructures/auth.py create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/werkzeug/datastructures/cache_control.py create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/werkzeug/datastructures/csp.py create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/werkzeug/datastructures/etag.py create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/werkzeug/datastructures/file_storage.py create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/werkzeug/datastructures/headers.py create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/werkzeug/datastructures/mixins.py create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/werkzeug/datastructures/range.py create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/werkzeug/datastructures/structures.py create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/werkzeug/debug/__init__.py create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/werkzeug/debug/__pycache__/__init__.cpython-312.pyc create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/werkzeug/debug/__pycache__/console.cpython-312.pyc create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/werkzeug/debug/__pycache__/repr.cpython-312.pyc create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/werkzeug/debug/__pycache__/tbtools.cpython-312.pyc create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/werkzeug/debug/console.py create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/werkzeug/debug/repr.py create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/werkzeug/debug/shared/ICON_LICENSE.md create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/werkzeug/debug/shared/console.png create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/werkzeug/debug/shared/debugger.js create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/werkzeug/debug/shared/less.png create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/werkzeug/debug/shared/more.png create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/werkzeug/debug/shared/style.css create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/werkzeug/debug/tbtools.py create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/werkzeug/exceptions.py create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/werkzeug/formparser.py create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/werkzeug/http.py create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/werkzeug/local.py create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/werkzeug/middleware/__init__.py create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/werkzeug/middleware/__pycache__/__init__.cpython-312.pyc create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/werkzeug/middleware/__pycache__/dispatcher.cpython-312.pyc create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/werkzeug/middleware/__pycache__/http_proxy.cpython-312.pyc create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/werkzeug/middleware/__pycache__/lint.cpython-312.pyc create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/werkzeug/middleware/__pycache__/profiler.cpython-312.pyc create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/werkzeug/middleware/__pycache__/proxy_fix.cpython-312.pyc create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/werkzeug/middleware/__pycache__/shared_data.cpython-312.pyc create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/werkzeug/middleware/dispatcher.py create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/werkzeug/middleware/http_proxy.py create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/werkzeug/middleware/lint.py create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/werkzeug/middleware/profiler.py create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/werkzeug/middleware/proxy_fix.py create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/werkzeug/middleware/shared_data.py create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/werkzeug/py.typed create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/werkzeug/routing/__init__.py create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/werkzeug/routing/__pycache__/__init__.cpython-312.pyc create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/werkzeug/routing/__pycache__/converters.cpython-312.pyc create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/werkzeug/routing/__pycache__/exceptions.cpython-312.pyc create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/werkzeug/routing/__pycache__/map.cpython-312.pyc create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/werkzeug/routing/__pycache__/matcher.cpython-312.pyc create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/werkzeug/routing/__pycache__/rules.cpython-312.pyc create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/werkzeug/routing/converters.py create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/werkzeug/routing/exceptions.py create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/werkzeug/routing/map.py create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/werkzeug/routing/matcher.py create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/werkzeug/routing/rules.py create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/werkzeug/sansio/__init__.py create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/werkzeug/sansio/__pycache__/__init__.cpython-312.pyc create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/werkzeug/sansio/__pycache__/http.cpython-312.pyc create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/werkzeug/sansio/__pycache__/multipart.cpython-312.pyc create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/werkzeug/sansio/__pycache__/request.cpython-312.pyc create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/werkzeug/sansio/__pycache__/response.cpython-312.pyc create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/werkzeug/sansio/__pycache__/utils.cpython-312.pyc create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/werkzeug/sansio/http.py create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/werkzeug/sansio/multipart.py create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/werkzeug/sansio/request.py create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/werkzeug/sansio/response.py create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/werkzeug/sansio/utils.py create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/werkzeug/security.py create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/werkzeug/serving.py create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/werkzeug/test.py create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/werkzeug/testapp.py create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/werkzeug/urls.py create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/werkzeug/user_agent.py create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/werkzeug/utils.py create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/werkzeug/wrappers/__init__.py create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/werkzeug/wrappers/__pycache__/__init__.cpython-312.pyc create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/werkzeug/wrappers/__pycache__/request.cpython-312.pyc create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/werkzeug/wrappers/__pycache__/response.cpython-312.pyc create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/werkzeug/wrappers/request.py create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/werkzeug/wrappers/response.py create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/werkzeug/wsgi.py create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/wheel-0.45.1.dist-info/INSTALLER create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/wheel-0.45.1.dist-info/LICENSE.txt create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/wheel-0.45.1.dist-info/METADATA create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/wheel-0.45.1.dist-info/RECORD create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/wheel-0.45.1.dist-info/WHEEL create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/wheel-0.45.1.dist-info/entry_points.txt create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/wheel/__init__.py create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/wheel/__main__.py create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/wheel/__pycache__/__init__.cpython-312.pyc create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/wheel/__pycache__/__main__.cpython-312.pyc create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/wheel/__pycache__/_bdist_wheel.cpython-312.pyc create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/wheel/__pycache__/_setuptools_logging.cpython-312.pyc create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/wheel/__pycache__/bdist_wheel.cpython-312.pyc create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/wheel/__pycache__/macosx_libfile.cpython-312.pyc create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/wheel/__pycache__/metadata.cpython-312.pyc create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/wheel/__pycache__/util.cpython-312.pyc create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/wheel/__pycache__/wheelfile.cpython-312.pyc create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/wheel/_bdist_wheel.py create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/wheel/_setuptools_logging.py create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/wheel/bdist_wheel.py create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/wheel/cli/__init__.py create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/wheel/cli/__pycache__/__init__.cpython-312.pyc create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/wheel/cli/__pycache__/convert.cpython-312.pyc create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/wheel/cli/__pycache__/pack.cpython-312.pyc create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/wheel/cli/__pycache__/tags.cpython-312.pyc create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/wheel/cli/__pycache__/unpack.cpython-312.pyc create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/wheel/cli/convert.py create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/wheel/cli/pack.py create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/wheel/cli/tags.py create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/wheel/cli/unpack.py create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/wheel/macosx_libfile.py create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/wheel/metadata.py create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/wheel/util.py create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/wheel/vendored/__init__.py create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/wheel/vendored/__pycache__/__init__.cpython-312.pyc create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/wheel/vendored/packaging/LICENSE create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/wheel/vendored/packaging/LICENSE.APACHE create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/wheel/vendored/packaging/LICENSE.BSD create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/wheel/vendored/packaging/__init__.py create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/wheel/vendored/packaging/__pycache__/__init__.cpython-312.pyc create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/wheel/vendored/packaging/__pycache__/_elffile.cpython-312.pyc create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/wheel/vendored/packaging/__pycache__/_manylinux.cpython-312.pyc create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/wheel/vendored/packaging/__pycache__/_musllinux.cpython-312.pyc create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/wheel/vendored/packaging/__pycache__/_parser.cpython-312.pyc create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/wheel/vendored/packaging/__pycache__/_structures.cpython-312.pyc create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/wheel/vendored/packaging/__pycache__/_tokenizer.cpython-312.pyc create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/wheel/vendored/packaging/__pycache__/markers.cpython-312.pyc create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/wheel/vendored/packaging/__pycache__/requirements.cpython-312.pyc create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/wheel/vendored/packaging/__pycache__/specifiers.cpython-312.pyc create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/wheel/vendored/packaging/__pycache__/tags.cpython-312.pyc create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/wheel/vendored/packaging/__pycache__/utils.cpython-312.pyc create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/wheel/vendored/packaging/__pycache__/version.cpython-312.pyc create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/wheel/vendored/packaging/_elffile.py create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/wheel/vendored/packaging/_manylinux.py create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/wheel/vendored/packaging/_musllinux.py create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/wheel/vendored/packaging/_parser.py create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/wheel/vendored/packaging/_structures.py create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/wheel/vendored/packaging/_tokenizer.py create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/wheel/vendored/packaging/markers.py create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/wheel/vendored/packaging/requirements.py create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/wheel/vendored/packaging/specifiers.py create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/wheel/vendored/packaging/tags.py create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/wheel/vendored/packaging/utils.py create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/wheel/vendored/packaging/version.py create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/wheel/vendored/vendor.txt create mode 100644 psets/9/finance/env/lib/python3.12/site-packages/wheel/wheelfile.py create mode 120000 psets/9/finance/env/lib64 create mode 100644 psets/9/finance/env/pyvenv.cfg create mode 100644 psets/9/finance/flask_session/497876a3b151a6b60f167574a809af69 diff --git a/psets/9/finance/.idea/dataSources.xml b/psets/9/finance/.idea/dataSources.xml new file mode 100644 index 0000000..2a83a8a --- /dev/null +++ b/psets/9/finance/.idea/dataSources.xml @@ -0,0 +1,12 @@ + + + + + sqlite.xerial + true + org.sqlite.JDBC + jdbc:sqlite:$PROJECT_DIR$/finance.db + $ProjectFileDir$ + + + \ No newline at end of file diff --git a/psets/9/finance/.idea/misc.xml b/psets/9/finance/.idea/misc.xml new file mode 100644 index 0000000..cafab9f --- /dev/null +++ b/psets/9/finance/.idea/misc.xml @@ -0,0 +1,6 @@ + + + + + \ No newline at end of file diff --git a/psets/9/finance/.idea/vcs.xml b/psets/9/finance/.idea/vcs.xml new file mode 100644 index 0000000..c2365ab --- /dev/null +++ b/psets/9/finance/.idea/vcs.xml @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/psets/9/finance/Dockerfile b/psets/9/finance/Dockerfile new file mode 100644 index 0000000..65f0e00 --- /dev/null +++ b/psets/9/finance/Dockerfile @@ -0,0 +1,10 @@ +FROM python:3.8-slim-buster + +WORKDIR /python-docker + +COPY requirements.txt requirements.txt +RUN pip3 install -r requirements.txt + +COPY . . + +CMD [ "python3", "-m" , "flask", "run", "--host=0.0.0.0"] diff --git a/psets/9/finance/__pycache__/app.cpython-312.pyc b/psets/9/finance/__pycache__/app.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..9c1eba8b50f6086079cc5ea3e8cd770b9a7b6641 GIT binary patch literal 11942 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 WXYk$U`|-ZJMiyt=lM>!5 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/psets/9/finance/env/bin/activate b/psets/9/finance/env/bin/activate new file mode 100644 index 0000000..06f9cf1 --- /dev/null +++ b/psets/9/finance/env/bin/activate @@ -0,0 +1,70 @@ +# 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 + + # Call hash to forget past commands. Without forgetting + # past commands the $PATH changes we made may not be respected + hash -r 2> /dev/null + + 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 + +# on Windows, a path can contain colons and backslashes and has to be converted: +if [ "${OSTYPE:-}" = "cygwin" ] || [ "${OSTYPE:-}" = "msys" ] ; then + # transform D:\path\to\venv to /d/path/to/venv on MSYS + # and to /cygdrive/d/path/to/venv on Cygwin + export VIRTUAL_ENV=$(cygpath "/mnt/Daten/coding/cs50/psets/9/finance/env") +else + # use the path as-is + export VIRTUAL_ENV="/mnt/Daten/coding/cs50/psets/9/finance/env" +fi + +_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="(env) ${PS1:-}" + export PS1 + VIRTUAL_ENV_PROMPT="(env) " + export VIRTUAL_ENV_PROMPT +fi + +# Call hash to forget past commands. Without forgetting +# past commands the $PATH changes we made may not be respected +hash -r 2> /dev/null diff --git a/psets/9/finance/env/bin/activate.csh b/psets/9/finance/env/bin/activate.csh new file mode 100644 index 0000000..47431ae --- /dev/null +++ b/psets/9/finance/env/bin/activate.csh @@ -0,0 +1,27 @@ +# 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 "/mnt/Daten/coding/cs50/psets/9/finance/env" + +set _OLD_VIRTUAL_PATH="$PATH" +setenv PATH "$VIRTUAL_ENV/bin:$PATH" + + +set _OLD_VIRTUAL_PROMPT="$prompt" + +if (! "$?VIRTUAL_ENV_DISABLE_PROMPT") then + set prompt = "(env) $prompt" + setenv VIRTUAL_ENV_PROMPT "(env) " +endif + +alias pydoc python -m pydoc + +rehash diff --git a/psets/9/finance/env/bin/activate.fish b/psets/9/finance/env/bin/activate.fish new file mode 100644 index 0000000..1677742 --- /dev/null +++ b/psets/9/finance/env/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 "/mnt/Daten/coding/cs50/psets/9/finance/env" + +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) "(env) " (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 "(env) " +end diff --git a/psets/9/finance/env/bin/automat-visualize b/psets/9/finance/env/bin/automat-visualize new file mode 100644 index 0000000..3c2a3dd --- /dev/null +++ b/psets/9/finance/env/bin/automat-visualize @@ -0,0 +1,8 @@ +#!/mnt/Daten/coding/cs50/psets/9/finance/env/bin/python +# -*- coding: utf-8 -*- +import re +import sys +from automat._visualize import tool +if __name__ == '__main__': + sys.argv[0] = re.sub(r'(-script\.pyw|\.exe)?$', '', sys.argv[0]) + sys.exit(tool()) diff --git a/psets/9/finance/env/bin/flask b/psets/9/finance/env/bin/flask new file mode 100644 index 0000000..2464bd3 --- /dev/null +++ b/psets/9/finance/env/bin/flask @@ -0,0 +1,8 @@ +#!/mnt/Daten/coding/cs50/psets/9/finance/env/bin/python +# -*- coding: utf-8 -*- +import re +import sys +from flask.cli import main +if __name__ == '__main__': + sys.argv[0] = re.sub(r'(-script\.pyw|\.exe)?$', '', sys.argv[0]) + sys.exit(main()) diff --git a/psets/9/finance/env/bin/normalizer b/psets/9/finance/env/bin/normalizer new file mode 100644 index 0000000..90028dd --- /dev/null +++ b/psets/9/finance/env/bin/normalizer @@ -0,0 +1,8 @@ +#!/mnt/Daten/coding/cs50/psets/9/finance/env/bin/python +# -*- coding: utf-8 -*- +import re +import sys +from charset_normalizer.cli import cli_detect +if __name__ == '__main__': + sys.argv[0] = re.sub(r'(-script\.pyw|\.exe)?$', '', sys.argv[0]) + sys.exit(cli_detect()) diff --git a/psets/9/finance/env/bin/pip b/psets/9/finance/env/bin/pip new file mode 100644 index 0000000..a3bfbe5 --- /dev/null +++ b/psets/9/finance/env/bin/pip @@ -0,0 +1,8 @@ +#!/mnt/Daten/coding/cs50/psets/9/finance/env/bin/python +# -*- 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/psets/9/finance/env/bin/pip3 b/psets/9/finance/env/bin/pip3 new file mode 100644 index 0000000..a3bfbe5 --- /dev/null +++ b/psets/9/finance/env/bin/pip3 @@ -0,0 +1,8 @@ +#!/mnt/Daten/coding/cs50/psets/9/finance/env/bin/python +# -*- 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/psets/9/finance/env/bin/pip3.12 b/psets/9/finance/env/bin/pip3.12 new file mode 100644 index 0000000..a3bfbe5 --- /dev/null +++ b/psets/9/finance/env/bin/pip3.12 @@ -0,0 +1,8 @@ +#!/mnt/Daten/coding/cs50/psets/9/finance/env/bin/python +# -*- 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/psets/9/finance/env/bin/python b/psets/9/finance/env/bin/python new file mode 120000 index 0000000..acd4152 --- /dev/null +++ b/psets/9/finance/env/bin/python @@ -0,0 +1 @@ +/usr/bin/python \ No newline at end of file diff --git a/psets/9/finance/env/bin/python3 b/psets/9/finance/env/bin/python3 new file mode 120000 index 0000000..d8654aa --- /dev/null +++ b/psets/9/finance/env/bin/python3 @@ -0,0 +1 @@ +python \ No newline at end of file diff --git a/psets/9/finance/env/bin/python3.12 b/psets/9/finance/env/bin/python3.12 new file mode 120000 index 0000000..d8654aa --- /dev/null +++ b/psets/9/finance/env/bin/python3.12 @@ -0,0 +1 @@ +python \ No newline at end of file diff --git a/psets/9/finance/env/bin/sqlformat b/psets/9/finance/env/bin/sqlformat new file mode 100644 index 0000000..422ea2f --- /dev/null +++ b/psets/9/finance/env/bin/sqlformat @@ -0,0 +1,8 @@ +#!/mnt/Daten/coding/cs50/psets/9/finance/env/bin/python +# -*- coding: utf-8 -*- +import re +import sys +from sqlparse.__main__ import main +if __name__ == '__main__': + sys.argv[0] = re.sub(r'(-script\.pyw|\.exe)?$', '', sys.argv[0]) + sys.exit(main()) diff --git a/psets/9/finance/env/bin/wheel b/psets/9/finance/env/bin/wheel new file mode 100644 index 0000000..93f49e3 --- /dev/null +++ b/psets/9/finance/env/bin/wheel @@ -0,0 +1,8 @@ +#!/mnt/Daten/coding/cs50/psets/9/finance/env/bin/python +# -*- coding: utf-8 -*- +import re +import sys +from wheel.cli import main +if __name__ == '__main__': + sys.argv[0] = re.sub(r'(-script\.pyw|\.exe)?$', '', sys.argv[0]) + sys.exit(main()) diff --git a/psets/9/finance/env/include/site/python3.12/greenlet/greenlet.h b/psets/9/finance/env/include/site/python3.12/greenlet/greenlet.h new file mode 100644 index 0000000..d02a16e --- /dev/null +++ b/psets/9/finance/env/include/site/python3.12/greenlet/greenlet.h @@ -0,0 +1,164 @@ +/* -*- indent-tabs-mode: nil; tab-width: 4; -*- */ + +/* Greenlet object interface */ + +#ifndef Py_GREENLETOBJECT_H +#define Py_GREENLETOBJECT_H + + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/* This is deprecated and undocumented. It does not change. */ +#define GREENLET_VERSION "1.0.0" + +#ifndef GREENLET_MODULE +#define implementation_ptr_t void* +#endif + +typedef struct _greenlet { + PyObject_HEAD + PyObject* weakreflist; + PyObject* dict; + implementation_ptr_t pimpl; +} PyGreenlet; + +#define PyGreenlet_Check(op) (op && PyObject_TypeCheck(op, &PyGreenlet_Type)) + + +/* C API functions */ + +/* Total number of symbols that are exported */ +#define PyGreenlet_API_pointers 12 + +#define PyGreenlet_Type_NUM 0 +#define PyExc_GreenletError_NUM 1 +#define PyExc_GreenletExit_NUM 2 + +#define PyGreenlet_New_NUM 3 +#define PyGreenlet_GetCurrent_NUM 4 +#define PyGreenlet_Throw_NUM 5 +#define PyGreenlet_Switch_NUM 6 +#define PyGreenlet_SetParent_NUM 7 + +#define PyGreenlet_MAIN_NUM 8 +#define PyGreenlet_STARTED_NUM 9 +#define PyGreenlet_ACTIVE_NUM 10 +#define PyGreenlet_GET_PARENT_NUM 11 + +#ifndef GREENLET_MODULE +/* This section is used by modules that uses the greenlet C API */ +static void** _PyGreenlet_API = NULL; + +# define PyGreenlet_Type \ + (*(PyTypeObject*)_PyGreenlet_API[PyGreenlet_Type_NUM]) + +# define PyExc_GreenletError \ + ((PyObject*)_PyGreenlet_API[PyExc_GreenletError_NUM]) + +# define PyExc_GreenletExit \ + ((PyObject*)_PyGreenlet_API[PyExc_GreenletExit_NUM]) + +/* + * PyGreenlet_New(PyObject *args) + * + * greenlet.greenlet(run, parent=None) + */ +# define PyGreenlet_New \ + (*(PyGreenlet * (*)(PyObject * run, PyGreenlet * parent)) \ + _PyGreenlet_API[PyGreenlet_New_NUM]) + +/* + * PyGreenlet_GetCurrent(void) + * + * greenlet.getcurrent() + */ +# define PyGreenlet_GetCurrent \ + (*(PyGreenlet * (*)(void)) _PyGreenlet_API[PyGreenlet_GetCurrent_NUM]) + +/* + * PyGreenlet_Throw( + * PyGreenlet *greenlet, + * PyObject *typ, + * PyObject *val, + * PyObject *tb) + * + * g.throw(...) + */ +# define PyGreenlet_Throw \ + (*(PyObject * (*)(PyGreenlet * self, \ + PyObject * typ, \ + PyObject * val, \ + PyObject * tb)) \ + _PyGreenlet_API[PyGreenlet_Throw_NUM]) + +/* + * PyGreenlet_Switch(PyGreenlet *greenlet, PyObject *args) + * + * g.switch(*args, **kwargs) + */ +# define PyGreenlet_Switch \ + (*(PyObject * \ + (*)(PyGreenlet * greenlet, PyObject * args, PyObject * kwargs)) \ + _PyGreenlet_API[PyGreenlet_Switch_NUM]) + +/* + * PyGreenlet_SetParent(PyObject *greenlet, PyObject *new_parent) + * + * g.parent = new_parent + */ +# define PyGreenlet_SetParent \ + (*(int (*)(PyGreenlet * greenlet, PyGreenlet * nparent)) \ + _PyGreenlet_API[PyGreenlet_SetParent_NUM]) + +/* + * PyGreenlet_GetParent(PyObject* greenlet) + * + * return greenlet.parent; + * + * This could return NULL even if there is no exception active. + * If it does not return NULL, you are responsible for decrementing the + * reference count. + */ +# define PyGreenlet_GetParent \ + (*(PyGreenlet* (*)(PyGreenlet*)) \ + _PyGreenlet_API[PyGreenlet_GET_PARENT_NUM]) + +/* + * deprecated, undocumented alias. + */ +# define PyGreenlet_GET_PARENT PyGreenlet_GetParent + +# define PyGreenlet_MAIN \ + (*(int (*)(PyGreenlet*)) \ + _PyGreenlet_API[PyGreenlet_MAIN_NUM]) + +# define PyGreenlet_STARTED \ + (*(int (*)(PyGreenlet*)) \ + _PyGreenlet_API[PyGreenlet_STARTED_NUM]) + +# define PyGreenlet_ACTIVE \ + (*(int (*)(PyGreenlet*)) \ + _PyGreenlet_API[PyGreenlet_ACTIVE_NUM]) + + + + +/* Macro that imports greenlet and initializes C API */ +/* NOTE: This has actually moved to ``greenlet._greenlet._C_API``, but we + keep the older definition to be sure older code that might have a copy of + the header still works. */ +# define PyGreenlet_Import() \ + { \ + _PyGreenlet_API = (void**)PyCapsule_Import("greenlet._C_API", 0); \ + } + +#endif /* GREENLET_MODULE */ + +#ifdef __cplusplus +} +#endif +#endif /* !Py_GREENLETOBJECT_H */ diff --git a/psets/9/finance/env/lib/python3.12/site-packages/Automat-24.8.1.dist-info/INSTALLER b/psets/9/finance/env/lib/python3.12/site-packages/Automat-24.8.1.dist-info/INSTALLER new file mode 100644 index 0000000..a1b589e --- /dev/null +++ b/psets/9/finance/env/lib/python3.12/site-packages/Automat-24.8.1.dist-info/INSTALLER @@ -0,0 +1 @@ +pip diff --git a/psets/9/finance/env/lib/python3.12/site-packages/Automat-24.8.1.dist-info/LICENSE b/psets/9/finance/env/lib/python3.12/site-packages/Automat-24.8.1.dist-info/LICENSE new file mode 100644 index 0000000..9773501 --- /dev/null +++ b/psets/9/finance/env/lib/python3.12/site-packages/Automat-24.8.1.dist-info/LICENSE @@ -0,0 +1,21 @@ +Copyright (c) 2014 +Rackspace + +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/psets/9/finance/env/lib/python3.12/site-packages/Automat-24.8.1.dist-info/METADATA b/psets/9/finance/env/lib/python3.12/site-packages/Automat-24.8.1.dist-info/METADATA new file mode 100644 index 0000000..b86e9ab --- /dev/null +++ b/psets/9/finance/env/lib/python3.12/site-packages/Automat-24.8.1.dist-info/METADATA @@ -0,0 +1,199 @@ +Metadata-Version: 2.1 +Name: Automat +Version: 24.8.1 +Summary: Self-service finite-state machines for the programmer on the go. +Author-email: Glyph +License: Copyright (c) 2014 + Rackspace + + 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. + +Project-URL: Documentation, https://automat.readthedocs.io/ +Project-URL: Source, https://github.com/glyph/automat/ +Keywords: fsm,state machine,automata +Classifier: Intended Audience :: Developers +Classifier: License :: OSI Approved :: MIT License +Classifier: Operating System :: OS Independent +Classifier: Programming Language :: Python +Classifier: Programming Language :: Python :: 3 +Classifier: Programming Language :: Python :: 3.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/markdown +License-File: LICENSE +Requires-Dist: typing-extensions; python_version < "3.10" +Provides-Extra: visualize +Requires-Dist: graphviz>0.5.1; extra == "visualize" +Requires-Dist: Twisted>=16.1.1; extra == "visualize" + +# Automat # + +[![Documentation Status](https://readthedocs.org/projects/automat/badge/?version=latest)](http://automat.readthedocs.io/en/latest/) +[![Build Status](https://github.com/glyph/automat/actions/workflows/ci.yml/badge.svg?branch=trunk)](https://github.com/glyph/automat/actions/workflows/ci.yml?query=branch%3Atrunk) +[![Coverage Status](http://codecov.io/github/glyph/automat/coverage.svg?branch=trunk)](http://codecov.io/github/glyph/automat?branch=trunk) + +## Self-service finite-state machines for the programmer on the go. ## + +Automat is a library for concise, idiomatic Python expression of finite-state +automata (particularly deterministic finite-state transducers). + +Read more here, or on [Read the Docs](https://automat.readthedocs.io/), or watch the following videos for an overview and presentation + +### Why use state machines? ### + +Sometimes you have to create an object whose behavior varies with its state, +but still wishes to present a consistent interface to its callers. + +For example, let's say you're writing the software for a coffee machine. It +has a lid that can be opened or closed, a chamber for water, a chamber for +coffee beans, and a button for "brew". + +There are a number of possible states for the coffee machine. It might or +might not have water. It might or might not have beans. The lid might be open +or closed. The "brew" button should only actually attempt to brew coffee in +one of these configurations, and the "open lid" button should only work if the +coffee is not, in fact, brewing. + +With diligence and attention to detail, you can implement this correctly using +a collection of attributes on an object; `hasWater`, `hasBeans`, `isLidOpen` +and so on. However, you have to keep all these attributes consistent. As the +coffee maker becomes more complex - perhaps you add an additional chamber for +flavorings so you can make hazelnut coffee, for example - you have to keep +adding more and more checks and more and more reasoning about which +combinations of states are allowed. + +Rather than adding tedious `if` checks to every single method to make sure that +each of these flags are exactly what you expect, you can use a state machine to +ensure that if your code runs at all, it will be run with all the required +values initialized, because they have to be called in the order you declare +them. + +You can read about state machines and their advantages for Python programmers +in more detail [in this excellent article by Jean-Paul +Calderone](https://web.archive.org/web/20160507053658/https://clusterhq.com/2013/12/05/what-is-a-state-machine/). + +### What makes Automat different? ### + +There are +[dozens of libraries on PyPI implementing state machines](https://pypi.org/search/?q=finite+state+machine). +So it behooves me to say why yet another one would be a good idea. + +Automat is designed around this principle: while organizing your code around +state machines is a good idea, your callers don't, and shouldn't have to, care +that you've done so. In Python, the "input" to a stateful system is a method +call; the "output" may be a method call, if you need to invoke a side effect, +or a return value, if you are just performing a computation in memory. Most +other state-machine libraries require you to explicitly create an input object, +provide that object to a generic "input" method, and then receive results, +sometimes in terms of that library's interfaces and sometimes in terms of +classes you define yourself. + +For example, a snippet of the coffee-machine example above might be implemented +as follows in naive Python: + +```python +class CoffeeMachine(object): + def brewButton(self) -> None: + if self.hasWater and self.hasBeans and not self.isLidOpen: + self.heatTheHeatingElement() + # ... +``` + +With Automat, you'd begin with a `typing.Protocol` that describes all of your +inputs: + +```python +from typing import Protocol + +class CoffeeBrewer(Protocol): + def brewButton(self) -> None: + "The user pressed the 'brew' button." + def putInBeans(self) -> None: + "The user put in some beans." +``` + +We'll then need a concrete class to contain the shared core of state shared +among the different states: + +```python +from dataclasses import dataclass + +@dataclass +class BrewerCore: + heatingElement: HeatingElement +``` + +Next, we need to describe our state machine, including all of our states. For +simplicity's sake let's say that the only two states are `noBeans` and +`haveBeans`: + +```python +from automat import TypeMachineBuilder + +builder = TypeMachineBuilder(CoffeeBrewer, BrewerCore) +noBeans = builder.state("noBeans") +haveBeans = builder.state("haveBeans") +``` + +Next we can describe a simple transition; when we put in beans, we move to the +`haveBeans` state, with no other behavior. + +```python +# When we don't have beans, upon putting in beans, we will then have beans +noBeans.upon(CoffeeBrewer.putInBeans).to(haveBeans).returns(None) +``` + +And then another transition that we describe with a decorator, one that *does* +have some behavior, that needs to heat up the heating element to brew the +coffee: + +```python +@haveBeans.upon(CoffeeBrewer.brewButton).to(noBeans) +def heatUp(inputs: CoffeeBrewer, core: BrewerCore) -> None: + """ + When we have beans, upon pressing the brew button, we will then not have + beans any more (as they have been entered into the brewing chamber) and + our output will be heating the heating element. + """ + print("Brewing the coffee...") + core.heatingElement.turnOn() +``` + +Then we finalize the state machine by building it, which gives us a callable +that takes a `BrewerCore` and returns a synthetic `CoffeeBrewer` + +```python +newCoffeeMachine = builder.build() +``` + +```python +>>> coffee = newCoffeeMachine(BrewerCore(HeatingElement())) +>>> machine.putInBeans() +>>> machine.brewButton() +Brewing the coffee... +``` + +All of the *inputs* are provided by calling them like methods, all of the +*output behaviors* are automatically invoked when they are produced according +to the outputs specified to `upon` and all of the states are simply opaque +tokens. diff --git a/psets/9/finance/env/lib/python3.12/site-packages/Automat-24.8.1.dist-info/RECORD b/psets/9/finance/env/lib/python3.12/site-packages/Automat-24.8.1.dist-info/RECORD new file mode 100644 index 0000000..fbd0458 --- /dev/null +++ b/psets/9/finance/env/lib/python3.12/site-packages/Automat-24.8.1.dist-info/RECORD @@ -0,0 +1,40 @@ +../../../bin/automat-visualize,sha256=Gyv_3d6TeKMpzxHJb64voO8imr3m8LPZReWuLMxsYwE,254 +Automat-24.8.1.dist-info/INSTALLER,sha256=zuuue4knoyJ-UwPPXg8fezS7VCrXJQrAP7zeNuwvFQg,4 +Automat-24.8.1.dist-info/LICENSE,sha256=siATAWeNCpN9k4VDgnyhNgcS6zTiPejuPzv_-9TA43Y,1053 +Automat-24.8.1.dist-info/METADATA,sha256=XJIxL4Olb15WCoAdVEcORum39__wiCXQR6LNubERZ6M,8396 +Automat-24.8.1.dist-info/RECORD,, +Automat-24.8.1.dist-info/REQUESTED,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0 +Automat-24.8.1.dist-info/WHEEL,sha256=HiCZjzuy6Dw0hdX5R3LCFPDmFS4BWl8H-8W39XfmgX4,91 +Automat-24.8.1.dist-info/entry_points.txt,sha256=D5Dc6byHpLWAktM443OHbx0ZGl1ZBZtf6rPNlGi7NbQ,62 +Automat-24.8.1.dist-info/top_level.txt,sha256=vg4zAOyhP_3YCmpKZLNgFw1uMF3lC_b6TKsdz7jBSpI,8 +automat/__init__.py,sha256=8yHAuqaxK0mdiOEXHbwe6WaNzaY01k2HMWD_RltPB-U,356 +automat/__pycache__/__init__.cpython-312.pyc,, +automat/__pycache__/_core.cpython-312.pyc,, +automat/__pycache__/_discover.cpython-312.pyc,, +automat/__pycache__/_introspection.cpython-312.pyc,, +automat/__pycache__/_methodical.cpython-312.pyc,, +automat/__pycache__/_runtimeproto.cpython-312.pyc,, +automat/__pycache__/_typed.cpython-312.pyc,, +automat/__pycache__/_visualize.cpython-312.pyc,, +automat/_core.py,sha256=oe4QNlfvmgsnKe_8fyNiOsHsfz5xPArGuXWle9zePp8,6663 +automat/_discover.py,sha256=KRbmm7kxpd-WReDQU4qe6hVKGUKmGBHUjYIkRneO4mc,5197 +automat/_introspection.py,sha256=uF5ymY-GZckyRxvRs7UToPBV_oVV6xHmvlBVey9nv80,1441 +automat/_methodical.py,sha256=YgZXraDe6dvK6w_Y9xfPa0kXCka4ZeGLfcb4IfK4bnI,17243 +automat/_runtimeproto.py,sha256=mJ_4VuEGpLc1u7Ptm5cfaLUq7LGD7KfrvmsAa4LsyuU,1654 +automat/_test/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0 +automat/_test/__pycache__/__init__.cpython-312.pyc,, +automat/_test/__pycache__/test_core.cpython-312.pyc,, +automat/_test/__pycache__/test_discover.cpython-312.pyc,, +automat/_test/__pycache__/test_methodical.cpython-312.pyc,, +automat/_test/__pycache__/test_trace.cpython-312.pyc,, +automat/_test/__pycache__/test_type_based.cpython-312.pyc,, +automat/_test/__pycache__/test_visualize.cpython-312.pyc,, +automat/_test/test_core.py,sha256=PJHNvQ85i8vjH-oF6nPNKB84_noTyl2dQSv_iRl70J8,3481 +automat/_test/test_discover.py,sha256=ROnW7eSLE4T76FVncY2UK05DIYcHZ3TSGGg7kQnbvtw,22067 +automat/_test/test_methodical.py,sha256=SKMMbl-6bjH-QZ1hDFRItCOyKF4SstuA4QvExnVhn7w,20267 +automat/_test/test_trace.py,sha256=tty7P_ctJtk38ZXnpmEy-J9Rn-Hh2AKb_ia6EmtXSQI,3299 +automat/_test/test_type_based.py,sha256=8oZxz3T7zIvyMKg4THg7M85zaHtE4QU9nAegU_OUvko,17872 +automat/_test/test_visualize.py,sha256=HXBPgMAD0OTz_l1Yq0lI3d1vJ_l3sHTH67Jauaf-2sk,14631 +automat/_typed.py,sha256=lMzMgUfX713Xw_W4pr8iyPqcdpRSbu4rEpRlrXAOW2k,24204 +automat/_visualize.py,sha256=DQYig2mBKX-LquPEEy89Y_qyj21tSutAUaFsF1F64ws,6512 +automat/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0 diff --git a/psets/9/finance/env/lib/python3.12/site-packages/Automat-24.8.1.dist-info/REQUESTED b/psets/9/finance/env/lib/python3.12/site-packages/Automat-24.8.1.dist-info/REQUESTED new file mode 100644 index 0000000..e69de29 diff --git a/psets/9/finance/env/lib/python3.12/site-packages/Automat-24.8.1.dist-info/WHEEL b/psets/9/finance/env/lib/python3.12/site-packages/Automat-24.8.1.dist-info/WHEEL new file mode 100644 index 0000000..71360e0 --- /dev/null +++ b/psets/9/finance/env/lib/python3.12/site-packages/Automat-24.8.1.dist-info/WHEEL @@ -0,0 +1,5 @@ +Wheel-Version: 1.0 +Generator: setuptools (72.2.0) +Root-Is-Purelib: true +Tag: py3-none-any + diff --git a/psets/9/finance/env/lib/python3.12/site-packages/Automat-24.8.1.dist-info/entry_points.txt b/psets/9/finance/env/lib/python3.12/site-packages/Automat-24.8.1.dist-info/entry_points.txt new file mode 100644 index 0000000..ec4b91a --- /dev/null +++ b/psets/9/finance/env/lib/python3.12/site-packages/Automat-24.8.1.dist-info/entry_points.txt @@ -0,0 +1,2 @@ +[console_scripts] +automat-visualize = automat._visualize:tool diff --git a/psets/9/finance/env/lib/python3.12/site-packages/Automat-24.8.1.dist-info/top_level.txt b/psets/9/finance/env/lib/python3.12/site-packages/Automat-24.8.1.dist-info/top_level.txt new file mode 100644 index 0000000..b69387b --- /dev/null +++ b/psets/9/finance/env/lib/python3.12/site-packages/Automat-24.8.1.dist-info/top_level.txt @@ -0,0 +1 @@ +automat diff --git a/psets/9/finance/env/lib/python3.12/site-packages/MarkupSafe-3.0.2.dist-info/INSTALLER b/psets/9/finance/env/lib/python3.12/site-packages/MarkupSafe-3.0.2.dist-info/INSTALLER new file mode 100644 index 0000000..a1b589e --- /dev/null +++ b/psets/9/finance/env/lib/python3.12/site-packages/MarkupSafe-3.0.2.dist-info/INSTALLER @@ -0,0 +1 @@ +pip diff --git a/psets/9/finance/env/lib/python3.12/site-packages/MarkupSafe-3.0.2.dist-info/LICENSE.txt b/psets/9/finance/env/lib/python3.12/site-packages/MarkupSafe-3.0.2.dist-info/LICENSE.txt new file mode 100644 index 0000000..9d227a0 --- /dev/null +++ b/psets/9/finance/env/lib/python3.12/site-packages/MarkupSafe-3.0.2.dist-info/LICENSE.txt @@ -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/psets/9/finance/env/lib/python3.12/site-packages/MarkupSafe-3.0.2.dist-info/METADATA b/psets/9/finance/env/lib/python3.12/site-packages/MarkupSafe-3.0.2.dist-info/METADATA new file mode 100644 index 0000000..82261f2 --- /dev/null +++ b/psets/9/finance/env/lib/python3.12/site-packages/MarkupSafe-3.0.2.dist-info/METADATA @@ -0,0 +1,92 @@ +Metadata-Version: 2.1 +Name: MarkupSafe +Version: 3.0.2 +Summary: Safely add untrusted strings to HTML/XML markup. +Maintainer-email: Pallets +License: 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. + +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, https://github.com/pallets/markupsafe/ +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 +Classifier: Typing :: Typed +Requires-Python: >=3.9 +Description-Content-Type: text/markdown +License-File: LICENSE.txt + +# 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. + + +## Examples + +```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 diff --git a/psets/9/finance/env/lib/python3.12/site-packages/MarkupSafe-3.0.2.dist-info/RECORD b/psets/9/finance/env/lib/python3.12/site-packages/MarkupSafe-3.0.2.dist-info/RECORD new file mode 100644 index 0000000..31fd29c --- /dev/null +++ b/psets/9/finance/env/lib/python3.12/site-packages/MarkupSafe-3.0.2.dist-info/RECORD @@ -0,0 +1,14 @@ +MarkupSafe-3.0.2.dist-info/INSTALLER,sha256=zuuue4knoyJ-UwPPXg8fezS7VCrXJQrAP7zeNuwvFQg,4 +MarkupSafe-3.0.2.dist-info/LICENSE.txt,sha256=SJqOEQhQntmKN7uYPhHg9-HTHwvY-Zp5yESOf_N9B-o,1475 +MarkupSafe-3.0.2.dist-info/METADATA,sha256=aAwbZhSmXdfFuMM-rEHpeiHRkBOGESyVLJIuwzHP-nw,3975 +MarkupSafe-3.0.2.dist-info/RECORD,, +MarkupSafe-3.0.2.dist-info/WHEEL,sha256=OVgtqZzfzIXXtylXP90gxCZ6CKBCwKYyHM8PpMEjN1M,151 +MarkupSafe-3.0.2.dist-info/top_level.txt,sha256=qy0Plje5IJuvsCBjejJyhDCjEAdcDLK_2agVcex8Z6U,11 +markupsafe/__init__.py,sha256=sr-U6_27DfaSrj5jnHYxWN-pvhM27sjlDplMDPZKm7k,13214 +markupsafe/__pycache__/__init__.cpython-312.pyc,, +markupsafe/__pycache__/_native.cpython-312.pyc,, +markupsafe/_native.py,sha256=hSLs8Jmz5aqayuengJJ3kdT5PwNpBWpKrmQSdipndC8,210 +markupsafe/_speedups.c,sha256=O7XulmTo-epI6n2FtMVOrJXl8EAaIwD2iNYmBI5SEoQ,4149 +markupsafe/_speedups.cpython-312-x86_64-linux-gnu.so,sha256=t1DBZlpsjFA30BOOvXfXfT1wvO_4cS16VbHz1-49q5U,43432 +markupsafe/_speedups.pyi,sha256=ENd1bYe7gbBUf2ywyYWOGUpnXOHNJ-cgTNqetlW8h5k,41 +markupsafe/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0 diff --git a/psets/9/finance/env/lib/python3.12/site-packages/MarkupSafe-3.0.2.dist-info/WHEEL b/psets/9/finance/env/lib/python3.12/site-packages/MarkupSafe-3.0.2.dist-info/WHEEL new file mode 100644 index 0000000..057fef6 --- /dev/null +++ b/psets/9/finance/env/lib/python3.12/site-packages/MarkupSafe-3.0.2.dist-info/WHEEL @@ -0,0 +1,6 @@ +Wheel-Version: 1.0 +Generator: setuptools (75.2.0) +Root-Is-Purelib: false +Tag: cp312-cp312-manylinux_2_17_x86_64 +Tag: cp312-cp312-manylinux2014_x86_64 + diff --git a/psets/9/finance/env/lib/python3.12/site-packages/MarkupSafe-3.0.2.dist-info/top_level.txt b/psets/9/finance/env/lib/python3.12/site-packages/MarkupSafe-3.0.2.dist-info/top_level.txt new file mode 100644 index 0000000..75bf729 --- /dev/null +++ b/psets/9/finance/env/lib/python3.12/site-packages/MarkupSafe-3.0.2.dist-info/top_level.txt @@ -0,0 +1 @@ +markupsafe diff --git a/psets/9/finance/env/lib/python3.12/site-packages/SQLAlchemy-2.0.36.dist-info/INSTALLER b/psets/9/finance/env/lib/python3.12/site-packages/SQLAlchemy-2.0.36.dist-info/INSTALLER new file mode 100644 index 0000000..a1b589e --- /dev/null +++ b/psets/9/finance/env/lib/python3.12/site-packages/SQLAlchemy-2.0.36.dist-info/INSTALLER @@ -0,0 +1 @@ +pip diff --git a/psets/9/finance/env/lib/python3.12/site-packages/SQLAlchemy-2.0.36.dist-info/LICENSE b/psets/9/finance/env/lib/python3.12/site-packages/SQLAlchemy-2.0.36.dist-info/LICENSE new file mode 100644 index 0000000..967cdc5 --- /dev/null +++ b/psets/9/finance/env/lib/python3.12/site-packages/SQLAlchemy-2.0.36.dist-info/LICENSE @@ -0,0 +1,19 @@ +Copyright 2005-2024 SQLAlchemy authors and contributors . + +Permission is hereby granted, free of charge, to any person obtaining a copy of +this software and associated documentation files (the "Software"), to deal in +the Software without restriction, including without limitation the rights to +use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies +of the Software, and to permit persons to whom the Software is furnished to do +so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/psets/9/finance/env/lib/python3.12/site-packages/SQLAlchemy-2.0.36.dist-info/METADATA b/psets/9/finance/env/lib/python3.12/site-packages/SQLAlchemy-2.0.36.dist-info/METADATA new file mode 100644 index 0000000..0c802c4 --- /dev/null +++ b/psets/9/finance/env/lib/python3.12/site-packages/SQLAlchemy-2.0.36.dist-info/METADATA @@ -0,0 +1,243 @@ +Metadata-Version: 2.1 +Name: SQLAlchemy +Version: 2.0.36 +Summary: Database Abstraction Library +Home-page: https://www.sqlalchemy.org +Author: Mike Bayer +Author-email: mike_mp@zzzcomputing.com +License: MIT +Project-URL: Documentation, https://docs.sqlalchemy.org +Project-URL: Issue Tracker, https://github.com/sqlalchemy/sqlalchemy/ +Classifier: Development Status :: 5 - Production/Stable +Classifier: Intended Audience :: Developers +Classifier: License :: OSI Approved :: MIT License +Classifier: Operating System :: OS Independent +Classifier: Programming Language :: Python +Classifier: Programming Language :: Python :: 3 +Classifier: Programming Language :: Python :: 3.7 +Classifier: Programming Language :: Python :: 3.8 +Classifier: Programming Language :: Python :: 3.9 +Classifier: Programming Language :: Python :: 3.10 +Classifier: Programming Language :: Python :: 3.11 +Classifier: Programming Language :: Python :: 3.12 +Classifier: Programming Language :: Python :: 3.13 +Classifier: Programming Language :: Python :: Implementation :: CPython +Classifier: Programming Language :: Python :: Implementation :: PyPy +Classifier: Topic :: Database :: Front-Ends +Requires-Python: >=3.7 +Description-Content-Type: text/x-rst +License-File: LICENSE +Requires-Dist: typing-extensions >=4.6.0 +Requires-Dist: greenlet !=0.4.17 ; python_version < "3.13" and (platform_machine == "aarch64" or (platform_machine == "ppc64le" or (platform_machine == "x86_64" or (platform_machine == "amd64" or (platform_machine == "AMD64" or (platform_machine == "win32" or platform_machine == "WIN32")))))) +Requires-Dist: importlib-metadata ; python_version < "3.8" +Provides-Extra: aiomysql +Requires-Dist: greenlet !=0.4.17 ; extra == 'aiomysql' +Requires-Dist: aiomysql >=0.2.0 ; extra == 'aiomysql' +Provides-Extra: aioodbc +Requires-Dist: greenlet !=0.4.17 ; extra == 'aioodbc' +Requires-Dist: aioodbc ; extra == 'aioodbc' +Provides-Extra: aiosqlite +Requires-Dist: greenlet !=0.4.17 ; extra == 'aiosqlite' +Requires-Dist: aiosqlite ; extra == 'aiosqlite' +Requires-Dist: typing-extensions !=3.10.0.1 ; extra == 'aiosqlite' +Provides-Extra: asyncio +Requires-Dist: greenlet !=0.4.17 ; extra == 'asyncio' +Provides-Extra: asyncmy +Requires-Dist: greenlet !=0.4.17 ; extra == 'asyncmy' +Requires-Dist: asyncmy !=0.2.4,!=0.2.6,>=0.2.3 ; extra == 'asyncmy' +Provides-Extra: mariadb_connector +Requires-Dist: mariadb !=1.1.10,!=1.1.2,!=1.1.5,>=1.0.1 ; extra == 'mariadb_connector' +Provides-Extra: mssql +Requires-Dist: pyodbc ; extra == 'mssql' +Provides-Extra: mssql_pymssql +Requires-Dist: pymssql ; extra == 'mssql_pymssql' +Provides-Extra: mssql_pyodbc +Requires-Dist: pyodbc ; extra == 'mssql_pyodbc' +Provides-Extra: mypy +Requires-Dist: mypy >=0.910 ; extra == 'mypy' +Provides-Extra: mysql +Requires-Dist: mysqlclient >=1.4.0 ; extra == 'mysql' +Provides-Extra: mysql_connector +Requires-Dist: mysql-connector-python ; extra == 'mysql_connector' +Provides-Extra: oracle +Requires-Dist: cx-oracle >=8 ; extra == 'oracle' +Provides-Extra: oracle_oracledb +Requires-Dist: oracledb >=1.0.1 ; extra == 'oracle_oracledb' +Provides-Extra: postgresql +Requires-Dist: psycopg2 >=2.7 ; extra == 'postgresql' +Provides-Extra: postgresql_asyncpg +Requires-Dist: greenlet !=0.4.17 ; extra == 'postgresql_asyncpg' +Requires-Dist: asyncpg ; extra == 'postgresql_asyncpg' +Provides-Extra: postgresql_pg8000 +Requires-Dist: pg8000 >=1.29.1 ; extra == 'postgresql_pg8000' +Provides-Extra: postgresql_psycopg +Requires-Dist: psycopg >=3.0.7 ; extra == 'postgresql_psycopg' +Provides-Extra: postgresql_psycopg2binary +Requires-Dist: psycopg2-binary ; extra == 'postgresql_psycopg2binary' +Provides-Extra: postgresql_psycopg2cffi +Requires-Dist: psycopg2cffi ; extra == 'postgresql_psycopg2cffi' +Provides-Extra: postgresql_psycopgbinary +Requires-Dist: psycopg[binary] >=3.0.7 ; extra == 'postgresql_psycopgbinary' +Provides-Extra: pymysql +Requires-Dist: pymysql ; extra == 'pymysql' +Provides-Extra: sqlcipher +Requires-Dist: sqlcipher3-binary ; extra == 'sqlcipher' + +SQLAlchemy +========== + +|PyPI| |Python| |Downloads| + +.. |PyPI| image:: https://img.shields.io/pypi/v/sqlalchemy + :target: https://pypi.org/project/sqlalchemy + :alt: PyPI + +.. |Python| image:: https://img.shields.io/pypi/pyversions/sqlalchemy + :target: https://pypi.org/project/sqlalchemy + :alt: PyPI - Python Version + +.. |Downloads| image:: https://static.pepy.tech/badge/sqlalchemy/month + :target: https://pepy.tech/project/sqlalchemy + :alt: PyPI - Downloads + + +The Python SQL Toolkit and Object Relational Mapper + +Introduction +------------- + +SQLAlchemy is the Python SQL toolkit and Object Relational Mapper +that gives application developers the full power and +flexibility of SQL. SQLAlchemy provides a full suite +of well known enterprise-level persistence patterns, +designed for efficient and high-performing database +access, adapted into a simple and Pythonic domain +language. + +Major SQLAlchemy features include: + +* An industrial strength ORM, built + from the core on the identity map, unit of work, + and data mapper patterns. These patterns + allow transparent persistence of objects + using a declarative configuration system. + Domain models + can be constructed and manipulated naturally, + and changes are synchronized with the + current transaction automatically. +* A relationally-oriented query system, exposing + the full range of SQL's capabilities + explicitly, including joins, subqueries, + correlation, and most everything else, + in terms of the object model. + Writing queries with the ORM uses the same + techniques of relational composition you use + when writing SQL. While you can drop into + literal SQL at any time, it's virtually never + needed. +* A comprehensive and flexible system + of eager loading for related collections and objects. + Collections are cached within a session, + and can be loaded on individual access, all + at once using joins, or by query per collection + across the full result set. +* A Core SQL construction system and DBAPI + interaction layer. The SQLAlchemy Core is + separate from the ORM and is a full database + abstraction layer in its own right, and includes + an extensible Python-based SQL expression + language, schema metadata, connection pooling, + type coercion, and custom types. +* All primary and foreign key constraints are + assumed to be composite and natural. Surrogate + integer primary keys are of course still the + norm, but SQLAlchemy never assumes or hardcodes + to this model. +* Database introspection and generation. Database + schemas can be "reflected" in one step into + Python structures representing database metadata; + those same structures can then generate + CREATE statements right back out - all within + the Core, independent of the ORM. + +SQLAlchemy's philosophy: + +* SQL databases behave less and less like object + collections the more size and performance start to + matter; object collections behave less and less like + tables and rows the more abstraction starts to matter. + SQLAlchemy aims to accommodate both of these + principles. +* An ORM doesn't need to hide the "R". A relational + database provides rich, set-based functionality + that should be fully exposed. SQLAlchemy's + ORM provides an open-ended set of patterns + that allow a developer to construct a custom + mediation layer between a domain model and + a relational schema, turning the so-called + "object relational impedance" issue into + a distant memory. +* The developer, in all cases, makes all decisions + regarding the design, structure, and naming conventions + of both the object model as well as the relational + schema. SQLAlchemy only provides the means + to automate the execution of these decisions. +* With SQLAlchemy, there's no such thing as + "the ORM generated a bad query" - you + retain full control over the structure of + queries, including how joins are organized, + how subqueries and correlation is used, what + columns are requested. Everything SQLAlchemy + does is ultimately the result of a developer-initiated + decision. +* Don't use an ORM if the problem doesn't need one. + SQLAlchemy consists of a Core and separate ORM + component. The Core offers a full SQL expression + language that allows Pythonic construction + of SQL constructs that render directly to SQL + strings for a target database, returning + result sets that are essentially enhanced DBAPI + cursors. +* Transactions should be the norm. With SQLAlchemy's + ORM, nothing goes to permanent storage until + commit() is called. SQLAlchemy encourages applications + to create a consistent means of delineating + the start and end of a series of operations. +* Never render a literal value in a SQL statement. + Bound parameters are used to the greatest degree + possible, allowing query optimizers to cache + query plans effectively and making SQL injection + attacks a non-issue. + +Documentation +------------- + +Latest documentation is at: + +https://www.sqlalchemy.org/docs/ + +Installation / Requirements +--------------------------- + +Full documentation for installation is at +`Installation `_. + +Getting Help / Development / Bug reporting +------------------------------------------ + +Please refer to the `SQLAlchemy Community Guide `_. + +Code of Conduct +--------------- + +Above all, SQLAlchemy places great emphasis on polite, thoughtful, and +constructive communication between users and developers. +Please see our current Code of Conduct at +`Code of Conduct `_. + +License +------- + +SQLAlchemy is distributed under the `MIT license +`_. + diff --git a/psets/9/finance/env/lib/python3.12/site-packages/SQLAlchemy-2.0.36.dist-info/RECORD b/psets/9/finance/env/lib/python3.12/site-packages/SQLAlchemy-2.0.36.dist-info/RECORD new file mode 100644 index 0000000..93566a7 --- /dev/null +++ b/psets/9/finance/env/lib/python3.12/site-packages/SQLAlchemy-2.0.36.dist-info/RECORD @@ -0,0 +1,530 @@ +SQLAlchemy-2.0.36.dist-info/INSTALLER,sha256=zuuue4knoyJ-UwPPXg8fezS7VCrXJQrAP7zeNuwvFQg,4 +SQLAlchemy-2.0.36.dist-info/LICENSE,sha256=PA9Zq4h9BB3mpOUv_j6e212VIt6Qn66abNettue-MpM,1100 +SQLAlchemy-2.0.36.dist-info/METADATA,sha256=EZH514FydYtyOhgoZk_OF1ZQEtI4eTAEddlnUlRjzac,9692 +SQLAlchemy-2.0.36.dist-info/RECORD,, +SQLAlchemy-2.0.36.dist-info/REQUESTED,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0 +SQLAlchemy-2.0.36.dist-info/WHEEL,sha256=7B4nnId14TToQHuAKpxbDLCJbNciqBsV-mvXE2hVLJc,151 +SQLAlchemy-2.0.36.dist-info/top_level.txt,sha256=rp-ZgB7D8G11ivXON5VGPjupT1voYmWqkciDt5Uaw_Q,11 +sqlalchemy/__init__.py,sha256=J2PsdiJiNW93Etxk6YN8o_C3TcpR1_DckU71r4LBcGE,13033 +sqlalchemy/__pycache__/__init__.cpython-312.pyc,, +sqlalchemy/__pycache__/events.cpython-312.pyc,, +sqlalchemy/__pycache__/exc.cpython-312.pyc,, +sqlalchemy/__pycache__/inspection.cpython-312.pyc,, +sqlalchemy/__pycache__/log.cpython-312.pyc,, +sqlalchemy/__pycache__/schema.cpython-312.pyc,, +sqlalchemy/__pycache__/types.cpython-312.pyc,, +sqlalchemy/connectors/__init__.py,sha256=PzXPqZqi3BzEnrs1eW0DcsR4lyknAzhhN9rWcQ97hb4,476 +sqlalchemy/connectors/__pycache__/__init__.cpython-312.pyc,, +sqlalchemy/connectors/__pycache__/aioodbc.cpython-312.pyc,, +sqlalchemy/connectors/__pycache__/asyncio.cpython-312.pyc,, +sqlalchemy/connectors/__pycache__/pyodbc.cpython-312.pyc,, +sqlalchemy/connectors/aioodbc.py,sha256=GSTiNMO9h0qjPxgqaxDwWZ8HvhWMFNVR6MJQnN1oc40,5288 +sqlalchemy/connectors/asyncio.py,sha256=Hq2bkXmG6-KO_RfCrwMqx4oGH-uH1Z1WWKqPWNjz8p4,6138 +sqlalchemy/connectors/pyodbc.py,sha256=t7AjyxIOnaWg3CrlUEpBs4Y5l0HFdNt3P_cSSKhbi0Y,8501 +sqlalchemy/cyextension/__init__.py,sha256=GzhhN8cjMnDTE0qerlUlpbrNmFPHQWCZ4Gk74OAxl04,244 +sqlalchemy/cyextension/__pycache__/__init__.cpython-312.pyc,, +sqlalchemy/cyextension/collections.cpython-312-x86_64-linux-gnu.so,sha256=ofziMIrcxCV-AGNBEvHL7QorRR2SPA9bkQj_k3WLD9E,1932256 +sqlalchemy/cyextension/collections.pyx,sha256=L7DZ3DGKpgw2MT2ZZRRxCnrcyE5pU1NAFowWgAzQPEc,12571 +sqlalchemy/cyextension/immutabledict.cpython-312-x86_64-linux-gnu.so,sha256=7SNuSRYPX4hzKqjAtbxJT2xLwa6Aegqtjfc9MYYZV0w,805632 +sqlalchemy/cyextension/immutabledict.pxd,sha256=3x3-rXG5eRQ7bBnktZ-OJ9-6ft8zToPmTDOd92iXpB0,291 +sqlalchemy/cyextension/immutabledict.pyx,sha256=KfDTYbTfebstE8xuqAtuXsHNAK0_b5q_ymUiinUe_xs,3535 +sqlalchemy/cyextension/processors.cpython-312-x86_64-linux-gnu.so,sha256=hBeVC8lWoCgLmD5det5fcoL4V8LYT9Cu8TRLaAzWeW0,530680 +sqlalchemy/cyextension/processors.pyx,sha256=R1rHsGLEaGeBq5VeCydjClzYlivERIJ9B-XLOJlf2MQ,1792 +sqlalchemy/cyextension/resultproxy.cpython-312-x86_64-linux-gnu.so,sha256=n6E3F0rPZFVUnpAm1pr3T-Rc8ZMqUcLjdRoOetVvJ8M,621328 +sqlalchemy/cyextension/resultproxy.pyx,sha256=eWLdyBXiBy_CLQrF5ScfWJm7X0NeelscSXedtj1zv9Q,2725 +sqlalchemy/cyextension/util.cpython-312-x86_64-linux-gnu.so,sha256=IbH9FP4ihbuGMhZ95oiRo_6F2wkSAlE2YDzegCVqErg,950928 +sqlalchemy/cyextension/util.pyx,sha256=B85orxa9LddLuQEaDoVSq1XmAXIbLKxrxpvuB8ogV_o,2530 +sqlalchemy/dialects/__init__.py,sha256=Kos9Gf5JZg1Vg6GWaCqEbD6e0r1jCwCmcnJIfcxDdcY,1770 +sqlalchemy/dialects/__pycache__/__init__.cpython-312.pyc,, +sqlalchemy/dialects/__pycache__/_typing.cpython-312.pyc,, +sqlalchemy/dialects/_typing.py,sha256=hyv0nKucX2gI8ispB1IsvaUgrEPn9zEcq9hS7kfstEw,888 +sqlalchemy/dialects/mssql/__init__.py,sha256=r5t8wFRNtBQoiUWh0WfIEWzXZW6f3D0uDt6NZTW_7Cc,1880 +sqlalchemy/dialects/mssql/__pycache__/__init__.cpython-312.pyc,, +sqlalchemy/dialects/mssql/__pycache__/aioodbc.cpython-312.pyc,, +sqlalchemy/dialects/mssql/__pycache__/base.cpython-312.pyc,, +sqlalchemy/dialects/mssql/__pycache__/information_schema.cpython-312.pyc,, +sqlalchemy/dialects/mssql/__pycache__/json.cpython-312.pyc,, +sqlalchemy/dialects/mssql/__pycache__/provision.cpython-312.pyc,, +sqlalchemy/dialects/mssql/__pycache__/pymssql.cpython-312.pyc,, +sqlalchemy/dialects/mssql/__pycache__/pyodbc.cpython-312.pyc,, +sqlalchemy/dialects/mssql/aioodbc.py,sha256=UQd9ecSMIML713TDnLAviuBVJle7P7i1FtqGZZePk2Y,2022 +sqlalchemy/dialects/mssql/base.py,sha256=msl_N_a_z8ali7Nthx55AGoV7b5wakCWvWu560BvH9o,132423 +sqlalchemy/dialects/mssql/information_schema.py,sha256=HswjDc6y0mPXCf_x6VyylHlBdBa4PSY6Evxmmlch700,8084 +sqlalchemy/dialects/mssql/json.py,sha256=evUACW2O62TAPq8B7QIPagz7jfc664ql9ms68JqiYzg,4816 +sqlalchemy/dialects/mssql/provision.py,sha256=ZAtt6Div9NLIngMs8kyloxfphw0KDNMsnRCAVd7-esE,5593 +sqlalchemy/dialects/mssql/pymssql.py,sha256=LAv43q4vBCB85OsAwHQItaQUYTYIO0QJ-jvzaBrswmY,4097 +sqlalchemy/dialects/mssql/pyodbc.py,sha256=vwM-vBlmRwrqxOc73P0sFOrBSwn24wzc5IkEOpalbXQ,27056 +sqlalchemy/dialects/mysql/__init__.py,sha256=bxbi4hkysUK2OOVvr1F49akUj1cky27kKb07tgFzI9U,2153 +sqlalchemy/dialects/mysql/__pycache__/__init__.cpython-312.pyc,, +sqlalchemy/dialects/mysql/__pycache__/aiomysql.cpython-312.pyc,, +sqlalchemy/dialects/mysql/__pycache__/asyncmy.cpython-312.pyc,, +sqlalchemy/dialects/mysql/__pycache__/base.cpython-312.pyc,, +sqlalchemy/dialects/mysql/__pycache__/cymysql.cpython-312.pyc,, +sqlalchemy/dialects/mysql/__pycache__/dml.cpython-312.pyc,, +sqlalchemy/dialects/mysql/__pycache__/enumerated.cpython-312.pyc,, +sqlalchemy/dialects/mysql/__pycache__/expression.cpython-312.pyc,, +sqlalchemy/dialects/mysql/__pycache__/json.cpython-312.pyc,, +sqlalchemy/dialects/mysql/__pycache__/mariadb.cpython-312.pyc,, +sqlalchemy/dialects/mysql/__pycache__/mariadbconnector.cpython-312.pyc,, +sqlalchemy/dialects/mysql/__pycache__/mysqlconnector.cpython-312.pyc,, +sqlalchemy/dialects/mysql/__pycache__/mysqldb.cpython-312.pyc,, +sqlalchemy/dialects/mysql/__pycache__/provision.cpython-312.pyc,, +sqlalchemy/dialects/mysql/__pycache__/pymysql.cpython-312.pyc,, +sqlalchemy/dialects/mysql/__pycache__/pyodbc.cpython-312.pyc,, +sqlalchemy/dialects/mysql/__pycache__/reflection.cpython-312.pyc,, +sqlalchemy/dialects/mysql/__pycache__/reserved_words.cpython-312.pyc,, +sqlalchemy/dialects/mysql/__pycache__/types.cpython-312.pyc,, +sqlalchemy/dialects/mysql/aiomysql.py,sha256=-oMZnCqNsSki8mlQRTWIwiQPT1OVdZIuANkb90q8LAs,9999 +sqlalchemy/dialects/mysql/asyncmy.py,sha256=YpuuOh8VknEeqHqUXQGfQ3jhfO3Xb-vZv78Jq5cscJ0,10067 +sqlalchemy/dialects/mysql/base.py,sha256=giGlZNGrKsNMoSkbzY0PGgfamKjA9rOkSq1o5vKvno4,122755 +sqlalchemy/dialects/mysql/cymysql.py,sha256=eXT1ry0w_qRxjiO24M980c-8PZ9qSsbhqBHntjEiKB0,2300 +sqlalchemy/dialects/mysql/dml.py,sha256=HXJMAvimJsqvhj3UZO4vW_6LkF5RqaKbHvklAjor7yU,7645 +sqlalchemy/dialects/mysql/enumerated.py,sha256=ipEPPQqoXfFwcywNdcLlZCEzHBtnitHRah1Gn6nItcg,8448 +sqlalchemy/dialects/mysql/expression.py,sha256=lsmQCHKwfPezUnt27d2kR6ohk4IRFCA64KBS16kx5dc,4097 +sqlalchemy/dialects/mysql/json.py,sha256=l6MEZ0qp8FgiRrIQvOMhyEJq0q6OqiEnvDTx5Cbt9uQ,2269 +sqlalchemy/dialects/mysql/mariadb.py,sha256=kTfBLioLKk4JFFst4TY_iWqPtnvvQXFHknLfm89H2N8,853 +sqlalchemy/dialects/mysql/mariadbconnector.py,sha256=_S1aV93kyP52Nvj7HR9weThML4oUvSLsLqiVFdoLR2o,8623 +sqlalchemy/dialects/mysql/mysqlconnector.py,sha256=oq3mtsNOMldUjs32JbJG2u3Hy3DObyVzUUMYfOkwkHg,5729 +sqlalchemy/dialects/mysql/mysqldb.py,sha256=qUBbA6STeYGozutyTxHCo5p1W3p59QFFS2FwCgPrjBA,9503 +sqlalchemy/dialects/mysql/provision.py,sha256=Jnk8UO9_Apd2odR2IQFLrscCfAmYxuBKcB8giS3bBog,3575 +sqlalchemy/dialects/mysql/pymysql.py,sha256=GUnSHd2M2uKjmN46Hheymtm26g7phEgwYOXrX0zLY8M,4083 +sqlalchemy/dialects/mysql/pyodbc.py,sha256=072crI4qVyPhajYvHnsfFeSrNjLFVPIjBQKo5uyz5yk,4297 +sqlalchemy/dialects/mysql/reflection.py,sha256=3u34YwT1JJh3uThGZJZ3FKdnUcT7v08QB-tAl1r7VRk,22834 +sqlalchemy/dialects/mysql/reserved_words.py,sha256=ucKX2p2c3UnMq2ayZuOHuf73eXhu7SKsOsTlIN1Q83I,9258 +sqlalchemy/dialects/mysql/types.py,sha256=L5cTCsMT1pTedszNEM3jSxFNZEMcHQLprYCZ0vmfsnA,24343 +sqlalchemy/dialects/oracle/__init__.py,sha256=p4-2gw7TT0bX_MoJXTGD4i8WHctYsK9kCRbkpzykBrc,1493 +sqlalchemy/dialects/oracle/__pycache__/__init__.cpython-312.pyc,, +sqlalchemy/dialects/oracle/__pycache__/base.cpython-312.pyc,, +sqlalchemy/dialects/oracle/__pycache__/cx_oracle.cpython-312.pyc,, +sqlalchemy/dialects/oracle/__pycache__/dictionary.cpython-312.pyc,, +sqlalchemy/dialects/oracle/__pycache__/oracledb.cpython-312.pyc,, +sqlalchemy/dialects/oracle/__pycache__/provision.cpython-312.pyc,, +sqlalchemy/dialects/oracle/__pycache__/types.cpython-312.pyc,, +sqlalchemy/dialects/oracle/base.py,sha256=zLMZedrr6j1LvJz4qYnoSjikI5RZY92YFeQHiZ_YvW0,119676 +sqlalchemy/dialects/oracle/cx_oracle.py,sha256=q8Nyj15UZCE2TWOmxuWp5ZsxiCiGMzqfd_9UkmjIja0,55235 +sqlalchemy/dialects/oracle/dictionary.py,sha256=7WMrbPkqo8ZdGjaEZyQr-5f2pajSOF1OTGb8P97z8-g,19519 +sqlalchemy/dialects/oracle/oracledb.py,sha256=fZRKGqNIwW9LG4i8yDOXABrucbfzn_yC86Od-BJ3PcM,13619 +sqlalchemy/dialects/oracle/provision.py,sha256=O9ZpF4OG6Cx4mMzLRfZwhs8dZjrJETWR402n9c7726A,8304 +sqlalchemy/dialects/oracle/types.py,sha256=QK3hJvWzKnnCe3oD3rItwEEIwcoBze8qGg7VFOvVlIk,8231 +sqlalchemy/dialects/postgresql/__init__.py,sha256=wwnNAq4wDQzrlPRzDNB06ayuq3L2HNO99nzeEvq-YcU,3892 +sqlalchemy/dialects/postgresql/__pycache__/__init__.cpython-312.pyc,, +sqlalchemy/dialects/postgresql/__pycache__/_psycopg_common.cpython-312.pyc,, +sqlalchemy/dialects/postgresql/__pycache__/array.cpython-312.pyc,, +sqlalchemy/dialects/postgresql/__pycache__/asyncpg.cpython-312.pyc,, +sqlalchemy/dialects/postgresql/__pycache__/base.cpython-312.pyc,, +sqlalchemy/dialects/postgresql/__pycache__/dml.cpython-312.pyc,, +sqlalchemy/dialects/postgresql/__pycache__/ext.cpython-312.pyc,, +sqlalchemy/dialects/postgresql/__pycache__/hstore.cpython-312.pyc,, +sqlalchemy/dialects/postgresql/__pycache__/json.cpython-312.pyc,, +sqlalchemy/dialects/postgresql/__pycache__/named_types.cpython-312.pyc,, +sqlalchemy/dialects/postgresql/__pycache__/operators.cpython-312.pyc,, +sqlalchemy/dialects/postgresql/__pycache__/pg8000.cpython-312.pyc,, +sqlalchemy/dialects/postgresql/__pycache__/pg_catalog.cpython-312.pyc,, +sqlalchemy/dialects/postgresql/__pycache__/provision.cpython-312.pyc,, +sqlalchemy/dialects/postgresql/__pycache__/psycopg.cpython-312.pyc,, +sqlalchemy/dialects/postgresql/__pycache__/psycopg2.cpython-312.pyc,, +sqlalchemy/dialects/postgresql/__pycache__/psycopg2cffi.cpython-312.pyc,, +sqlalchemy/dialects/postgresql/__pycache__/ranges.cpython-312.pyc,, +sqlalchemy/dialects/postgresql/__pycache__/types.cpython-312.pyc,, +sqlalchemy/dialects/postgresql/_psycopg_common.py,sha256=7TudtgsPiSB8O5kX8W8KxcNYR8t5h_UHb86b_ChL0P8,5696 +sqlalchemy/dialects/postgresql/array.py,sha256=bWcame7ntmI_Kx6gmBX0-chwADFdLHeCvaDQ4iX8id8,13734 +sqlalchemy/dialects/postgresql/asyncpg.py,sha256=9P0Itn9eeSBu67kGSsHuzx8xd4YYwRKdiZ5m7bF5onU,41074 +sqlalchemy/dialects/postgresql/base.py,sha256=dGPsaV3Esw6-AwE3QcgHF0Fray3Yw5-gLLgCvgdxvS0,179083 +sqlalchemy/dialects/postgresql/dml.py,sha256=Pc69Le6qzmUHHb1FT5zeUSD31dWm6SBgdCAGW89cs3s,11212 +sqlalchemy/dialects/postgresql/ext.py,sha256=1bZ--iNh2O9ym7l2gXZX48yP3yMO4dqb9RpYro2Mj2Q,16262 +sqlalchemy/dialects/postgresql/hstore.py,sha256=otAx-RTDfpi_tcXkMuQV0JOIXtYgevgnsikLKKOkI6U,11541 +sqlalchemy/dialects/postgresql/json.py,sha256=53rQWon9cUXd1yCjIvUpJjWwNyRSy3U7Kz0HV70ftrc,11618 +sqlalchemy/dialects/postgresql/named_types.py,sha256=3IV1ufo7zJjKmX4VtGDEnoXE6xEqLJAtGG82IiqHXwY,17594 +sqlalchemy/dialects/postgresql/operators.py,sha256=NsAaWun_tL3d_be0fs9YL6T4LPKK6crnmFxxIJHgyeY,2808 +sqlalchemy/dialects/postgresql/pg8000.py,sha256=3yoekiWSF-xnaWMqG76XrYPMqerg-42TdmfsW_ivK9E,18640 +sqlalchemy/dialects/postgresql/pg_catalog.py,sha256=hY3NXEUHxTWD4umhd2aowNu3laC-61Q_qQ_pReyXTUM,9254 +sqlalchemy/dialects/postgresql/provision.py,sha256=t6TZj0XaWG9zrpCjNr0oJRjAC_WQzaNdp3kaKJIbS8I,5770 +sqlalchemy/dialects/postgresql/psycopg.py,sha256=Uwf45f9fInOtaExiEdwiP9xzRo7hw0XyZTkRtgdom44,23168 +sqlalchemy/dialects/postgresql/psycopg2.py,sha256=kwEnflz5bAqJcuO_20eYiCtha_a4m_tg5_lppdDnaeU,31998 +sqlalchemy/dialects/postgresql/psycopg2cffi.py,sha256=M7wAYSL6Pvt-4nbfacAHGyyw4XMKJ_bQZ1tc1pBtIdg,1756 +sqlalchemy/dialects/postgresql/ranges.py,sha256=6CgV7qkxEMJ9AQsiibo_XBLJYzGh-2ZxpG83sRaesVY,32949 +sqlalchemy/dialects/postgresql/types.py,sha256=Jfxqw9JaKNOq29JRWBublywgb3lLMyzx8YZI7CXpS2s,7300 +sqlalchemy/dialects/sqlite/__init__.py,sha256=lp9DIggNn349M-7IYhUA8et8--e8FRExWD2V_r1LJk4,1182 +sqlalchemy/dialects/sqlite/__pycache__/__init__.cpython-312.pyc,, +sqlalchemy/dialects/sqlite/__pycache__/aiosqlite.cpython-312.pyc,, +sqlalchemy/dialects/sqlite/__pycache__/base.cpython-312.pyc,, +sqlalchemy/dialects/sqlite/__pycache__/dml.cpython-312.pyc,, +sqlalchemy/dialects/sqlite/__pycache__/json.cpython-312.pyc,, +sqlalchemy/dialects/sqlite/__pycache__/provision.cpython-312.pyc,, +sqlalchemy/dialects/sqlite/__pycache__/pysqlcipher.cpython-312.pyc,, +sqlalchemy/dialects/sqlite/__pycache__/pysqlite.cpython-312.pyc,, +sqlalchemy/dialects/sqlite/aiosqlite.py,sha256=g3qGV6jmiXabWyb3282g_Nmxtj1jThxGSe9C9yalb-U,12345 +sqlalchemy/dialects/sqlite/base.py,sha256=LcnW6hzxqTtPlDBOInHumvuDt8a31THA5Jnm4vFvdFI,97811 +sqlalchemy/dialects/sqlite/dml.py,sha256=9GE55WvwoktKy2fHeT-Wbc9xPHgsbh5oBfd_fckMH5Q,8443 +sqlalchemy/dialects/sqlite/json.py,sha256=Eoplbb_4dYlfrtmQaI8Xddd2suAIHA-IdbDQYM-LIhs,2777 +sqlalchemy/dialects/sqlite/provision.py,sha256=UCpmwxf4IWlrpb2eLHGbPTpCFVbdI_KAh2mKtjiLYao,5632 +sqlalchemy/dialects/sqlite/pysqlcipher.py,sha256=OL2S_05DK9kllZj6DOz7QtEl7jI7syxjW6woS725ii4,5356 +sqlalchemy/dialects/sqlite/pysqlite.py,sha256=aDp47n0J509kl2hDchoaBKXEQVZtkux54DwfKytUAe4,28068 +sqlalchemy/dialects/type_migration_guidelines.txt,sha256=-uHNdmYFGB7bzUNT6i8M5nb4j6j9YUKAtW4lcBZqsMg,8239 +sqlalchemy/engine/__init__.py,sha256=Stb2oV6l8w65JvqEo6J4qtKoApcmOpXy3AAxQud4C1o,2818 +sqlalchemy/engine/__pycache__/__init__.cpython-312.pyc,, +sqlalchemy/engine/__pycache__/_py_processors.cpython-312.pyc,, +sqlalchemy/engine/__pycache__/_py_row.cpython-312.pyc,, +sqlalchemy/engine/__pycache__/_py_util.cpython-312.pyc,, +sqlalchemy/engine/__pycache__/base.cpython-312.pyc,, +sqlalchemy/engine/__pycache__/characteristics.cpython-312.pyc,, +sqlalchemy/engine/__pycache__/create.cpython-312.pyc,, +sqlalchemy/engine/__pycache__/cursor.cpython-312.pyc,, +sqlalchemy/engine/__pycache__/default.cpython-312.pyc,, +sqlalchemy/engine/__pycache__/events.cpython-312.pyc,, +sqlalchemy/engine/__pycache__/interfaces.cpython-312.pyc,, +sqlalchemy/engine/__pycache__/mock.cpython-312.pyc,, +sqlalchemy/engine/__pycache__/processors.cpython-312.pyc,, +sqlalchemy/engine/__pycache__/reflection.cpython-312.pyc,, +sqlalchemy/engine/__pycache__/result.cpython-312.pyc,, +sqlalchemy/engine/__pycache__/row.cpython-312.pyc,, +sqlalchemy/engine/__pycache__/strategies.cpython-312.pyc,, +sqlalchemy/engine/__pycache__/url.cpython-312.pyc,, +sqlalchemy/engine/__pycache__/util.cpython-312.pyc,, +sqlalchemy/engine/_py_processors.py,sha256=j9i_lcYYQOYJMcsDerPxI0sVFBIlX5sqoYMdMJlgWPI,3744 +sqlalchemy/engine/_py_row.py,sha256=wSqoUFzLOJ1f89kgDb6sJm9LUrF5LMFpXPcK1vUsKcs,3787 +sqlalchemy/engine/_py_util.py,sha256=f2DI3AN1kv6EplelowesCVpwS8hSXNufRkZoQmJtSH8,2484 +sqlalchemy/engine/base.py,sha256=frWSMmt3dlentYH4QNN3cijdGzp8NbunColUZwWsWgI,122958 +sqlalchemy/engine/characteristics.py,sha256=N3kbvw_ApMh86wb5yAGnxtPYD4YRhYMWion1H_aVZBI,4765 +sqlalchemy/engine/create.py,sha256=mYJtOG2ZKM8sgyfjpGpamW15RDU7JXi5s6iibbJHMIs,33206 +sqlalchemy/engine/cursor.py,sha256=cFq61yrw76k-QR_xNUBWuL-Zeyb14ltG-6jo2Q2iuuw,76392 +sqlalchemy/engine/default.py,sha256=2wwKKdsagb3QTajRSEw8Hl-EnQ-LmRxy822xOGyenHc,84648 +sqlalchemy/engine/events.py,sha256=c0unNFFiHzTAvkUtXoJaxzMFMDwurBkHiiUhuN8qluc,37381 +sqlalchemy/engine/interfaces.py,sha256=fcVHOmnMo7JZLHzgSKoK3QsdVHH7kJ_AmrDvwW9Ka3k,112936 +sqlalchemy/engine/mock.py,sha256=yvpxgFmRw5G4QsHeF-ZwQGHKES-HqQOucTxFtN1uzdk,4179 +sqlalchemy/engine/processors.py,sha256=XyfINKbo-2fjN-mW55YybvFyQMOil50_kVqsunahkNs,2379 +sqlalchemy/engine/reflection.py,sha256=gwGs8y7x6py5z-ZWx3hQqQrwpHepMCTJyQcFwWJjPlw,75364 +sqlalchemy/engine/result.py,sha256=NZEskTMAcDzK-vjE96Fw8VvBL58s5Y6rt9vXcmZdM4w,77651 +sqlalchemy/engine/row.py,sha256=9AAQo9zYDL88GcZ3bjcQTwMT-YIcuGTSMAyTfmBJ_yM,12032 +sqlalchemy/engine/strategies.py,sha256=DqFSWaXJPL-29Omot9O0aOcuGL8KmCGyOvnPGDkAJoE,442 +sqlalchemy/engine/url.py,sha256=8eWkUaIUyDExOcJ2D4xJXRcn4OY1GQJ3Q2duSX6UGAg,30784 +sqlalchemy/engine/util.py,sha256=bNirO8k1S8yOW61uNH-a9QrWtAJ9VGFgbiR0lk1lUQU,5682 +sqlalchemy/event/__init__.py,sha256=KBrp622xojnC3FFquxa2JsMamwAbfkvzfv6Op0NKiYc,997 +sqlalchemy/event/__pycache__/__init__.cpython-312.pyc,, +sqlalchemy/event/__pycache__/api.cpython-312.pyc,, +sqlalchemy/event/__pycache__/attr.cpython-312.pyc,, +sqlalchemy/event/__pycache__/base.cpython-312.pyc,, +sqlalchemy/event/__pycache__/legacy.cpython-312.pyc,, +sqlalchemy/event/__pycache__/registry.cpython-312.pyc,, +sqlalchemy/event/api.py,sha256=DtDVgjKSorOfp9MGJ7fgMWrj4seC_hkwF4D8CW1RFZU,8226 +sqlalchemy/event/attr.py,sha256=X8QeHGK4ioSYht1vkhc11f606_mq_t91jMNIT314ubs,20751 +sqlalchemy/event/base.py,sha256=270OShTD17-bSFUFnPtKdVnB0NFJZ2AouYPo1wT0aJw,15127 +sqlalchemy/event/legacy.py,sha256=teMPs00fO-4g8a_z2omcVKkYce5wj_1uvJO2n2MIeuo,8227 +sqlalchemy/event/registry.py,sha256=nfTSSyhjZZXc5wseWB4sXn-YibSc0LKX8mg17XlWmAo,10835 +sqlalchemy/events.py,sha256=k-ZD38aSPD29LYhED7CBqttp5MDVVx_YSaWC2-cu9ec,525 +sqlalchemy/exc.py,sha256=M_8-O1hd8i6gbyx-TapV400p_Lxq2QqTGMXUAO-YgCc,23976 +sqlalchemy/ext/__init__.py,sha256=S1fGKAbycnQDV01gs-JWGaFQ9GCD4QHwKcU2wnugg_o,322 +sqlalchemy/ext/__pycache__/__init__.cpython-312.pyc,, +sqlalchemy/ext/__pycache__/associationproxy.cpython-312.pyc,, +sqlalchemy/ext/__pycache__/automap.cpython-312.pyc,, +sqlalchemy/ext/__pycache__/baked.cpython-312.pyc,, +sqlalchemy/ext/__pycache__/compiler.cpython-312.pyc,, +sqlalchemy/ext/__pycache__/horizontal_shard.cpython-312.pyc,, +sqlalchemy/ext/__pycache__/hybrid.cpython-312.pyc,, +sqlalchemy/ext/__pycache__/indexable.cpython-312.pyc,, +sqlalchemy/ext/__pycache__/instrumentation.cpython-312.pyc,, +sqlalchemy/ext/__pycache__/mutable.cpython-312.pyc,, +sqlalchemy/ext/__pycache__/orderinglist.cpython-312.pyc,, +sqlalchemy/ext/__pycache__/serializer.cpython-312.pyc,, +sqlalchemy/ext/associationproxy.py,sha256=ZGc_ssGf7FC6eKrja1iTvnWEKLkFZQA8CiVAjR8iVRw,66062 +sqlalchemy/ext/asyncio/__init__.py,sha256=1OqSxEyIUn7RWLGyO12F-jAUIvk1I6DXlVy80-Gvkds,1317 +sqlalchemy/ext/asyncio/__pycache__/__init__.cpython-312.pyc,, +sqlalchemy/ext/asyncio/__pycache__/base.cpython-312.pyc,, +sqlalchemy/ext/asyncio/__pycache__/engine.cpython-312.pyc,, +sqlalchemy/ext/asyncio/__pycache__/exc.cpython-312.pyc,, +sqlalchemy/ext/asyncio/__pycache__/result.cpython-312.pyc,, +sqlalchemy/ext/asyncio/__pycache__/scoping.cpython-312.pyc,, +sqlalchemy/ext/asyncio/__pycache__/session.cpython-312.pyc,, +sqlalchemy/ext/asyncio/base.py,sha256=fl7wxZD9KjgFiCtG3WXrYjHEvanamcsodCqq9pH9lOk,8905 +sqlalchemy/ext/asyncio/engine.py,sha256=S_IRWX4QAjj2veLSu4Y3gKBIXkKQt7_2StJAK2_KUDY,48190 +sqlalchemy/ext/asyncio/exc.py,sha256=8sII7VMXzs2TrhizhFQMzSfcroRtiesq8o3UwLfXSgQ,639 +sqlalchemy/ext/asyncio/result.py,sha256=3rbVIY_wySi50JwaK3Kf2qa3c5Fc8W84FtUpt-9i9Vk,30477 +sqlalchemy/ext/asyncio/scoping.py,sha256=UxHAFxtWKqA7TEozyN2h7MJyzSspTCrS-1SlgQLTExo,52608 +sqlalchemy/ext/asyncio/session.py,sha256=QpXnqspwYnT28znD1EdpUIaVjQOO1BirtS0BJeBxeZk,63087 +sqlalchemy/ext/automap.py,sha256=r0mUSyogNyqdBL4m9AA1NXbLiTLQmtvyQymsssNEipo,61581 +sqlalchemy/ext/baked.py,sha256=H6T1il7GY84BhzPFj49UECSpZh_eBuiHomA-QIsYOYQ,17807 +sqlalchemy/ext/compiler.py,sha256=6X6sZCAo9v-PQfLbwBSYQUK0-XH2xTE5Jm0Zg6Ka6eM,20877 +sqlalchemy/ext/declarative/__init__.py,sha256=20psLdFQbbOWfpdXHZ0CTY6I1k4UqXvKemNVu1LvPOI,1818 +sqlalchemy/ext/declarative/__pycache__/__init__.cpython-312.pyc,, +sqlalchemy/ext/declarative/__pycache__/extensions.cpython-312.pyc,, +sqlalchemy/ext/declarative/extensions.py,sha256=uCjN1GisQt54AjqYnKYzJdUjnGd2pZBW47WWdPlS7FE,19547 +sqlalchemy/ext/horizontal_shard.py,sha256=wuwAPnHymln0unSBnyx-cpX0AfESKSsypaSQTYCvzDk,16750 +sqlalchemy/ext/hybrid.py,sha256=IYkCaPZ29gm2cPKPg0cWMkLCEqMykD8-JJTvgacGbmc,52458 +sqlalchemy/ext/indexable.py,sha256=UkTelbydKCdKelzbv3HWFFavoET9WocKaGRPGEOVfN8,11032 +sqlalchemy/ext/instrumentation.py,sha256=sg8ghDjdHSODFXh_jAmpgemnNX1rxCeeXEG3-PMdrNk,15707 +sqlalchemy/ext/mutable.py,sha256=L5ZkHBGYhMaqO75Xtyrk2DBR44RDk0g6Rz2HzHH0F8Q,37355 +sqlalchemy/ext/mypy/__init__.py,sha256=0WebDIZmqBD0OTq5JLtd_PmfF9JGxe4d4Qv3Ml3PKUg,241 +sqlalchemy/ext/mypy/__pycache__/__init__.cpython-312.pyc,, +sqlalchemy/ext/mypy/__pycache__/apply.cpython-312.pyc,, +sqlalchemy/ext/mypy/__pycache__/decl_class.cpython-312.pyc,, +sqlalchemy/ext/mypy/__pycache__/infer.cpython-312.pyc,, +sqlalchemy/ext/mypy/__pycache__/names.cpython-312.pyc,, +sqlalchemy/ext/mypy/__pycache__/plugin.cpython-312.pyc,, +sqlalchemy/ext/mypy/__pycache__/util.cpython-312.pyc,, +sqlalchemy/ext/mypy/apply.py,sha256=Aek_-XA1eXihT4attxhfE43yBKtCgsxBSb--qgZKUqc,10550 +sqlalchemy/ext/mypy/decl_class.py,sha256=1vVJRII2apnLTUbc5HkJS6Z2GueaUv_eKvhbqh7Wik4,17384 +sqlalchemy/ext/mypy/infer.py,sha256=KVnmLFEVS33Al8pUKI7MJbJQu3KeveBUMl78EluBORw,19369 +sqlalchemy/ext/mypy/names.py,sha256=Q3ef8XQBgVm9WUwlItqlYCXDNi_kbV5DdLEgbtEMEI8,10479 +sqlalchemy/ext/mypy/plugin.py,sha256=74ML8LI9xar0V86oCxnPFv5FQGEEfUzK64vOay4BKFs,9750 +sqlalchemy/ext/mypy/util.py,sha256=DKRaurkXHI2lAMAAcEO5GLXbX_m2Xqy7l_juh8Byf5U,9960 +sqlalchemy/ext/orderinglist.py,sha256=TGYbsGH72wEZcFNQDYDsZg9OSPuzf__P8YX8_2HtYUo,14384 +sqlalchemy/ext/serializer.py,sha256=D0g4jMZkRk0Gjr0L-FZe81SR63h0Zs-9JzuWtT_SD7k,6140 +sqlalchemy/future/__init__.py,sha256=q2mw-gxk_xoxJLEvRoyMha3vO1xSRHrslcExOHZwmPA,512 +sqlalchemy/future/__pycache__/__init__.cpython-312.pyc,, +sqlalchemy/future/__pycache__/engine.cpython-312.pyc,, +sqlalchemy/future/engine.py,sha256=AgIw6vMsef8W6tynOTkxsjd6o_OQDwGjLdbpoMD8ue8,495 +sqlalchemy/inspection.py,sha256=MF-LE358wZDUEl1IH8-Uwt2HI65EsQpQW5o5udHkZwA,5063 +sqlalchemy/log.py,sha256=8x9UR3nj0uFm6or6bQF-JWb4fYv2zOeQjG_w-0wOJFA,8607 +sqlalchemy/orm/__init__.py,sha256=ZYys5nL3RFUDCMOLFDBrRI52F6er3S1U1OY9TeORuKs,8463 +sqlalchemy/orm/__pycache__/__init__.cpython-312.pyc,, +sqlalchemy/orm/__pycache__/_orm_constructors.cpython-312.pyc,, +sqlalchemy/orm/__pycache__/_typing.cpython-312.pyc,, +sqlalchemy/orm/__pycache__/attributes.cpython-312.pyc,, +sqlalchemy/orm/__pycache__/base.cpython-312.pyc,, +sqlalchemy/orm/__pycache__/bulk_persistence.cpython-312.pyc,, +sqlalchemy/orm/__pycache__/clsregistry.cpython-312.pyc,, +sqlalchemy/orm/__pycache__/collections.cpython-312.pyc,, +sqlalchemy/orm/__pycache__/context.cpython-312.pyc,, +sqlalchemy/orm/__pycache__/decl_api.cpython-312.pyc,, +sqlalchemy/orm/__pycache__/decl_base.cpython-312.pyc,, +sqlalchemy/orm/__pycache__/dependency.cpython-312.pyc,, +sqlalchemy/orm/__pycache__/descriptor_props.cpython-312.pyc,, +sqlalchemy/orm/__pycache__/dynamic.cpython-312.pyc,, +sqlalchemy/orm/__pycache__/evaluator.cpython-312.pyc,, +sqlalchemy/orm/__pycache__/events.cpython-312.pyc,, +sqlalchemy/orm/__pycache__/exc.cpython-312.pyc,, +sqlalchemy/orm/__pycache__/identity.cpython-312.pyc,, +sqlalchemy/orm/__pycache__/instrumentation.cpython-312.pyc,, +sqlalchemy/orm/__pycache__/interfaces.cpython-312.pyc,, +sqlalchemy/orm/__pycache__/loading.cpython-312.pyc,, +sqlalchemy/orm/__pycache__/mapped_collection.cpython-312.pyc,, +sqlalchemy/orm/__pycache__/mapper.cpython-312.pyc,, +sqlalchemy/orm/__pycache__/path_registry.cpython-312.pyc,, +sqlalchemy/orm/__pycache__/persistence.cpython-312.pyc,, +sqlalchemy/orm/__pycache__/properties.cpython-312.pyc,, +sqlalchemy/orm/__pycache__/query.cpython-312.pyc,, +sqlalchemy/orm/__pycache__/relationships.cpython-312.pyc,, +sqlalchemy/orm/__pycache__/scoping.cpython-312.pyc,, +sqlalchemy/orm/__pycache__/session.cpython-312.pyc,, +sqlalchemy/orm/__pycache__/state.cpython-312.pyc,, +sqlalchemy/orm/__pycache__/state_changes.cpython-312.pyc,, +sqlalchemy/orm/__pycache__/strategies.cpython-312.pyc,, +sqlalchemy/orm/__pycache__/strategy_options.cpython-312.pyc,, +sqlalchemy/orm/__pycache__/sync.cpython-312.pyc,, +sqlalchemy/orm/__pycache__/unitofwork.cpython-312.pyc,, +sqlalchemy/orm/__pycache__/util.cpython-312.pyc,, +sqlalchemy/orm/__pycache__/writeonly.cpython-312.pyc,, +sqlalchemy/orm/_orm_constructors.py,sha256=8EQfYsDL2k_ev0eK-wxMl3algouczN38Gu43CrRlAlo,103434 +sqlalchemy/orm/_typing.py,sha256=DVBfpHmDVK4x1zxaGJPY2GoTrAsyR6uexv20Lzf1afc,4973 +sqlalchemy/orm/attributes.py,sha256=lorOHBJvJJYndOuafWJhHBbQ1pR6FAyimhqz-mErBRQ,92534 +sqlalchemy/orm/base.py,sha256=FXkYTSCDUJFQSB5pcyPt2wG-dRctf5P6ySjyjVxQsX0,27502 +sqlalchemy/orm/bulk_persistence.py,sha256=1FC23bRJKjpfbp2D5hYuV1qOVIKGSswu9XPXbbSJ5Mo,72663 +sqlalchemy/orm/clsregistry.py,sha256=IjoDZwWpjG42ji59L4M1EZvjBEoXPZykzENDtKWxU8A,17974 +sqlalchemy/orm/collections.py,sha256=WEKuUCRgLhDhJEIBhZ21UrE0pBOyRm2zxD20GvbgA9g,52243 +sqlalchemy/orm/context.py,sha256=FMPyw07OA9OXWQ32RQx52AEa2xTLSkqdYgx9R_yN1x0,112955 +sqlalchemy/orm/decl_api.py,sha256=_WPKQ_vSE5k2TLtNmkaxxYmvbhZvkRMrrvCeDxdqDQE,63998 +sqlalchemy/orm/decl_base.py,sha256=8R7go5sULTYNRlhYiEjXIJkQ34oPp7DY_fC2nS5D5is,83343 +sqlalchemy/orm/dependency.py,sha256=hgjksUWhgbmgHK5GdJdiDCBgDAIGQXIrY-Tj79tbL2k,47631 +sqlalchemy/orm/descriptor_props.py,sha256=dR_h4Gvdtpcdp4sj_ZOR4P5Nng2J2vhsvFHouRLlntc,37244 +sqlalchemy/orm/dynamic.py,sha256=rWAZ-nfAkREuNjt8e_FRdqYrvHDdbODn1CcfyP8Y18k,9816 +sqlalchemy/orm/evaluator.py,sha256=tRETz4dNZ71VsEA8nG0hpefByB-W0zBt02IxcSR5H2g,12353 +sqlalchemy/orm/events.py,sha256=1PiGT7JMUWTDAb3X1T79P02BMVDmcWEpatz1FwpLqoA,127777 +sqlalchemy/orm/exc.py,sha256=IP40P-wOeXhkYk0YizuTC3wqm6W9cPTaQU08f5MMaQ0,7413 +sqlalchemy/orm/identity.py,sha256=jHdCxCpCyda_8mFOfGmN_Pr0XZdKiU-2hFZshlNxbHs,9249 +sqlalchemy/orm/instrumentation.py,sha256=M-kZmkUvHUxtf-0mCA8RIM5QmMH1hWlYR_pKMwaidjA,24321 +sqlalchemy/orm/interfaces.py,sha256=7Lni4Cue41b1CsmN4VbeUyWwzuNMcKtkrpihc9U-WIw,48690 +sqlalchemy/orm/loading.py,sha256=9RacpzFOWbuKgPRWHFmyIvD4fYCLAnkpwBFASyQ2CoI,58277 +sqlalchemy/orm/mapped_collection.py,sha256=zK3d3iozORzDruBUrAmkVC0RR3Orj5szk-TSQ24xzIU,19682 +sqlalchemy/orm/mapper.py,sha256=W-srpoEc3UIYv_6qTXTd_dG_TVeQcToG77VGrXt85PM,171738 +sqlalchemy/orm/path_registry.py,sha256=sJZMv_WPqUpHfQtKWaX3WYFeKBcNJ8C3wOM2mkBGkTE,25920 +sqlalchemy/orm/persistence.py,sha256=dzyB2JOXNwQgaCbN8kh0sEz00WFePr48qf8NWVCUZH8,61701 +sqlalchemy/orm/properties.py,sha256=eDPFzxYUgdM3uWjHywnb1XW-i0tVKKyx7A2MCD31GQU,29306 +sqlalchemy/orm/query.py,sha256=Cf0e94-u1XyoXJoOAmr4iFvtCwNY98kxUYyMPenaWTE,117708 +sqlalchemy/orm/relationships.py,sha256=dS5SY0v1MiD7iCNnAQlHaI6prUQhL5EkXT7ijc8FR8E,128644 +sqlalchemy/orm/scoping.py,sha256=rJVc7_Lic4V00HZ-UvYFWkVpXqdrMayRmIs4fIwH1UA,78688 +sqlalchemy/orm/session.py,sha256=CZJTQ-wPwIy0c3AMFxgJnBgaft6eEf4JzcCLcaaCSjg,195979 +sqlalchemy/orm/state.py,sha256=327-F4TG29s6mLC8oWRiO2PuvYIUZzY1MqUPjtUy7M4,37670 +sqlalchemy/orm/state_changes.py,sha256=qKYg7NxwrDkuUY3EPygAztym6oAVUFcP2wXn7QD3Mz4,6815 +sqlalchemy/orm/strategies.py,sha256=-tsBRsmEqkaxAAIn4t2F-U5SrRIPoPCyzpqFYGTAwNs,119866 +sqlalchemy/orm/strategy_options.py,sha256=oeDl_rMDNAC_90N7ytsni-psXWAeQMhABQFyKBSmai0,85353 +sqlalchemy/orm/sync.py,sha256=g7iZfSge1HgxMk9SKRgUgtHEbpbZ1kP_CBqOIdTOXqc,5779 +sqlalchemy/orm/unitofwork.py,sha256=fiVaqcymbDDHRa1NjS90N9Z466nd5pkJOEi1dHO6QLY,27033 +sqlalchemy/orm/util.py,sha256=5SC4MOVU0cPObexDjpMvXvetueiU5pze42raL94gj24,81021 +sqlalchemy/orm/writeonly.py,sha256=SYu2sAaHZONk2pW4PmtE871LG-O0P_bjidvKzY1H_zI,22305 +sqlalchemy/pool/__init__.py,sha256=qiDdq4r4FFAoDrK6ncugF_i6usi_X1LeJt-CuBHey0s,1804 +sqlalchemy/pool/__pycache__/__init__.cpython-312.pyc,, +sqlalchemy/pool/__pycache__/base.cpython-312.pyc,, +sqlalchemy/pool/__pycache__/events.cpython-312.pyc,, +sqlalchemy/pool/__pycache__/impl.cpython-312.pyc,, +sqlalchemy/pool/base.py,sha256=WF4az4ZKuzQGuKeSJeyexaYjmWZUvYdC6KIi8zTGodw,52236 +sqlalchemy/pool/events.py,sha256=xGjkIUZl490ZDtCHqnQF9ZCwe2Jv93eGXmnQxftB11E,13147 +sqlalchemy/pool/impl.py,sha256=JwpALSkH-pCoO_6oENbkHYY00Jx9nlttyoI61LivRNc,18944 +sqlalchemy/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0 +sqlalchemy/schema.py,sha256=dKiWmgHYjcKQ4TiiD6vD0UMmIsD8u0Fsor1M9AAeGUs,3194 +sqlalchemy/sql/__init__.py,sha256=UNa9EUiYWoPayf-FzNcwVgQvpsBdInPZfpJesAStN9o,5820 +sqlalchemy/sql/__pycache__/__init__.cpython-312.pyc,, +sqlalchemy/sql/__pycache__/_dml_constructors.cpython-312.pyc,, +sqlalchemy/sql/__pycache__/_elements_constructors.cpython-312.pyc,, +sqlalchemy/sql/__pycache__/_orm_types.cpython-312.pyc,, +sqlalchemy/sql/__pycache__/_py_util.cpython-312.pyc,, +sqlalchemy/sql/__pycache__/_selectable_constructors.cpython-312.pyc,, +sqlalchemy/sql/__pycache__/_typing.cpython-312.pyc,, +sqlalchemy/sql/__pycache__/annotation.cpython-312.pyc,, +sqlalchemy/sql/__pycache__/base.cpython-312.pyc,, +sqlalchemy/sql/__pycache__/cache_key.cpython-312.pyc,, +sqlalchemy/sql/__pycache__/coercions.cpython-312.pyc,, +sqlalchemy/sql/__pycache__/compiler.cpython-312.pyc,, +sqlalchemy/sql/__pycache__/crud.cpython-312.pyc,, +sqlalchemy/sql/__pycache__/ddl.cpython-312.pyc,, +sqlalchemy/sql/__pycache__/default_comparator.cpython-312.pyc,, +sqlalchemy/sql/__pycache__/dml.cpython-312.pyc,, +sqlalchemy/sql/__pycache__/elements.cpython-312.pyc,, +sqlalchemy/sql/__pycache__/events.cpython-312.pyc,, +sqlalchemy/sql/__pycache__/expression.cpython-312.pyc,, +sqlalchemy/sql/__pycache__/functions.cpython-312.pyc,, +sqlalchemy/sql/__pycache__/lambdas.cpython-312.pyc,, +sqlalchemy/sql/__pycache__/naming.cpython-312.pyc,, +sqlalchemy/sql/__pycache__/operators.cpython-312.pyc,, +sqlalchemy/sql/__pycache__/roles.cpython-312.pyc,, +sqlalchemy/sql/__pycache__/schema.cpython-312.pyc,, +sqlalchemy/sql/__pycache__/selectable.cpython-312.pyc,, +sqlalchemy/sql/__pycache__/sqltypes.cpython-312.pyc,, +sqlalchemy/sql/__pycache__/traversals.cpython-312.pyc,, +sqlalchemy/sql/__pycache__/type_api.cpython-312.pyc,, +sqlalchemy/sql/__pycache__/util.cpython-312.pyc,, +sqlalchemy/sql/__pycache__/visitors.cpython-312.pyc,, +sqlalchemy/sql/_dml_constructors.py,sha256=YdBJex0MCVACv4q2nl_ii3uhxzwU6aDB8zAsratX5UQ,3867 +sqlalchemy/sql/_elements_constructors.py,sha256=833Flez92odZkE2Vy6SXK8LcoO1AwkfVzOnATJLWFsA,63168 +sqlalchemy/sql/_orm_types.py,sha256=T-vjcry4C1y0GToFKVxQCnmly_-Zsq4IO4SHN6bvUF4,625 +sqlalchemy/sql/_py_util.py,sha256=hiM9ePbRSGs60bAMxPFuJCIC_p9SQ1VzqXGiPchiYwE,2173 +sqlalchemy/sql/_selectable_constructors.py,sha256=wjE6HrLm9cR7bxvZXT8sFLUqT6t_J9G1XyQCnYmBDl0,18780 +sqlalchemy/sql/_typing.py,sha256=oqwrYHVMtK-AuKGH9c4SgfiOEJUt5vjkzSEzzscMHkM,12771 +sqlalchemy/sql/annotation.py,sha256=aqbbVz9kfbCT3_66CZ9GEirVN197Cukoqt8rq48FgkQ,18245 +sqlalchemy/sql/base.py,sha256=M1b-Tg49ikUW2mnZv0aI38oASG6dgeo4jBNWDgJgAg8,73925 +sqlalchemy/sql/cache_key.py,sha256=0Db8mR8IrpBgdzXs4TGTt98LOpL3c7KABd72MAPKUQQ,33668 +sqlalchemy/sql/coercions.py,sha256=hAEou9Ycyswzu8yz_Q7QkwL2_c3nctzBJQS2oDEr4iE,40664 +sqlalchemy/sql/compiler.py,sha256=hrTptbOKIgVIHapywj4Lk5OMwpXvHS-KGg3odFwlo-I,274687 +sqlalchemy/sql/crud.py,sha256=HBX4QPtW_PYYJmIKfNr-wE8IdEr963N24WXzFBUZOo0,56514 +sqlalchemy/sql/ddl.py,sha256=lKqvOigbcYrDG0euxd5F4tu9HbBi1kmp3eFPc45HH-8,45636 +sqlalchemy/sql/default_comparator.py,sha256=utXWsZVGEjflhFfCT4ywa6RnhORc1Rryo87Hga71Rps,16707 +sqlalchemy/sql/dml.py,sha256=pn0Lm1ofC5qVZzwGWFW73lPCiNba8OsTeemurJgwRyg,65614 +sqlalchemy/sql/elements.py,sha256=YfccXzQc9DlgF8q15kDf-zKBUY_vpIe0FGaVDBPoic4,176544 +sqlalchemy/sql/events.py,sha256=iC_Q1Htm1Aobt5tOYxWfHHqNpoytrULORmUKcusH_-E,18290 +sqlalchemy/sql/expression.py,sha256=VMX-dLpsZYnVRJpYNDozDUgaj7iQ0HuewUKVefD57PE,7586 +sqlalchemy/sql/functions.py,sha256=kMMYplvuIHFAPwxBI03SizwaLcYEHzysecWk-R1V-JM,63762 +sqlalchemy/sql/lambdas.py,sha256=DP0Qz7Ypo8QhzMwygGHYgRhwJMx-rNezO1euouH3iYU,49292 +sqlalchemy/sql/naming.py,sha256=ZHs1qSV3ou8TYmZ92uvU3sfdklUQlIz4uhe330n05SU,6858 +sqlalchemy/sql/operators.py,sha256=himArRqBzrljob3Zfhi_ZS-Jleg1u6YFp0g3d7Co6IM,76106 +sqlalchemy/sql/roles.py,sha256=pOsVn_OZD7mF2gJByHf24Rjopt0_Hu3dUCEOK5t4KS8,7662 +sqlalchemy/sql/schema.py,sha256=iFleWHkxi-3mKGiK_N1TzUqxnNwOpypB4bWDuAVQe8c,229717 +sqlalchemy/sql/selectable.py,sha256=cgyV0AsPy4CXAFdhMiTCkbgaHiFilW9sclzxlHJKH3o,236460 +sqlalchemy/sql/sqltypes.py,sha256=5_N9MhprQFWYc3yjcXgFC_DmvkQU-Jz-Ok9nIMYp2Q4,127469 +sqlalchemy/sql/traversals.py,sha256=3ScTC1fh1-y8Y478h_2Azmd2xdQdWPWkDve4YgrwMf8,33664 +sqlalchemy/sql/type_api.py,sha256=SN16_oNZG6G65cvG6ABPcptz_YV5vfB2fknwJZxrkOs,84464 +sqlalchemy/sql/util.py,sha256=qGHQF-tPCj-m1FBerzT7weCanGcXU7dK5m-W7NHio-4,48077 +sqlalchemy/sql/visitors.py,sha256=71wdVvhhZL4nJvVwFAs6ssaW-qZgNRSmKjpAcOzF_TA,36317 +sqlalchemy/testing/__init__.py,sha256=zgitAYzsCWT_U48ZiifXHHLJFo8nZBYmI-5TueA4_lE,3160 +sqlalchemy/testing/__pycache__/__init__.cpython-312.pyc,, +sqlalchemy/testing/__pycache__/assertions.cpython-312.pyc,, +sqlalchemy/testing/__pycache__/assertsql.cpython-312.pyc,, +sqlalchemy/testing/__pycache__/asyncio.cpython-312.pyc,, +sqlalchemy/testing/__pycache__/config.cpython-312.pyc,, +sqlalchemy/testing/__pycache__/engines.cpython-312.pyc,, +sqlalchemy/testing/__pycache__/entities.cpython-312.pyc,, +sqlalchemy/testing/__pycache__/exclusions.cpython-312.pyc,, +sqlalchemy/testing/__pycache__/pickleable.cpython-312.pyc,, +sqlalchemy/testing/__pycache__/profiling.cpython-312.pyc,, +sqlalchemy/testing/__pycache__/provision.cpython-312.pyc,, +sqlalchemy/testing/__pycache__/requirements.cpython-312.pyc,, +sqlalchemy/testing/__pycache__/schema.cpython-312.pyc,, +sqlalchemy/testing/__pycache__/util.cpython-312.pyc,, +sqlalchemy/testing/__pycache__/warnings.cpython-312.pyc,, +sqlalchemy/testing/assertions.py,sha256=gL0rA7CCZJbcVgvWOPV91tTZTRwQc1_Ta0-ykBn83Ew,31439 +sqlalchemy/testing/assertsql.py,sha256=IgQG7l94WaiRP8nTbilJh1ZHZl125g7GPq-S5kmQZN0,16817 +sqlalchemy/testing/asyncio.py,sha256=kM8uuOqDBagZF0r9xvGmsiirUVLUQ_KBzjUFU67W-b8,3830 +sqlalchemy/testing/config.py,sha256=AqyH1qub_gDqX0BvlL-JBQe7N-t2wo8655FtwblUNOY,12090 +sqlalchemy/testing/engines.py,sha256=HFJceEBD3Q_TTFQMTtIV5wGWO_a7oUgoKtUF_z636SM,13481 +sqlalchemy/testing/entities.py,sha256=IphFegPKbff3Un47jY6bi7_MQXy6qkx_50jX2tHZJR4,3354 +sqlalchemy/testing/exclusions.py,sha256=T8B01hmm8WVs-EKcUOQRzabahPqblWJfOidi6bHJ6GA,12460 +sqlalchemy/testing/fixtures/__init__.py,sha256=dMClrIoxqlYIFpk2ia4RZpkbfxsS_3EBigr9QsPJ66g,1198 +sqlalchemy/testing/fixtures/__pycache__/__init__.cpython-312.pyc,, +sqlalchemy/testing/fixtures/__pycache__/base.cpython-312.pyc,, +sqlalchemy/testing/fixtures/__pycache__/mypy.cpython-312.pyc,, +sqlalchemy/testing/fixtures/__pycache__/orm.cpython-312.pyc,, +sqlalchemy/testing/fixtures/__pycache__/sql.cpython-312.pyc,, +sqlalchemy/testing/fixtures/base.py,sha256=9r_J2ksiTzClpUxW0TczICHrWR7Ny8PV8IsBz6TsGFI,12256 +sqlalchemy/testing/fixtures/mypy.py,sha256=gdxiwNFIzDlNGSOdvM3gbwDceVCC9t8oM5kKbwyhGBk,11973 +sqlalchemy/testing/fixtures/orm.py,sha256=8EFbnaBbXX_Bf4FcCzBUaAHgyVpsLGBHX16SGLqE3Fg,6095 +sqlalchemy/testing/fixtures/sql.py,sha256=KZMjco9_3dsuspmkew5Ejp88Wlr9PsSBB1qeJGFxQAk,15900 +sqlalchemy/testing/pickleable.py,sha256=U9mIqk-zaxq9Xfy7HErP7UrKgTov-A3QFnhZh-NiOjI,2833 +sqlalchemy/testing/plugin/__init__.py,sha256=79F--BIY_NTBzVRIlJGgAY5LNJJ3cD19XvrAo4X0W9A,247 +sqlalchemy/testing/plugin/__pycache__/__init__.cpython-312.pyc,, +sqlalchemy/testing/plugin/__pycache__/bootstrap.cpython-312.pyc,, +sqlalchemy/testing/plugin/__pycache__/plugin_base.cpython-312.pyc,, +sqlalchemy/testing/plugin/__pycache__/pytestplugin.cpython-312.pyc,, +sqlalchemy/testing/plugin/bootstrap.py,sha256=oYScMbEW4pCnWlPEAq1insFruCXFQeEVBwo__i4McpU,1685 +sqlalchemy/testing/plugin/plugin_base.py,sha256=BgNzWNEmgpK4CwhyblQQKnH-7FDKVi_Uul5vw8fFjBU,21578 +sqlalchemy/testing/plugin/pytestplugin.py,sha256=6jkQHH2VQMD75k2As9CuWXmEy9jrscoFRhCNg6-PaTw,27656 +sqlalchemy/testing/profiling.py,sha256=PbuPhRFbauFilUONeY3tV_Y_5lBkD7iCa8VVyH2Sk9Y,10148 +sqlalchemy/testing/provision.py,sha256=3qFor_sN1FFlS7odUGkKqLUxGmQZC9XM67I9vQ_zeXo,14626 +sqlalchemy/testing/requirements.py,sha256=Z__o-1Rj9B7dI8E_l3qsKTvsg0rK198vB0A1p7A5dcM,52832 +sqlalchemy/testing/schema.py,sha256=lr4GkGrGwagaHMuSGzWdzkMaj3HnS7dgfLLWfxt__-U,6513 +sqlalchemy/testing/suite/__init__.py,sha256=Y5DRNG0Yl1u3ypt9zVF0Z9suPZeuO_UQGLl-wRgvTjU,722 +sqlalchemy/testing/suite/__pycache__/__init__.cpython-312.pyc,, +sqlalchemy/testing/suite/__pycache__/test_cte.cpython-312.pyc,, +sqlalchemy/testing/suite/__pycache__/test_ddl.cpython-312.pyc,, +sqlalchemy/testing/suite/__pycache__/test_deprecations.cpython-312.pyc,, +sqlalchemy/testing/suite/__pycache__/test_dialect.cpython-312.pyc,, +sqlalchemy/testing/suite/__pycache__/test_insert.cpython-312.pyc,, +sqlalchemy/testing/suite/__pycache__/test_reflection.cpython-312.pyc,, +sqlalchemy/testing/suite/__pycache__/test_results.cpython-312.pyc,, +sqlalchemy/testing/suite/__pycache__/test_rowcount.cpython-312.pyc,, +sqlalchemy/testing/suite/__pycache__/test_select.cpython-312.pyc,, +sqlalchemy/testing/suite/__pycache__/test_sequence.cpython-312.pyc,, +sqlalchemy/testing/suite/__pycache__/test_types.cpython-312.pyc,, +sqlalchemy/testing/suite/__pycache__/test_unicode_ddl.cpython-312.pyc,, +sqlalchemy/testing/suite/__pycache__/test_update_delete.cpython-312.pyc,, +sqlalchemy/testing/suite/test_cte.py,sha256=6zBC3W2OwX1Xs-HedzchcKN2S7EaLNkgkvV_JSZ_Pq0,6451 +sqlalchemy/testing/suite/test_ddl.py,sha256=1Npkf0C_4UNxphthAGjG078n0vPEgnSIHpDu5MfokxQ,12031 +sqlalchemy/testing/suite/test_deprecations.py,sha256=BcJxZTcjYqeOAENVElCg3hVvU6fkGEW3KGBMfnW8bng,5337 +sqlalchemy/testing/suite/test_dialect.py,sha256=EH4ZQWbnGdtjmx5amZtTyhYmrkXJCvW1SQoLahoE7uk,22923 +sqlalchemy/testing/suite/test_insert.py,sha256=9azifj6-OCD7s8h_tAO1uPw100ibQv8YoKc_VA3hn3c,18824 +sqlalchemy/testing/suite/test_reflection.py,sha256=7sML8-owubSQeEM7Ve6LbnB8uIVlNV00WWepKwII2a8,109648 +sqlalchemy/testing/suite/test_results.py,sha256=X720GafdA4p75SOGS93j-dXkt6QDEnnJbU2bh18VCcg,16914 +sqlalchemy/testing/suite/test_rowcount.py,sha256=3KDTlRgjpQ1OVfp__1cv8Hvq4CsDKzmrhJQ_WIJWoJg,7900 +sqlalchemy/testing/suite/test_select.py,sha256=ulRZQJlzkwwcewEyisuBEXVWFR0Wshz9MEDxYYiYLwQ,61732 +sqlalchemy/testing/suite/test_sequence.py,sha256=66bCoy4xo99GBSaX6Hxb88foANAykLGRz1YEKbvpfuA,9923 +sqlalchemy/testing/suite/test_types.py,sha256=K4MGHvnTtgqeksoQOBCZRVQYC7HoYO6Z6rVt5vj2t9o,67805 +sqlalchemy/testing/suite/test_unicode_ddl.py,sha256=c3_eIxLyORuSOhNDP0jWKxPyUf3SwMFpdalxtquwqlM,6141 +sqlalchemy/testing/suite/test_update_delete.py,sha256=yTiM2unnfOK9rK8ZkqeTTU_MkT-RsKFLmdYliniZfAY,3994 +sqlalchemy/testing/util.py,sha256=qldXKw8gRJ4I2x3uXsBssYMqwatmcMFMTOveRQCmfDU,14469 +sqlalchemy/testing/warnings.py,sha256=fJ-QJUY2zY2PPxZJKv9medW-BKKbCNbA4Ns_V3YwFXM,1546 +sqlalchemy/types.py,sha256=cQFM-hFRmaf1GErun1qqgEs6QxufvzMuwKqj9tuMPpE,3168 +sqlalchemy/util/__init__.py,sha256=5D5Mquvx3SOmud0QErKzzGvBTkqMdhrrd_sXijOILeo,8312 +sqlalchemy/util/__pycache__/__init__.cpython-312.pyc,, +sqlalchemy/util/__pycache__/_collections.cpython-312.pyc,, +sqlalchemy/util/__pycache__/_concurrency_py3k.cpython-312.pyc,, +sqlalchemy/util/__pycache__/_has_cy.cpython-312.pyc,, +sqlalchemy/util/__pycache__/_py_collections.cpython-312.pyc,, +sqlalchemy/util/__pycache__/compat.cpython-312.pyc,, +sqlalchemy/util/__pycache__/concurrency.cpython-312.pyc,, +sqlalchemy/util/__pycache__/deprecations.cpython-312.pyc,, +sqlalchemy/util/__pycache__/langhelpers.cpython-312.pyc,, +sqlalchemy/util/__pycache__/preloaded.cpython-312.pyc,, +sqlalchemy/util/__pycache__/queue.cpython-312.pyc,, +sqlalchemy/util/__pycache__/tool_support.cpython-312.pyc,, +sqlalchemy/util/__pycache__/topological.cpython-312.pyc,, +sqlalchemy/util/__pycache__/typing.cpython-312.pyc,, +sqlalchemy/util/_collections.py,sha256=aZoSAVOXnHBoYEsxDOi0O9odg9wqLbGb7PGjaWQKiyY,20078 +sqlalchemy/util/_concurrency_py3k.py,sha256=zb0Bow2Y_QjTdaACEviBEEaFvqDuVvpJfmwCjaw8xNE,9170 +sqlalchemy/util/_has_cy.py,sha256=wCQmeSjT3jaH_oxfCEtGk-1g0gbSpt5MCK5UcWdMWqk,1247 +sqlalchemy/util/_py_collections.py,sha256=U6L5AoyLdgSv7cdqB4xxQbw1rpeJjyOZVXffgxgga8I,16714 +sqlalchemy/util/compat.py,sha256=cnucBQOKspo58vjRpQXUBrHGguHOSFvftpD-I8vfUy0,8760 +sqlalchemy/util/concurrency.py,sha256=9lT_cMoO1fZNdY8QTUZ22oeSf-L5I-79Ke7chcBNPA0,3304 +sqlalchemy/util/deprecations.py,sha256=YBwvvYhSB8LhasIZRKvg_-WNoVhPUcaYI1ZrnjDn868,11971 +sqlalchemy/util/langhelpers.py,sha256=uIK3szZuq9aMnO-vEpSlNekNWv4I-E391e56bkTnUm0,65090 +sqlalchemy/util/preloaded.py,sha256=az7NmLJLsqs0mtM9uBkIu10-841RYDq8wOyqJ7xXvqE,5904 +sqlalchemy/util/queue.py,sha256=CaeSEaYZ57YwtmLdNdOIjT5PK_LCuwMFiO0mpp39ybM,10185 +sqlalchemy/util/tool_support.py,sha256=9braZyidaiNrZVsWtGmkSmus50-byhuYrlAqvhjcmnA,6135 +sqlalchemy/util/topological.py,sha256=N3M3Le7KzGHCmqPGg0ZBqixTDGwmFLhOZvBtc4rHL_g,3458 +sqlalchemy/util/typing.py,sha256=lFcGo1dJbZIZ9drAnvef-PzP0cX4LMxMSwgk3lJBb0g,18182 diff --git a/psets/9/finance/env/lib/python3.12/site-packages/SQLAlchemy-2.0.36.dist-info/REQUESTED b/psets/9/finance/env/lib/python3.12/site-packages/SQLAlchemy-2.0.36.dist-info/REQUESTED new file mode 100644 index 0000000..e69de29 diff --git a/psets/9/finance/env/lib/python3.12/site-packages/SQLAlchemy-2.0.36.dist-info/WHEEL b/psets/9/finance/env/lib/python3.12/site-packages/SQLAlchemy-2.0.36.dist-info/WHEEL new file mode 100644 index 0000000..3e81182 --- /dev/null +++ b/psets/9/finance/env/lib/python3.12/site-packages/SQLAlchemy-2.0.36.dist-info/WHEEL @@ -0,0 +1,6 @@ +Wheel-Version: 1.0 +Generator: setuptools (75.1.0) +Root-Is-Purelib: false +Tag: cp312-cp312-manylinux_2_17_x86_64 +Tag: cp312-cp312-manylinux2014_x86_64 + diff --git a/psets/9/finance/env/lib/python3.12/site-packages/SQLAlchemy-2.0.36.dist-info/top_level.txt b/psets/9/finance/env/lib/python3.12/site-packages/SQLAlchemy-2.0.36.dist-info/top_level.txt new file mode 100644 index 0000000..39fb2be --- /dev/null +++ b/psets/9/finance/env/lib/python3.12/site-packages/SQLAlchemy-2.0.36.dist-info/top_level.txt @@ -0,0 +1 @@ +sqlalchemy diff --git a/psets/9/finance/env/lib/python3.12/site-packages/__pycache__/typing_extensions.cpython-312.pyc b/psets/9/finance/env/lib/python3.12/site-packages/__pycache__/typing_extensions.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..07874fb6f5618c39a6ea80fbf406c2e496f44ca9 GIT binary patch literal 139400 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�cpgweAyOe9Q|tp{}_p}CIt=GD0p_QiB1_PM)~ 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
#sN8%8q+hNuxg$;nD(n`n8cmEe+s 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 aUJ?Kg;V&@02TS+h^HY=#f~!=|JJMf|FNj+J literal 0 HcmV?d00001 diff --git a/psets/9/finance/env/lib/python3.12/site-packages/automat/__pycache__/_core.cpython-312.pyc b/psets/9/finance/env/lib/python3.12/site-packages/automat/__pycache__/_core.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..cbc4057cc22fc33da4dd205013533bb734418354 GIT binary patch literal 8963 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 literal 0 HcmV?d00001 diff --git a/psets/9/finance/env/lib/python3.12/site-packages/automat/__pycache__/_methodical.cpython-312.pyc b/psets/9/finance/env/lib/python3.12/site-packages/automat/__pycache__/_methodical.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..66cddec0c93add36a34abb2f292d045aaa23dfb5 GIT binary patch literal 22687 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 VT;lqBWxWnDFyZ;RKyOCT{x3<>-=Y8j literal 0 HcmV?d00001 diff --git a/psets/9/finance/env/lib/python3.12/site-packages/automat/__pycache__/_runtimeproto.cpython-312.pyc b/psets/9/finance/env/lib/python3.12/site-packages/automat/__pycache__/_runtimeproto.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..380d1aaa743336bcbde8958ecad9aa0980342ed3 GIT binary patch literal 2844 zcmbVO-EUmQ6`$FA_v@~|?q>64()40Gz$RfA8j^tJxQgtA#DO#-4h@@Hx7T~e>uc`E zYVNGb8e3YGJOl|*SE?FU;vsz_N|E4=2mSygUTm#tl93-kAVH-*gl?*qJoU_6@5Tnv zhmLmUp7}a6bI$K~&VJV2tsyA6H(#sFClLBdblN2o3AptS5N@DL$VMe(V>{+zFII|S zAuFy@QsAq)suwTCy+kSDB}+*!RZ7YExSRI0lICSf8H{3xr0m3P9O*4}kwgWNu9?_g z7$|kyeRlGiTIvC9DcIFp>h=0ceV`>xbXyyNH6$J$03BI7b4}>#g}TG;f;LBz72MYA zpxa7x0_nRQi==UMI}%WPRcWWK+ud;9E<0=Yz<0O3!|sLep1P9HExfAzI-svxG^qKu zF%wYZ(wl6S7_L=*-3Vrk$$FKX4ydP%%raIDhl|CE!)9yKg>v8(t93RT_(iW?trwjz ztdX$z!tvurMwbfO-^DHRm}e~C517TAzz@&oRo*@M+J#f**qKvf=gyvgk*CHi*R`fy z!c!M$z=Cq%@}xNPRg30hJRLd}-(odNc=}>T#FOPs%gUz;8SH>t{UF>xi)c;`Z*MN5 zTlhTOCuN$xUgP0!i=NMl;}#=+u^iZrUn!Quqt6tpAz|>O;*8^4ewh@B zKVNj6>CJZ^DLng&V(2jPbQO$cRp9kjjRl^?iYBf3%<)K7ys1#F^RCSSc{uHZQ+GfO zyP#>HyP2-v55GOUs_tw-AHln|3Sl1crU?zX=7cjfzbq{HuxEw_3&e+OT?rYT;yL0~ zS-ow!mkGGT4!0Rc0Ax@Y=LrzbAuJ6vl}6|{0GK7b6kEi9!Z$ER?_^X|M;|C}U@C5P z3*Az9tndt1g}Jy&tnzFqlo^IWd*RE|BNgJ4t5rHm_d)+LsG$(PMgM7_`$##E__F`< z+Y{HvmxmrGDBXRp|MK@O6&C!iSI0bg>Z;{cU9#=6Ntl(Mya2)t#5!KK@ioN6>9Q;$ zCiKYi)3|5A@~A8T^Dlx~7uGeny>XH;VK##W20$vH#Bjt-JmN<{?+c4iL}TW2BCa_dv7F$VKm4CWvjq&s+~ zSs0;$6m+MU1E#hO8<8{u-Twc56*>reABP$WxHr&)EJ|nB^ohUre|YATx%K?nrasY3 zO>AiUzf*Af=l2yQo}fA`EqA~LofK5)<5mNNtuS1~i?KG~mXs}kRDKLdI=}>+WfA)r zaBj1wK!}pbs67&W+nU=!9RnZhNU|}X;7I_Y#TXUw!0|&S0uoms3h*R^139CTdCTP) z)2z6`G=K?$oXQgsXnD+GT!CQBwJi}@&`4k?GH#DK<6J%2iPy9Uv!aH_plP5Dea}jE zF_gxUS8Ml+Mmhd8;+stRMs8iBFkCMA%v{4Ha7l?qUC zt!hySr%c54gwRJqY2~~^4~h8%C1K5FJTBL5qayDyU1y$jvLHPU8;(K^PeB7v*HF*y z<@sj!{>JIM`tCdWz?wdAN6)Y6`M>FhuE#f0yO!ryYB#;lQ_q2GvWLG`v&+X;j;#(J zUss>Mo6#FDOJ~7VdqCkruFdk3?3E~)U74H`7ZgvUPr?#dIRGD?2&U&qnbGH=Lvvyx zC13M!XFIuHDHIBajcC~vJuKF}AeyH|BUH(~TsQzYGR6v>vpiqG{DmciKK$xnyqHu!LM+N`5{-Za_)chzG z@m_O_7lBYz1Q)KtS%k+~4bp}TS2FHMPfE8$(Nx5hh*+r+FR*Ja8KuHkf(_wY(A-xr z#{Y~dSpAoV@ZeWS`v#q8q7&bsr@mA(*T>#^se!-9?OS=}roM9N55HPPdMknPu79Tx zKJ>+|p(Yx-m(1OJZ0Nfv*$(|>^8Nfrmp(r8@o@9#=}%+L1Lr<1t@mGU#UU5Bkg_ka Xs_toZWpJXkPr<)@(3Qqn>GJ;q5&_05 literal 0 HcmV?d00001 diff --git a/psets/9/finance/env/lib/python3.12/site-packages/automat/__pycache__/_typed.cpython-312.pyc b/psets/9/finance/env/lib/python3.12/site-packages/automat/__pycache__/_typed.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..bdc7845b52ae757f51672f44955ccb748b995344 GIT binary patch literal 29471 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 literal 0 HcmV?d00001 diff --git a/psets/9/finance/env/lib/python3.12/site-packages/automat/__pycache__/_visualize.cpython-312.pyc b/psets/9/finance/env/lib/python3.12/site-packages/automat/__pycache__/_visualize.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..3e425a5f0825f370fde5e87e5af75ca69405bd86 GIT binary patch literal 8919 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 literal 0 HcmV?d00001 diff --git a/psets/9/finance/env/lib/python3.12/site-packages/automat/_core.py b/psets/9/finance/env/lib/python3.12/site-packages/automat/_core.py new file mode 100644 index 0000000..fc637b3 --- /dev/null +++ b/psets/9/finance/env/lib/python3.12/site-packages/automat/_core.py @@ -0,0 +1,203 @@ +# -*- test-case-name: automat._test.test_core -*- + +""" +A core state-machine abstraction. + +Perhaps something that could be replaced with or integrated into machinist. +""" +from __future__ import annotations + +import sys +from itertools import chain +from typing import Callable, Generic, Optional, Sequence, TypeVar, Hashable + +if sys.version_info >= (3, 10): + from typing import TypeAlias +else: + from typing_extensions import TypeAlias + +_NO_STATE = "" +State = TypeVar("State", bound=Hashable) +Input = TypeVar("Input", bound=Hashable) +Output = TypeVar("Output", bound=Hashable) + + +class NoTransition(Exception, Generic[State, Input]): + """ + A finite state machine in C{state} has no transition for C{symbol}. + + @ivar state: See C{state} init parameter. + + @ivar symbol: See C{symbol} init parameter. + """ + + def __init__(self, state: State, symbol: Input): + """ + Construct a L{NoTransition}. + + @param state: the finite state machine's state at the time of the + illegal transition. + + @param symbol: the input symbol for which no transition exists. + """ + self.state = state + self.symbol = symbol + super(Exception, self).__init__( + "no transition for {} in {}".format(symbol, state) + ) + + +class Automaton(Generic[State, Input, Output]): + """ + A declaration of a finite state machine. + + Note that this is not the machine itself; it is immutable. + """ + + def __init__(self, initial: State | None = None) -> None: + """ + Initialize the set of transitions and the initial state. + """ + if initial is None: + initial = _NO_STATE # type:ignore[assignment] + assert initial is not None + self._initialState: State = initial + self._transitions: set[tuple[State, Input, State, Sequence[Output]]] = set() + self._unhandledTransition: Optional[tuple[State, Sequence[Output]]] = None + + @property + def initialState(self) -> State: + """ + Return this automaton's initial state. + """ + return self._initialState + + @initialState.setter + def initialState(self, state: State) -> None: + """ + Set this automaton's initial state. Raises a ValueError if + this automaton already has an initial state. + """ + + if self._initialState is not _NO_STATE: + raise ValueError( + "initial state already set to {}".format(self._initialState) + ) + + self._initialState = state + + def addTransition( + self, + inState: State, + inputSymbol: Input, + outState: State, + outputSymbols: tuple[Output, ...], + ): + """ + Add the given transition to the outputSymbol. Raise ValueError if + there is already a transition with the same inState and inputSymbol. + """ + # keeping self._transitions in a flat list makes addTransition + # O(n^2), but state machines don't tend to have hundreds of + # transitions. + for anInState, anInputSymbol, anOutState, _ in self._transitions: + if anInState == inState and anInputSymbol == inputSymbol: + raise ValueError( + "already have transition from {} to {} via {}".format( + inState, anOutState, inputSymbol + ) + ) + self._transitions.add((inState, inputSymbol, outState, tuple(outputSymbols))) + + def unhandledTransition( + self, outState: State, outputSymbols: Sequence[Output] + ) -> None: + """ + All unhandled transitions will be handled by transitioning to the given + error state and error-handling output symbols. + """ + self._unhandledTransition = (outState, tuple(outputSymbols)) + + def allTransitions(self) -> frozenset[tuple[State, Input, State, Sequence[Output]]]: + """ + All transitions. + """ + return frozenset(self._transitions) + + def inputAlphabet(self) -> set[Input]: + """ + The full set of symbols acceptable to this automaton. + """ + return { + inputSymbol + for (inState, inputSymbol, outState, outputSymbol) in self._transitions + } + + def outputAlphabet(self) -> set[Output]: + """ + The full set of symbols which can be produced by this automaton. + """ + return set( + chain.from_iterable( + outputSymbols + for (inState, inputSymbol, outState, outputSymbols) in self._transitions + ) + ) + + def states(self) -> frozenset[State]: + """ + All valid states; "Q" in the mathematical description of a state + machine. + """ + return frozenset( + chain.from_iterable( + (inState, outState) + for (inState, inputSymbol, outState, outputSymbol) in self._transitions + ) + ) + + def outputForInput( + self, inState: State, inputSymbol: Input + ) -> tuple[State, Sequence[Output]]: + """ + A 2-tuple of (outState, outputSymbols) for inputSymbol. + """ + for anInState, anInputSymbol, outState, outputSymbols in self._transitions: + if (inState, inputSymbol) == (anInState, anInputSymbol): + return (outState, list(outputSymbols)) + if self._unhandledTransition is None: + raise NoTransition(state=inState, symbol=inputSymbol) + return self._unhandledTransition + + +OutputTracer = Callable[[Output], None] +Tracer: TypeAlias = "Callable[[State, Input, State], OutputTracer[Output] | None]" + + +class Transitioner(Generic[State, Input, Output]): + """ + The combination of a current state and an L{Automaton}. + """ + + def __init__(self, automaton: Automaton[State, Input, Output], initialState: State): + self._automaton: Automaton[State, Input, Output] = automaton + self._state: State = initialState + self._tracer: Tracer[State, Input, Output] | None = None + + def setTrace(self, tracer: Tracer[State, Input, Output] | None) -> None: + self._tracer = tracer + + def transition( + self, inputSymbol: Input + ) -> tuple[Sequence[Output], OutputTracer[Output] | None]: + """ + Transition between states, returning any outputs. + """ + outState, outputSymbols = self._automaton.outputForInput( + self._state, inputSymbol + ) + outTracer = None + if self._tracer: + outTracer = self._tracer(self._state, inputSymbol, outState) + self._state = outState + return (outputSymbols, outTracer) diff --git a/psets/9/finance/env/lib/python3.12/site-packages/automat/_discover.py b/psets/9/finance/env/lib/python3.12/site-packages/automat/_discover.py new file mode 100644 index 0000000..ae92f82 --- /dev/null +++ b/psets/9/finance/env/lib/python3.12/site-packages/automat/_discover.py @@ -0,0 +1,168 @@ +from __future__ import annotations + +import collections +import inspect +from typing import Any, Iterator + +from twisted.python.modules import PythonAttribute, PythonModule, getModule + +from automat import MethodicalMachine + +from ._typed import TypeMachine, InputProtocol, Core + + +def isOriginalLocation(attr: PythonAttribute | PythonModule) -> bool: + """ + Attempt to discover if this appearance of a PythonAttribute + representing a class refers to the module where that class was + defined. + """ + sourceModule = inspect.getmodule(attr.load()) + if sourceModule is None: + return False + + currentModule = attr + while not isinstance(currentModule, PythonModule): + currentModule = currentModule.onObject + + return currentModule.name == sourceModule.__name__ + + +def findMachinesViaWrapper( + within: PythonModule | PythonAttribute, +) -> Iterator[tuple[str, MethodicalMachine | TypeMachine[InputProtocol, Core]]]: + """ + Recursively yield L{MethodicalMachine}s and their FQPNs within a + L{PythonModule} or a L{twisted.python.modules.PythonAttribute} + wrapper object. + + Note that L{PythonModule}s may refer to packages, as well. + + The discovery heuristic considers L{MethodicalMachine} instances + that are module-level attributes or class-level attributes + accessible from module scope. Machines inside nested classes will + be discovered, but those returned from functions or methods will not be. + + @type within: L{PythonModule} or L{twisted.python.modules.PythonAttribute} + @param within: Where to start the search. + + @return: a generator which yields FQPN, L{MethodicalMachine} pairs. + """ + queue = collections.deque([within]) + visited: set[ + PythonModule + | PythonAttribute + | MethodicalMachine + | TypeMachine[InputProtocol, Core] + | type[Any] + ] = set() + + while queue: + attr = queue.pop() + value = attr.load() + if ( + isinstance(value, MethodicalMachine) or isinstance(value, TypeMachine) + ) and value not in visited: + visited.add(value) + yield attr.name, value + elif ( + inspect.isclass(value) and isOriginalLocation(attr) and value not in visited + ): + visited.add(value) + queue.extendleft(attr.iterAttributes()) + elif isinstance(attr, PythonModule) and value not in visited: + visited.add(value) + queue.extendleft(attr.iterAttributes()) + queue.extendleft(attr.iterModules()) + + +class InvalidFQPN(Exception): + """ + The given FQPN was not a dot-separated list of Python objects. + """ + + +class NoModule(InvalidFQPN): + """ + A prefix of the FQPN was not an importable module or package. + """ + + +class NoObject(InvalidFQPN): + """ + A suffix of the FQPN was not an accessible object + """ + + +def wrapFQPN(fqpn: str) -> PythonModule | PythonAttribute: + """ + Given an FQPN, retrieve the object via the global Python module + namespace and wrap it with a L{PythonModule} or a + L{twisted.python.modules.PythonAttribute}. + """ + # largely cribbed from t.p.reflect.namedAny + + if not fqpn: + raise InvalidFQPN("FQPN was empty") + + components = collections.deque(fqpn.split(".")) + + if "" in components: + raise InvalidFQPN( + "name must be a string giving a '.'-separated list of Python " + "identifiers, not %r" % (fqpn,) + ) + + component = components.popleft() + try: + module = getModule(component) + except KeyError: + raise NoModule(component) + + # find the bottom-most module + while components: + component = components.popleft() + try: + module = module[component] + except KeyError: + components.appendleft(component) + break + else: + module.load() + else: + return module + + # find the bottom-most attribute + attribute = module + for component in components: + try: + attribute = next( + child + for child in attribute.iterAttributes() + if child.name.rsplit(".", 1)[-1] == component + ) + except StopIteration: + raise NoObject("{}.{}".format(attribute.name, component)) + + return attribute + + +def findMachines( + fqpn: str, +) -> Iterator[tuple[str, MethodicalMachine | TypeMachine[InputProtocol, Core]]]: + """ + Recursively yield L{MethodicalMachine}s and their FQPNs in and under the a + Python object specified by an FQPN. + + The discovery heuristic considers L{MethodicalMachine} instances that are + module-level attributes or class-level attributes accessible from module + scope. Machines inside nested classes will be discovered, but those + returned from functions or methods will not be. + + @param fqpn: a fully-qualified Python identifier (i.e. the dotted + identifier of an object defined at module or class scope, including the + package and modele names); where to start the search. + + @return: a generator which yields (C{FQPN}, L{MethodicalMachine}) pairs. + """ + return findMachinesViaWrapper(wrapFQPN(fqpn)) diff --git a/psets/9/finance/env/lib/python3.12/site-packages/automat/_introspection.py b/psets/9/finance/env/lib/python3.12/site-packages/automat/_introspection.py new file mode 100644 index 0000000..e433b2f --- /dev/null +++ b/psets/9/finance/env/lib/python3.12/site-packages/automat/_introspection.py @@ -0,0 +1,57 @@ +""" +Python introspection helpers. +""" + +from types import CodeType as code, FunctionType as function + + +def copycode(template, changes): + if hasattr(code, "replace"): + return template.replace(**{"co_" + k: v for k, v in changes.items()}) + names = [ + "argcount", + "nlocals", + "stacksize", + "flags", + "code", + "consts", + "names", + "varnames", + "filename", + "name", + "firstlineno", + "lnotab", + "freevars", + "cellvars", + ] + if hasattr(code, "co_kwonlyargcount"): + names.insert(1, "kwonlyargcount") + if hasattr(code, "co_posonlyargcount"): + # PEP 570 added "positional only arguments" + names.insert(1, "posonlyargcount") + values = [changes.get(name, getattr(template, "co_" + name)) for name in names] + return code(*values) + + +def copyfunction(template, funcchanges, codechanges): + names = [ + "globals", + "name", + "defaults", + "closure", + ] + values = [ + funcchanges.get(name, getattr(template, "__" + name + "__")) for name in names + ] + return function(copycode(template.__code__, codechanges), *values) + + +def preserveName(f): + """ + Preserve the name of the given function on the decorated function. + """ + + def decorator(decorated): + return copyfunction(decorated, dict(name=f.__name__), dict(name=f.__name__)) + + return decorator diff --git a/psets/9/finance/env/lib/python3.12/site-packages/automat/_methodical.py b/psets/9/finance/env/lib/python3.12/site-packages/automat/_methodical.py new file mode 100644 index 0000000..6c46c11 --- /dev/null +++ b/psets/9/finance/env/lib/python3.12/site-packages/automat/_methodical.py @@ -0,0 +1,545 @@ +# -*- test-case-name: automat._test.test_methodical -*- +from __future__ import annotations + +import collections +import sys +from dataclasses import dataclass, field +from functools import wraps +from inspect import getfullargspec as getArgsSpec +from itertools import count +from typing import Any, Callable, Hashable, Iterable, TypeVar + +if sys.version_info < (3, 10): + from typing_extensions import TypeAlias +else: + from typing import TypeAlias + +from ._core import Automaton, OutputTracer, Tracer, Transitioner +from ._introspection import preserveName + +ArgSpec = collections.namedtuple( + "ArgSpec", + [ + "args", + "varargs", + "varkw", + "defaults", + "kwonlyargs", + "kwonlydefaults", + "annotations", + ], +) + + +def _getArgSpec(func): + """ + Normalize inspect.ArgSpec across python versions + and convert mutable attributes to immutable types. + + :param Callable func: A function. + :return: The function's ArgSpec. + :rtype: ArgSpec + """ + spec = getArgsSpec(func) + return ArgSpec( + args=tuple(spec.args), + varargs=spec.varargs, + varkw=spec.varkw, + defaults=spec.defaults if spec.defaults else (), + kwonlyargs=tuple(spec.kwonlyargs), + kwonlydefaults=( + tuple(spec.kwonlydefaults.items()) if spec.kwonlydefaults else () + ), + annotations=tuple(spec.annotations.items()), + ) + + +def _getArgNames(spec): + """ + Get the name of all arguments defined in a function signature. + + The name of * and ** arguments is normalized to "*args" and "**kwargs". + + :param ArgSpec spec: A function to interrogate for a signature. + :return: The set of all argument names in `func`s signature. + :rtype: Set[str] + """ + return set( + spec.args + + spec.kwonlyargs + + (("*args",) if spec.varargs else ()) + + (("**kwargs",) if spec.varkw else ()) + + spec.annotations + ) + + +def _keywords_only(f): + """ + Decorate a function so all its arguments must be passed by keyword. + + A useful utility for decorators that take arguments so that they don't + accidentally get passed the thing they're decorating as their first + argument. + + Only works for methods right now. + """ + + @wraps(f) + def g(self, **kw): + return f(self, **kw) + + return g + + +@dataclass(frozen=True) +class MethodicalState(object): + """ + A state for a L{MethodicalMachine}. + """ + + machine: MethodicalMachine = field(repr=False) + method: Callable[..., Any] = field() + serialized: bool = field(repr=False) + + def upon( + self, + input: MethodicalInput, + enter: MethodicalState | None = None, + outputs: Iterable[MethodicalOutput] | None = None, + collector: Callable[[Iterable[T]], object] = list, + ) -> None: + """ + Declare a state transition within the L{MethodicalMachine} associated + with this L{MethodicalState}: upon the receipt of the `input`, enter + the `state`, emitting each output in `outputs`. + + @param input: The input triggering a state transition. + + @param enter: The resulting state. + + @param outputs: The outputs to be triggered as a result of the declared + state transition. + + @param collector: The function to be used when collecting output return + values. + + @raises TypeError: if any of the `outputs` signatures do not match the + `inputs` signature. + + @raises ValueError: if the state transition from `self` via `input` has + already been defined. + """ + if enter is None: + enter = self + if outputs is None: + outputs = [] + inputArgs = _getArgNames(input.argSpec) + for output in outputs: + outputArgs = _getArgNames(output.argSpec) + if not outputArgs.issubset(inputArgs): + raise TypeError( + "method {input} signature {inputSignature} " + "does not match output {output} " + "signature {outputSignature}".format( + input=input.method.__name__, + output=output.method.__name__, + inputSignature=getArgsSpec(input.method), + outputSignature=getArgsSpec(output.method), + ) + ) + self.machine._oneTransition(self, input, enter, outputs, collector) + + def _name(self) -> str: + return self.method.__name__ + + +def _transitionerFromInstance( + oself: object, + symbol: str, + automaton: Automaton[MethodicalState, MethodicalInput, MethodicalOutput], +) -> Transitioner[MethodicalState, MethodicalInput, MethodicalOutput]: + """ + Get a L{Transitioner} + """ + transitioner = getattr(oself, symbol, None) + if transitioner is None: + transitioner = Transitioner( + automaton, + automaton.initialState, + ) + setattr(oself, symbol, transitioner) + return transitioner + + +def _empty(): + pass + + +def _docstring(): + """docstring""" + + +def assertNoCode(f: Callable[..., Any]) -> None: + # The function body must be empty, i.e. "pass" or "return None", which + # both yield the same bytecode: LOAD_CONST (None), RETURN_VALUE. We also + # accept functions with only a docstring, which yields slightly different + # bytecode, because the "None" is put in a different constant slot. + + # Unfortunately, this does not catch function bodies that return a + # constant value, e.g. "return 1", because their code is identical to a + # "return None". They differ in the contents of their constant table, but + # checking that would require us to parse the bytecode, find the index + # being returned, then making sure the table has a None at that index. + + if f.__code__.co_code not in (_empty.__code__.co_code, _docstring.__code__.co_code): + raise ValueError("function body must be empty") + + +def _filterArgs(args, kwargs, inputSpec, outputSpec): + """ + Filter out arguments that were passed to input that output won't accept. + + :param tuple args: The *args that input received. + :param dict kwargs: The **kwargs that input received. + :param ArgSpec inputSpec: The input's arg spec. + :param ArgSpec outputSpec: The output's arg spec. + :return: The args and kwargs that output will accept. + :rtype: Tuple[tuple, dict] + """ + named_args = tuple(zip(inputSpec.args[1:], args)) + if outputSpec.varargs: + # Only return all args if the output accepts *args. + return_args = args + else: + # Filter out arguments that don't appear + # in the output's method signature. + return_args = [v for n, v in named_args if n in outputSpec.args] + + # Get any of input's default arguments that were not passed. + passed_arg_names = tuple(kwargs) + for name, value in named_args: + passed_arg_names += (name, value) + defaults = zip(inputSpec.args[::-1], inputSpec.defaults[::-1]) + full_kwargs = {n: v for n, v in defaults if n not in passed_arg_names} + full_kwargs.update(kwargs) + + if outputSpec.varkw: + # Only pass all kwargs if the output method accepts **kwargs. + return_kwargs = full_kwargs + else: + # Filter out names that the output method does not accept. + all_accepted_names = outputSpec.args[1:] + outputSpec.kwonlyargs + return_kwargs = { + n: v for n, v in full_kwargs.items() if n in all_accepted_names + } + + return return_args, return_kwargs + + +T = TypeVar("T") +R = TypeVar("R") + + +@dataclass(eq=False) +class MethodicalInput(object): + """ + An input for a L{MethodicalMachine}. + """ + + automaton: Automaton[MethodicalState, MethodicalInput, MethodicalOutput] = field( + repr=False + ) + method: Callable[..., Any] = field() + symbol: str = field(repr=False) + collectors: dict[MethodicalState, Callable[[Iterable[T]], R]] = field( + default_factory=dict, repr=False + ) + + argSpec: ArgSpec = field(init=False, repr=False) + + def __post_init__(self) -> None: + self.argSpec = _getArgSpec(self.method) + assertNoCode(self.method) + + def __get__(self, oself: object, type: None = None) -> object: + """ + Return a function that takes no arguments and returns values returned + by output functions produced by the given L{MethodicalInput} in + C{oself}'s current state. + """ + transitioner = _transitionerFromInstance(oself, self.symbol, self.automaton) + + @preserveName(self.method) + @wraps(self.method) + def doInput(*args: object, **kwargs: object) -> object: + self.method(oself, *args, **kwargs) + previousState = transitioner._state + (outputs, outTracer) = transitioner.transition(self) + collector = self.collectors[previousState] + values = [] + for output in outputs: + if outTracer is not None: + outTracer(output) + a, k = _filterArgs(args, kwargs, self.argSpec, output.argSpec) + value = output(oself, *a, **k) + values.append(value) + return collector(values) + + return doInput + + def _name(self) -> str: + return self.method.__name__ + + +@dataclass(frozen=True) +class MethodicalOutput(object): + """ + An output for a L{MethodicalMachine}. + """ + + machine: MethodicalMachine = field(repr=False) + method: Callable[..., Any] + argSpec: ArgSpec = field(init=False, repr=False, compare=False) + + def __post_init__(self) -> None: + self.__dict__["argSpec"] = _getArgSpec(self.method) + + def __get__(self, oself, type=None): + """ + Outputs are private, so raise an exception when we attempt to get one. + """ + raise AttributeError( + "{cls}.{method} is a state-machine output method; " + "to produce this output, call an input method instead.".format( + cls=type.__name__, method=self.method.__name__ + ) + ) + + def __call__(self, oself, *args, **kwargs): + """ + Call the underlying method. + """ + return self.method(oself, *args, **kwargs) + + def _name(self) -> str: + return self.method.__name__ + + +StringOutputTracer = Callable[[str], None] +StringTracer: TypeAlias = "Callable[[str, str, str], StringOutputTracer | None]" + + +def wrapTracer( + wrapped: StringTracer | None, +) -> Tracer[MethodicalState, MethodicalInput, MethodicalOutput] | None: + if wrapped is None: + return None + + def tracer( + state: MethodicalState, + input: MethodicalInput, + output: MethodicalState, + ) -> OutputTracer[MethodicalOutput] | None: + result = wrapped(state._name(), input._name(), output._name()) + if result is not None: + return lambda out: result(out._name()) + return None + + return tracer + + +@dataclass(eq=False) +class MethodicalTracer(object): + automaton: Automaton[MethodicalState, MethodicalInput, MethodicalOutput] = field( + repr=False + ) + symbol: str = field(repr=False) + + def __get__( + self, oself: object, type: object = None + ) -> Callable[[StringTracer], None]: + transitioner = _transitionerFromInstance(oself, self.symbol, self.automaton) + + def setTrace(tracer: StringTracer | None) -> None: + transitioner.setTrace(wrapTracer(tracer)) + + return setTrace + + +counter = count() + + +def gensym(): + """ + Create a unique Python identifier. + """ + return "_symbol_" + str(next(counter)) + + +class MethodicalMachine(object): + """ + A L{MethodicalMachine} is an interface to an L{Automaton} that uses methods + on a class. + """ + + def __init__(self): + self._automaton = Automaton() + self._reducers = {} + self._symbol = gensym() + + def __get__(self, oself, type=None): + """ + L{MethodicalMachine} is an implementation detail for setting up + class-level state; applications should never need to access it on an + instance. + """ + if oself is not None: + raise AttributeError("MethodicalMachine is an implementation detail.") + return self + + @_keywords_only + def state( + self, initial: bool = False, terminal: bool = False, serialized: Hashable = None + ): + """ + Declare a state, possibly an initial state or a terminal state. + + This is a decorator for methods, but it will modify the method so as + not to be callable any more. + + @param initial: is this state the initial state? Only one state on + this L{automat.MethodicalMachine} may be an initial state; more + than one is an error. + + @param terminal: Is this state a terminal state? i.e. a state that the + machine can end up in? (This is purely informational at this + point.) + + @param serialized: a serializable value to be used to represent this + state to external systems. This value should be hashable; L{str} + is a good type to use. + """ + + def decorator(stateMethod): + state = MethodicalState( + machine=self, method=stateMethod, serialized=serialized + ) + if initial: + self._automaton.initialState = state + return state + + return decorator + + @_keywords_only + def input(self): + """ + Declare an input. + + This is a decorator for methods. + """ + + def decorator(inputMethod): + return MethodicalInput( + automaton=self._automaton, method=inputMethod, symbol=self._symbol + ) + + return decorator + + @_keywords_only + def output(self): + """ + Declare an output. + + This is a decorator for methods. + + This method will be called when the state machine transitions to this + state as specified in the decorated `output` method. + """ + + def decorator(outputMethod): + return MethodicalOutput(machine=self, method=outputMethod) + + return decorator + + def _oneTransition(self, startState, inputToken, endState, outputTokens, collector): + """ + See L{MethodicalState.upon}. + """ + # FIXME: tests for all of this (some of it is wrong) + # if not isinstance(startState, MethodicalState): + # raise NotImplementedError("start state {} isn't a state" + # .format(startState)) + # if not isinstance(inputToken, MethodicalInput): + # raise NotImplementedError("start state {} isn't an input" + # .format(inputToken)) + # if not isinstance(endState, MethodicalState): + # raise NotImplementedError("end state {} isn't a state" + # .format(startState)) + # for output in outputTokens: + # if not isinstance(endState, MethodicalState): + # raise NotImplementedError("output state {} isn't a state" + # .format(endState)) + self._automaton.addTransition( + startState, inputToken, endState, tuple(outputTokens) + ) + inputToken.collectors[startState] = collector + + @_keywords_only + def serializer(self): + """ """ + + def decorator(decoratee): + @wraps(decoratee) + def serialize(oself): + transitioner = _transitionerFromInstance( + oself, self._symbol, self._automaton + ) + return decoratee(oself, transitioner._state.serialized) + + return serialize + + return decorator + + @_keywords_only + def unserializer(self): + """ """ + + def decorator(decoratee): + @wraps(decoratee) + def unserialize(oself, *args, **kwargs): + state = decoratee(oself, *args, **kwargs) + mapping = {} + for eachState in self._automaton.states(): + mapping[eachState.serialized] = eachState + transitioner = _transitionerFromInstance( + oself, self._symbol, self._automaton + ) + transitioner._state = mapping[state] + return None # it's on purpose + + return unserialize + + return decorator + + @property + def _setTrace(self) -> MethodicalTracer: + return MethodicalTracer(self._automaton, self._symbol) + + def asDigraph(self): + """ + Generate a L{graphviz.Digraph} that represents this machine's + states and transitions. + + @return: L{graphviz.Digraph} object; for more information, please + see the documentation for + U{graphviz} + + """ + from ._visualize import makeDigraph + + return makeDigraph( + self._automaton, + stateAsString=lambda state: state.method.__name__, + inputAsString=lambda input: input.method.__name__, + outputAsString=lambda output: output.method.__name__, + ) diff --git a/psets/9/finance/env/lib/python3.12/site-packages/automat/_runtimeproto.py b/psets/9/finance/env/lib/python3.12/site-packages/automat/_runtimeproto.py new file mode 100644 index 0000000..c9c7409 --- /dev/null +++ b/psets/9/finance/env/lib/python3.12/site-packages/automat/_runtimeproto.py @@ -0,0 +1,62 @@ +""" +Workaround for U{the lack of TypeForm +}. +""" + +from __future__ import annotations + +import sys + +from typing import TYPE_CHECKING, Callable, Protocol, TypeVar + +from inspect import signature, Signature + +T = TypeVar("T") + +ProtocolAtRuntime = Callable[[], T] + + +def runtime_name(x: ProtocolAtRuntime[T]) -> str: + return x.__name__ + + +from inspect import getmembers, isfunction + +emptyProtocolMethods: frozenset[str] +if not TYPE_CHECKING: + emptyProtocolMethods = frozenset( + name + for name, each in getmembers(type("Example", tuple([Protocol]), {}), isfunction) + ) + + +def actuallyDefinedProtocolMethods(protocol: object) -> frozenset[str]: + """ + Attempt to ignore implementation details, and get all the methods that the + protocol actually defines. + + that includes locally defined methods and also those defined in inherited + superclasses. + """ + return ( + frozenset(name for name, each in getmembers(protocol, isfunction)) + - emptyProtocolMethods + ) + + +def _fixAnnotation(method: Callable[..., object], it: object, ann: str) -> None: + annotation = getattr(it, ann) + if isinstance(annotation, str): + setattr(it, ann, eval(annotation, method.__globals__)) + + +def _liveSignature(method: Callable[..., object]) -> Signature: + """ + Get a signature with evaluated annotations. + """ + # TODO: could this be replaced with get_type_hints? + result = signature(method) + for param in result.parameters.values(): + _fixAnnotation(method, param, "_annotation") + _fixAnnotation(method, result, "_return_annotation") + return result diff --git a/psets/9/finance/env/lib/python3.12/site-packages/automat/_test/__init__.py b/psets/9/finance/env/lib/python3.12/site-packages/automat/_test/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/psets/9/finance/env/lib/python3.12/site-packages/automat/_test/__pycache__/__init__.cpython-312.pyc b/psets/9/finance/env/lib/python3.12/site-packages/automat/_test/__pycache__/__init__.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..983b952bb0202e22d286e665248927f79e1a06a5 GIT binary patch literal 194 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 literal 0 HcmV?d00001 diff --git a/psets/9/finance/env/lib/python3.12/site-packages/automat/_test/__pycache__/test_trace.cpython-312.pyc b/psets/9/finance/env/lib/python3.12/site-packages/automat/_test/__pycache__/test_trace.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..3c1a2ecc69a8b0249e245f48a104bf688b6c496c GIT binary patch literal 4612 zcmd5=&2Jk;6rb5IuN^zMX++Xb+!he#BW_b#K(rMqw3MP6iT2PKr0vE#F%I_H>~26d zMoL7a*rigVMMpD!uDM27iyxzd2BqmJ{v=8#y2K`pJP8)4;o;2}Ff4tw1%ktZ) zz!q4!4XXlnd#@k9Edw^jZ>K_AU;}N~fi19V8#WBsU7Pq2Y{L!$c5g2>6=llwfnGfe zu>c#)G!K>%7U+u`U}_gm?TZVuK!*5Xa$jpF)%*fV|;w{(HNH|Ax6sEI`#-vyC1?lMsj15 z3Ny|oy9B*m3js~6W2R($$W=AX)bmW!+>oZ_3&u&O#N5Q^?=^kf=KB^Mx>~7KX3yM~f(vKo&Q|UE>80~ar&gr>t5Rs; z?YXz>V*UKm;iacmq}ZwySU59xrh1`%bZLA=+Up~vI$L`8XDP-rmhV(Y#q=3)9mBO% zF%3FTQlcS%luBY;azp$eupHYRX^%V3S@SYjS`ZgWhFlh_;uHl7>SxsP?Kf-LXF^4o z#t~glh5FT(5;}x!8=1Lmp0ekFN zt^jvB`^1bcsvrB}XU-%Q-x`O-@G<<;#YJf7pC$19vhkX%5) zIfhdT63w#WvBT5Q=4|5*=(f!)=M-{Pi+YwNix;LzaV~wLuaL^~J14pIMVdgeg7@&Azw-M!>96Q?968X8R23H@gqJhn9Qm zeKYZ|{4Wx}CuRRrB4yw!i3!Hk$4QLFL$QC0v_|!$4|6tbb&0; z1px>^>PG-IQlmA&AX8F{0;;qsR7q8uk~pV}74bZY3(1Z$(3}Jl_nLHH^CFtBbeJy@ z>vq%@Qu~=xzN}%A$hyfRyg~!Xr2qy~7yD-@0x4Ki&;}uOe4Ik6ZFMal{c2UFI{6W;^taNMecx>Z~g`1U9y$JB!1X>b&i|voX%B` xd3W>^)=98{WuHgXnn)@AjqLf2Jh!1dN%z%{ZV>p{NYY74L-o;n1b_MB{so~xZOi}w literal 0 HcmV?d00001 diff --git a/psets/9/finance/env/lib/python3.12/site-packages/automat/_test/__pycache__/test_type_based.cpython-312.pyc b/psets/9/finance/env/lib/python3.12/site-packages/automat/_test/__pycache__/test_type_based.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..8fe27af11efce975622eb3cf88815b451bd42226 GIT binary patch literal 34948 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≧pax$GvDlqZg#yCc?QzrdvUJ&qNeiu(pl4!CYF( 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 None: + """ + Automaton.unhandledTransition sets the outputs and end-state to be used + for all unhandled transitions. + """ + a: Automaton[str, str, str] = Automaton("start") + a.addTransition("oops-state", "check", "start", tuple(["checked"])) + a.unhandledTransition("oops-state", ["oops-out"]) + t = Transitioner(a, "start") + self.assertEqual(t.transition("check"), (tuple(["oops-out"]), None)) + self.assertEqual(t.transition("check"), (["checked"], None)) + self.assertEqual(t.transition("check"), (tuple(["oops-out"]), None)) + + def test_noOutputForInput(self): + """ + L{Automaton.outputForInput} raises L{NoTransition} if no + transition for that input is defined. + """ + a = Automaton() + self.assertRaises(NoTransition, a.outputForInput, "no-state", "no-symbol") + + def test_oneTransition(self): + """ + L{Automaton.addTransition} adds its input symbol to + L{Automaton.inputAlphabet}, all its outputs to + L{Automaton.outputAlphabet}, and causes L{Automaton.outputForInput} to + start returning the new state and output symbols. + """ + a = Automaton() + a.addTransition("beginning", "begin", "ending", ["end"]) + self.assertEqual(a.inputAlphabet(), {"begin"}) + self.assertEqual(a.outputAlphabet(), {"end"}) + self.assertEqual(a.outputForInput("beginning", "begin"), ("ending", ["end"])) + self.assertEqual(a.states(), {"beginning", "ending"}) + + def test_oneTransition_nonIterableOutputs(self): + """ + L{Automaton.addTransition} raises a TypeError when given outputs + that aren't iterable and doesn't add any transitions. + """ + a = Automaton() + nonIterableOutputs = 1 + self.assertRaises( + TypeError, + a.addTransition, + "fromState", + "viaSymbol", + "toState", + nonIterableOutputs, + ) + self.assertFalse(a.inputAlphabet()) + self.assertFalse(a.outputAlphabet()) + self.assertFalse(a.states()) + self.assertFalse(a.allTransitions()) + + def test_initialState(self): + """ + L{Automaton.initialState} is a descriptor that sets the initial + state if it's not yet set, and raises L{ValueError} if it is. + + """ + a = Automaton() + a.initialState = "a state" + self.assertEqual(a.initialState, "a state") + with self.assertRaises(ValueError): + a.initialState = "another state" + + +# FIXME: addTransition for transition that's been added before diff --git a/psets/9/finance/env/lib/python3.12/site-packages/automat/_test/test_discover.py b/psets/9/finance/env/lib/python3.12/site-packages/automat/_test/test_discover.py new file mode 100644 index 0000000..6e56b94 --- /dev/null +++ b/psets/9/finance/env/lib/python3.12/site-packages/automat/_test/test_discover.py @@ -0,0 +1,638 @@ +import operator +import os +import shutil +import sys +import textwrap +import tempfile +from unittest import skipIf, TestCase + + +def isTwistedInstalled(): + try: + __import__("twisted") + except ImportError: + return False + else: + return True + + +class _WritesPythonModules(TestCase): + """ + A helper that enables generating Python module test fixtures. + """ + + def setUp(self): + super(_WritesPythonModules, self).setUp() + + from twisted.python.modules import getModule, PythonPath + from twisted.python.filepath import FilePath + + self.getModule = getModule + self.PythonPath = PythonPath + self.FilePath = FilePath + + self.originalSysModules = set(sys.modules.keys()) + self.savedSysPath = sys.path[:] + + self.pathDir = tempfile.mkdtemp() + self.makeImportable(self.pathDir) + + def tearDown(self): + super(_WritesPythonModules, self).tearDown() + + sys.path[:] = self.savedSysPath + modulesToDelete = sys.modules.keys() - self.originalSysModules + for module in modulesToDelete: + del sys.modules[module] + + shutil.rmtree(self.pathDir) + + def makeImportable(self, path): + sys.path.append(path) + + def writeSourceInto(self, source, path, moduleName): + directory = self.FilePath(path) + + module = directory.child(moduleName) + # FilePath always opens a file in binary mode - but that will + # break on Python 3 + with open(module.path, "w") as f: + f.write(textwrap.dedent(source)) + + return self.PythonPath([directory.path]) + + def makeModule(self, source, path, moduleName): + pythonModuleName, _ = os.path.splitext(moduleName) + return self.writeSourceInto(source, path, moduleName)[pythonModuleName] + + def attributesAsDict(self, hasIterAttributes): + return {attr.name: attr for attr in hasIterAttributes.iterAttributes()} + + def loadModuleAsDict(self, module): + module.load() + return self.attributesAsDict(module) + + def makeModuleAsDict(self, source, path, name): + return self.loadModuleAsDict(self.makeModule(source, path, name)) + + +@skipIf(not isTwistedInstalled(), "Twisted is not installed.") +class OriginalLocationTests(_WritesPythonModules): + """ + Tests that L{isOriginalLocation} detects when a + L{PythonAttribute}'s FQPN refers to an object inside the module + where it was defined. + + For example: A L{twisted.python.modules.PythonAttribute} with a + name of 'foo.bar' that refers to a 'bar' object defined in module + 'baz' does *not* refer to bar's original location, while a + L{PythonAttribute} with a name of 'baz.bar' does. + + """ + + def setUp(self): + super(OriginalLocationTests, self).setUp() + from .._discover import isOriginalLocation + + self.isOriginalLocation = isOriginalLocation + + def test_failsWithNoModule(self): + """ + L{isOriginalLocation} returns False when the attribute refers to an + object whose source module cannot be determined. + """ + source = """\ + class Fake(object): + pass + hasEmptyModule = Fake() + hasEmptyModule.__module__ = None + """ + + moduleDict = self.makeModuleAsDict(source, self.pathDir, "empty_module_attr.py") + + self.assertFalse( + self.isOriginalLocation(moduleDict["empty_module_attr.hasEmptyModule"]) + ) + + def test_failsWithDifferentModule(self): + """ + L{isOriginalLocation} returns False when the attribute refers to + an object outside of the module where that object was defined. + """ + originalSource = """\ + class ImportThisClass(object): + pass + importThisObject = ImportThisClass() + importThisNestingObject = ImportThisClass() + importThisNestingObject.nestedObject = ImportThisClass() + """ + + importingSource = """\ + from original import (ImportThisClass, + importThisObject, + importThisNestingObject) + """ + + self.makeModule(originalSource, self.pathDir, "original.py") + importingDict = self.makeModuleAsDict( + importingSource, self.pathDir, "importing.py" + ) + self.assertFalse( + self.isOriginalLocation(importingDict["importing.ImportThisClass"]) + ) + self.assertFalse( + self.isOriginalLocation(importingDict["importing.importThisObject"]) + ) + + nestingObject = importingDict["importing.importThisNestingObject"] + nestingObjectDict = self.attributesAsDict(nestingObject) + nestedObject = nestingObjectDict[ + "importing.importThisNestingObject.nestedObject" + ] + + self.assertFalse(self.isOriginalLocation(nestedObject)) + + def test_succeedsWithSameModule(self): + """ + L{isOriginalLocation} returns True when the attribute refers to an + object inside the module where that object was defined. + """ + mSource = textwrap.dedent( + """ + class ThisClassWasDefinedHere(object): + pass + anObject = ThisClassWasDefinedHere() + aNestingObject = ThisClassWasDefinedHere() + aNestingObject.nestedObject = ThisClassWasDefinedHere() + """ + ) + mDict = self.makeModuleAsDict(mSource, self.pathDir, "m.py") + self.assertTrue(self.isOriginalLocation(mDict["m.ThisClassWasDefinedHere"])) + self.assertTrue(self.isOriginalLocation(mDict["m.aNestingObject"])) + + nestingObject = mDict["m.aNestingObject"] + nestingObjectDict = self.attributesAsDict(nestingObject) + nestedObject = nestingObjectDict["m.aNestingObject.nestedObject"] + + self.assertTrue(self.isOriginalLocation(nestedObject)) + + +@skipIf(not isTwistedInstalled(), "Twisted is not installed.") +class FindMachinesViaWrapperTests(_WritesPythonModules): + """ + L{findMachinesViaWrapper} recursively yields FQPN, + L{MethodicalMachine} pairs in and under a given + L{twisted.python.modules.PythonModule} or + L{twisted.python.modules.PythonAttribute}. + """ + + def setUp(self): + super(FindMachinesViaWrapperTests, self).setUp() + from .._discover import findMachinesViaWrapper + + self.findMachinesViaWrapper = findMachinesViaWrapper + + def test_yieldsMachine(self): + """ + When given a L{twisted.python.modules.PythonAttribute} that refers + directly to a L{MethodicalMachine}, L{findMachinesViaWrapper} + yields that machine and its FQPN. + """ + source = """\ + from automat import MethodicalMachine + + rootMachine = MethodicalMachine() + """ + + moduleDict = self.makeModuleAsDict(source, self.pathDir, "root.py") + rootMachine = moduleDict["root.rootMachine"] + self.assertIn( + ("root.rootMachine", rootMachine.load()), + list(self.findMachinesViaWrapper(rootMachine)), + ) + + def test_yieldsTypeMachine(self) -> None: + """ + When given a L{twisted.python.modules.PythonAttribute} that refers + directly to a L{TypeMachine}, L{findMachinesViaWrapper} yields that + machine and its FQPN. + """ + source = """\ + from automat import TypeMachineBuilder + from typing import Protocol, Callable + class P(Protocol): + def method(self) -> None: ... + class C:... + def buildBuilder() -> Callable[[C], P]: + builder = TypeMachineBuilder(P, C) + return builder.build() + rootMachine = buildBuilder() + """ + + moduleDict = self.makeModuleAsDict(source, self.pathDir, "root.py") + rootMachine = moduleDict["root.rootMachine"] + self.assertIn( + ("root.rootMachine", rootMachine.load()), + list(self.findMachinesViaWrapper(rootMachine)), + ) + + def test_yieldsMachineInClass(self): + """ + When given a L{twisted.python.modules.PythonAttribute} that refers + to a class that contains a L{MethodicalMachine} as a class + variable, L{findMachinesViaWrapper} yields that machine and + its FQPN. + """ + source = """\ + from automat import MethodicalMachine + + class PythonClass(object): + _classMachine = MethodicalMachine() + """ + moduleDict = self.makeModuleAsDict(source, self.pathDir, "clsmod.py") + PythonClass = moduleDict["clsmod.PythonClass"] + self.assertIn( + ("clsmod.PythonClass._classMachine", PythonClass.load()._classMachine), + list(self.findMachinesViaWrapper(PythonClass)), + ) + + def test_yieldsMachineInNestedClass(self): + """ + When given a L{twisted.python.modules.PythonAttribute} that refers + to a nested class that contains a L{MethodicalMachine} as a + class variable, L{findMachinesViaWrapper} yields that machine + and its FQPN. + """ + source = """\ + from automat import MethodicalMachine + + class PythonClass(object): + class NestedClass(object): + _classMachine = MethodicalMachine() + """ + moduleDict = self.makeModuleAsDict(source, self.pathDir, "nestedcls.py") + + PythonClass = moduleDict["nestedcls.PythonClass"] + self.assertIn( + ( + "nestedcls.PythonClass.NestedClass._classMachine", + PythonClass.load().NestedClass._classMachine, + ), + list(self.findMachinesViaWrapper(PythonClass)), + ) + + def test_yieldsMachineInModule(self): + """ + When given a L{twisted.python.modules.PythonModule} that refers to + a module that contains a L{MethodicalMachine}, + L{findMachinesViaWrapper} yields that machine and its FQPN. + """ + source = """\ + from automat import MethodicalMachine + + rootMachine = MethodicalMachine() + """ + module = self.makeModule(source, self.pathDir, "root.py") + rootMachine = self.loadModuleAsDict(module)["root.rootMachine"].load() + self.assertIn( + ("root.rootMachine", rootMachine), list(self.findMachinesViaWrapper(module)) + ) + + def test_yieldsMachineInClassInModule(self): + """ + When given a L{twisted.python.modules.PythonModule} that refers to + the original module of a class containing a + L{MethodicalMachine}, L{findMachinesViaWrapper} yields that + machine and its FQPN. + """ + source = """\ + from automat import MethodicalMachine + + class PythonClass(object): + _classMachine = MethodicalMachine() + """ + module = self.makeModule(source, self.pathDir, "clsmod.py") + PythonClass = self.loadModuleAsDict(module)["clsmod.PythonClass"].load() + self.assertIn( + ("clsmod.PythonClass._classMachine", PythonClass._classMachine), + list(self.findMachinesViaWrapper(module)), + ) + + def test_yieldsMachineInNestedClassInModule(self): + """ + When given a L{twisted.python.modules.PythonModule} that refers to + the original module of a nested class containing a + L{MethodicalMachine}, L{findMachinesViaWrapper} yields that + machine and its FQPN. + """ + source = """\ + from automat import MethodicalMachine + + class PythonClass(object): + class NestedClass(object): + _classMachine = MethodicalMachine() + """ + module = self.makeModule(source, self.pathDir, "nestedcls.py") + PythonClass = self.loadModuleAsDict(module)["nestedcls.PythonClass"].load() + + self.assertIn( + ( + "nestedcls.PythonClass.NestedClass._classMachine", + PythonClass.NestedClass._classMachine, + ), + list(self.findMachinesViaWrapper(module)), + ) + + def test_ignoresImportedClass(self): + """ + When given a L{twisted.python.modules.PythonAttribute} that refers + to a class imported from another module, any + L{MethodicalMachine}s on that class are ignored. + + This behavior ensures that a machine is only discovered on a + class when visiting the module where that class was defined. + """ + originalSource = """ + from automat import MethodicalMachine + + class PythonClass(object): + _classMachine = MethodicalMachine() + """ + + importingSource = """ + from original import PythonClass + """ + + self.makeModule(originalSource, self.pathDir, "original.py") + importingModule = self.makeModule(importingSource, self.pathDir, "importing.py") + + self.assertFalse(list(self.findMachinesViaWrapper(importingModule))) + + def test_descendsIntoPackages(self): + """ + L{findMachinesViaWrapper} descends into packages to discover + machines. + """ + pythonPath = self.PythonPath([self.pathDir]) + package = self.FilePath(self.pathDir).child("test_package") + package.makedirs() + package.child("__init__.py").touch() + + source = """ + from automat import MethodicalMachine + + + class PythonClass(object): + _classMachine = MethodicalMachine() + + + rootMachine = MethodicalMachine() + """ + self.makeModule(source, package.path, "module.py") + + test_package = pythonPath["test_package"] + machines = sorted( + self.findMachinesViaWrapper(test_package), key=operator.itemgetter(0) + ) + + moduleDict = self.loadModuleAsDict(test_package["module"]) + rootMachine = moduleDict["test_package.module.rootMachine"].load() + PythonClass = moduleDict["test_package.module.PythonClass"].load() + + expectedMachines = sorted( + [ + ("test_package.module.rootMachine", rootMachine), + ( + "test_package.module.PythonClass._classMachine", + PythonClass._classMachine, + ), + ], + key=operator.itemgetter(0), + ) + + self.assertEqual(expectedMachines, machines) + + def test_infiniteLoop(self): + """ + L{findMachinesViaWrapper} ignores infinite loops. + + Note this test can't fail - it can only run forever! + """ + source = """ + class InfiniteLoop(object): + pass + + InfiniteLoop.loop = InfiniteLoop + """ + module = self.makeModule(source, self.pathDir, "loop.py") + self.assertFalse(list(self.findMachinesViaWrapper(module))) + + +@skipIf(not isTwistedInstalled(), "Twisted is not installed.") +class WrapFQPNTests(TestCase): + """ + Tests that ensure L{wrapFQPN} loads the + L{twisted.python.modules.PythonModule} or + L{twisted.python.modules.PythonAttribute} for a given FQPN. + """ + + def setUp(self): + from twisted.python.modules import PythonModule, PythonAttribute + from .._discover import wrapFQPN, InvalidFQPN, NoModule, NoObject + + self.PythonModule = PythonModule + self.PythonAttribute = PythonAttribute + self.wrapFQPN = wrapFQPN + self.InvalidFQPN = InvalidFQPN + self.NoModule = NoModule + self.NoObject = NoObject + + def assertModuleWrapperRefersTo(self, moduleWrapper, module): + """ + Assert that a L{twisted.python.modules.PythonModule} refers to a + particular Python module. + """ + self.assertIsInstance(moduleWrapper, self.PythonModule) + self.assertEqual(moduleWrapper.name, module.__name__) + self.assertIs(moduleWrapper.load(), module) + + def assertAttributeWrapperRefersTo(self, attributeWrapper, fqpn, obj): + """ + Assert that a L{twisted.python.modules.PythonAttribute} refers to a + particular Python object. + """ + self.assertIsInstance(attributeWrapper, self.PythonAttribute) + self.assertEqual(attributeWrapper.name, fqpn) + self.assertIs(attributeWrapper.load(), obj) + + def test_failsWithEmptyFQPN(self): + """ + L{wrapFQPN} raises L{InvalidFQPN} when given an empty string. + """ + with self.assertRaises(self.InvalidFQPN): + self.wrapFQPN("") + + def test_failsWithBadDotting(self): + """ " + L{wrapFQPN} raises L{InvalidFQPN} when given a badly-dotted + FQPN. (e.g., x..y). + """ + for bad in (".fails", "fails.", "this..fails"): + with self.assertRaises(self.InvalidFQPN): + self.wrapFQPN(bad) + + def test_singleModule(self): + """ + L{wrapFQPN} returns a L{twisted.python.modules.PythonModule} + referring to the single module a dotless FQPN describes. + """ + import os + + moduleWrapper = self.wrapFQPN("os") + + self.assertIsInstance(moduleWrapper, self.PythonModule) + self.assertIs(moduleWrapper.load(), os) + + def test_failsWithMissingSingleModuleOrPackage(self): + """ + L{wrapFQPN} raises L{NoModule} when given a dotless FQPN that does + not refer to a module or package. + """ + with self.assertRaises(self.NoModule): + self.wrapFQPN("this is not an acceptable name!") + + def test_singlePackage(self): + """ + L{wrapFQPN} returns a L{twisted.python.modules.PythonModule} + referring to the single package a dotless FQPN describes. + """ + import xml + + self.assertModuleWrapperRefersTo(self.wrapFQPN("xml"), xml) + + def test_multiplePackages(self): + """ + L{wrapFQPN} returns a L{twisted.python.modules.PythonModule} + referring to the deepest package described by dotted FQPN. + """ + import xml.etree + + self.assertModuleWrapperRefersTo(self.wrapFQPN("xml.etree"), xml.etree) + + def test_multiplePackagesFinalModule(self): + """ + L{wrapFQPN} returns a L{twisted.python.modules.PythonModule} + referring to the deepest module described by dotted FQPN. + """ + import xml.etree.ElementTree + + self.assertModuleWrapperRefersTo( + self.wrapFQPN("xml.etree.ElementTree"), xml.etree.ElementTree + ) + + def test_singleModuleObject(self): + """ + L{wrapFQPN} returns a L{twisted.python.modules.PythonAttribute} + referring to the deepest object an FQPN names, traversing one module. + """ + import os + + self.assertAttributeWrapperRefersTo( + self.wrapFQPN("os.path"), "os.path", os.path + ) + + def test_multiplePackagesObject(self): + """ + L{wrapFQPN} returns a L{twisted.python.modules.PythonAttribute} + referring to the deepest object described by an FQPN, + descending through several packages. + """ + import xml.etree.ElementTree + import automat + + for fqpn, obj in [ + ("xml.etree.ElementTree.fromstring", xml.etree.ElementTree.fromstring), + ("automat.MethodicalMachine.__doc__", automat.MethodicalMachine.__doc__), + ]: + self.assertAttributeWrapperRefersTo(self.wrapFQPN(fqpn), fqpn, obj) + + def test_failsWithMultiplePackagesMissingModuleOrPackage(self): + """ + L{wrapFQPN} raises L{NoObject} when given an FQPN that contains a + missing attribute, module, or package. + """ + for bad in ("xml.etree.nope!", "xml.etree.nope!.but.the.rest.is.believable"): + with self.assertRaises(self.NoObject): + self.wrapFQPN(bad) + + +@skipIf(not isTwistedInstalled(), "Twisted is not installed.") +class FindMachinesIntegrationTests(_WritesPythonModules): + """ + Integration tests to check that L{findMachines} yields all + machines discoverable at or below an FQPN. + """ + + SOURCE = """ + from automat import MethodicalMachine + + class PythonClass(object): + _machine = MethodicalMachine() + ignored = "i am ignored" + + rootLevel = MethodicalMachine() + + ignored = "i am ignored" + """ + + def setUp(self): + super(FindMachinesIntegrationTests, self).setUp() + from .._discover import findMachines + + self.findMachines = findMachines + + packageDir = self.FilePath(self.pathDir).child("test_package") + packageDir.makedirs() + self.pythonPath = self.PythonPath([self.pathDir]) + self.writeSourceInto(self.SOURCE, packageDir.path, "__init__.py") + + subPackageDir = packageDir.child("subpackage") + subPackageDir.makedirs() + subPackageDir.child("__init__.py").touch() + + self.makeModule(self.SOURCE, subPackageDir.path, "module.py") + + self.packageDict = self.loadModuleAsDict(self.pythonPath["test_package"]) + self.moduleDict = self.loadModuleAsDict( + self.pythonPath["test_package"]["subpackage"]["module"] + ) + + def test_discoverAll(self): + """ + Given a top-level package FQPN, L{findMachines} discovers all + L{MethodicalMachine} instances in and below it. + """ + machines = sorted(self.findMachines("test_package"), key=operator.itemgetter(0)) + + tpRootLevel = self.packageDict["test_package.rootLevel"].load() + tpPythonClass = self.packageDict["test_package.PythonClass"].load() + + mRLAttr = self.moduleDict["test_package.subpackage.module.rootLevel"] + mRootLevel = mRLAttr.load() + mPCAttr = self.moduleDict["test_package.subpackage.module.PythonClass"] + mPythonClass = mPCAttr.load() + + expectedMachines = sorted( + [ + ("test_package.rootLevel", tpRootLevel), + ("test_package.PythonClass._machine", tpPythonClass._machine), + ("test_package.subpackage.module.rootLevel", mRootLevel), + ( + "test_package.subpackage.module.PythonClass._machine", + mPythonClass._machine, + ), + ], + key=operator.itemgetter(0), + ) + + self.assertEqual(expectedMachines, machines) diff --git a/psets/9/finance/env/lib/python3.12/site-packages/automat/_test/test_methodical.py b/psets/9/finance/env/lib/python3.12/site-packages/automat/_test/test_methodical.py new file mode 100644 index 0000000..ca03e66 --- /dev/null +++ b/psets/9/finance/env/lib/python3.12/site-packages/automat/_test/test_methodical.py @@ -0,0 +1,717 @@ +""" +Tests for the public interface of Automat. +""" + +from functools import reduce +from unittest import TestCase + +from automat._methodical import ArgSpec, _getArgNames, _getArgSpec, _filterArgs +from .. import MethodicalMachine, NoTransition +from .. import _methodical + + +class MethodicalTests(TestCase): + """ + Tests for L{MethodicalMachine}. + """ + + def test_oneTransition(self): + """ + L{MethodicalMachine} provides a way for you to declare a state machine + with inputs, outputs, and states as methods. When you have declared an + input, an output, and a state, calling the input method in that state + will produce the specified output. + """ + + class Machination(object): + machine = MethodicalMachine() + + @machine.input() + def anInput(self): + "an input" + + @machine.output() + def anOutput(self): + "an output" + return "an-output-value" + + @machine.output() + def anotherOutput(self): + "another output" + return "another-output-value" + + @machine.state(initial=True) + def anState(self): + "a state" + + @machine.state() + def anotherState(self): + "another state" + + anState.upon(anInput, enter=anotherState, outputs=[anOutput]) + anotherState.upon(anInput, enter=anotherState, outputs=[anotherOutput]) + + m = Machination() + self.assertEqual(m.anInput(), ["an-output-value"]) + self.assertEqual(m.anInput(), ["another-output-value"]) + + def test_machineItselfIsPrivate(self): + """ + L{MethodicalMachine} is an implementation detail. If you attempt to + access it on an instance of your class, you will get an exception. + However, since tools may need to access it for the purposes of, for + example, visualization, you may access it on the class itself. + """ + expectedMachine = MethodicalMachine() + + class Machination(object): + machine = expectedMachine + + machination = Machination() + with self.assertRaises(AttributeError) as cm: + machination.machine + self.assertIn( + "MethodicalMachine is an implementation detail", str(cm.exception) + ) + self.assertIs(Machination.machine, expectedMachine) + + def test_outputsArePrivate(self): + """ + One of the benefits of using a state machine is that your output method + implementations don't need to take invalid state transitions into + account - the methods simply won't be called. This property would be + broken if client code called output methods directly, so output methods + are not directly visible under their names. + """ + + class Machination(object): + machine = MethodicalMachine() + counter = 0 + + @machine.input() + def anInput(self): + "an input" + + @machine.output() + def anOutput(self): + self.counter += 1 + + @machine.state(initial=True) + def state(self): + "a machine state" + + state.upon(anInput, enter=state, outputs=[anOutput]) + + mach1 = Machination() + mach1.anInput() + self.assertEqual(mach1.counter, 1) + mach2 = Machination() + with self.assertRaises(AttributeError) as cm: + mach2.anOutput + self.assertEqual(mach2.counter, 0) + + self.assertIn( + "Machination.anOutput is a state-machine output method; to " + "produce this output, call an input method instead.", + str(cm.exception), + ) + + def test_multipleMachines(self): + """ + Two machines may co-exist happily on the same instance; they don't + interfere with each other. + """ + + class MultiMach(object): + a = MethodicalMachine() + b = MethodicalMachine() + + @a.input() + def inputA(self): + "input A" + + @b.input() + def inputB(self): + "input B" + + @a.state(initial=True) + def initialA(self): + "initial A" + + @b.state(initial=True) + def initialB(self): + "initial B" + + @a.output() + def outputA(self): + return "A" + + @b.output() + def outputB(self): + return "B" + + initialA.upon(inputA, initialA, [outputA]) + initialB.upon(inputB, initialB, [outputB]) + + mm = MultiMach() + self.assertEqual(mm.inputA(), ["A"]) + self.assertEqual(mm.inputB(), ["B"]) + + def test_collectOutputs(self): + """ + Outputs can be combined with the "collector" argument to "upon". + """ + import operator + + class Machine(object): + m = MethodicalMachine() + + @m.input() + def input(self): + "an input" + + @m.output() + def outputA(self): + return "A" + + @m.output() + def outputB(self): + return "B" + + @m.state(initial=True) + def state(self): + "a state" + + state.upon( + input, + state, + [outputA, outputB], + collector=lambda x: reduce(operator.add, x), + ) + + m = Machine() + self.assertEqual(m.input(), "AB") + + def test_methodName(self): + """ + Input methods preserve their declared names. + """ + + class Mech(object): + m = MethodicalMachine() + + @m.input() + def declaredInputName(self): + "an input" + + @m.state(initial=True) + def aState(self): + "state" + + m = Mech() + with self.assertRaises(TypeError) as cm: + m.declaredInputName("too", "many", "arguments") + self.assertIn("declaredInputName", str(cm.exception)) + + def test_inputWithArguments(self): + """ + If an input takes an argument, it will pass that along to its output. + """ + + class Mechanism(object): + m = MethodicalMachine() + + @m.input() + def input(self, x, y=1): + "an input" + + @m.state(initial=True) + def state(self): + "a state" + + @m.output() + def output(self, x, y=1): + self._x = x + return x + y + + state.upon(input, state, [output]) + + m = Mechanism() + self.assertEqual(m.input(3), [4]) + self.assertEqual(m._x, 3) + + def test_outputWithSubsetOfArguments(self): + """ + Inputs pass arguments that output will accept. + """ + + class Mechanism(object): + m = MethodicalMachine() + + @m.input() + def input(self, x, y=1): + "an input" + + @m.state(initial=True) + def state(self): + "a state" + + @m.output() + def outputX(self, x): + self._x = x + return x + + @m.output() + def outputY(self, y): + self._y = y + return y + + @m.output() + def outputNoArgs(self): + return None + + state.upon(input, state, [outputX, outputY, outputNoArgs]) + + m = Mechanism() + + # Pass x as positional argument. + self.assertEqual(m.input(3), [3, 1, None]) + self.assertEqual(m._x, 3) + self.assertEqual(m._y, 1) + + # Pass x as key word argument. + self.assertEqual(m.input(x=4), [4, 1, None]) + self.assertEqual(m._x, 4) + self.assertEqual(m._y, 1) + + # Pass y as positional argument. + self.assertEqual(m.input(6, 3), [6, 3, None]) + self.assertEqual(m._x, 6) + self.assertEqual(m._y, 3) + + # Pass y as key word argument. + self.assertEqual(m.input(5, y=2), [5, 2, None]) + self.assertEqual(m._x, 5) + self.assertEqual(m._y, 2) + + def test_inputFunctionsMustBeEmpty(self): + """ + The wrapped input function must have an empty body. + """ + # input functions are executed to assert that the signature matches, + # but their body must be empty + + _methodical._empty() # chase coverage + _methodical._docstring() + + class Mechanism(object): + m = MethodicalMachine() + with self.assertRaises(ValueError) as cm: + + @m.input() + def input(self): + "an input" + list() # pragma: no cover + + self.assertEqual(str(cm.exception), "function body must be empty") + + # all three of these cases should be valid. Functions/methods with + # docstrings produce slightly different bytecode than ones without. + + class MechanismWithDocstring(object): + m = MethodicalMachine() + + @m.input() + def input(self): + "an input" + + @m.state(initial=True) + def start(self): + "starting state" + + start.upon(input, enter=start, outputs=[]) + + MechanismWithDocstring().input() + + class MechanismWithPass(object): + m = MethodicalMachine() + + @m.input() + def input(self): + pass + + @m.state(initial=True) + def start(self): + "starting state" + + start.upon(input, enter=start, outputs=[]) + + MechanismWithPass().input() + + class MechanismWithDocstringAndPass(object): + m = MethodicalMachine() + + @m.input() + def input(self): + "an input" + pass + + @m.state(initial=True) + def start(self): + "starting state" + + start.upon(input, enter=start, outputs=[]) + + MechanismWithDocstringAndPass().input() + + class MechanismReturnsNone(object): + m = MethodicalMachine() + + @m.input() + def input(self): + return None + + @m.state(initial=True) + def start(self): + "starting state" + + start.upon(input, enter=start, outputs=[]) + + MechanismReturnsNone().input() + + class MechanismWithDocstringAndReturnsNone(object): + m = MethodicalMachine() + + @m.input() + def input(self): + "an input" + return None + + @m.state(initial=True) + def start(self): + "starting state" + + start.upon(input, enter=start, outputs=[]) + + MechanismWithDocstringAndReturnsNone().input() + + def test_inputOutputMismatch(self): + """ + All the argument lists of the outputs for a given input must match; if + one does not the call to C{upon} will raise a C{TypeError}. + """ + + class Mechanism(object): + m = MethodicalMachine() + + @m.input() + def nameOfInput(self, a): + "an input" + + @m.output() + def outputThatMatches(self, a): + "an output that matches" + + @m.output() + def outputThatDoesntMatch(self, b): + "an output that doesn't match" + + @m.state() + def state(self): + "a state" + + with self.assertRaises(TypeError) as cm: + state.upon( + nameOfInput, state, [outputThatMatches, outputThatDoesntMatch] + ) + self.assertIn("nameOfInput", str(cm.exception)) + self.assertIn("outputThatDoesntMatch", str(cm.exception)) + + def test_stateLoop(self): + """ + It is possible to write a self-loop by omitting "enter" + """ + + class Mechanism(object): + m = MethodicalMachine() + + @m.input() + def input(self): + "an input" + + @m.input() + def say_hi(self): + "an input" + + @m.output() + def _start_say_hi(self): + return "hi" + + @m.state(initial=True) + def start(self): + "a state" + + def said_hi(self): + "a state with no inputs" + + start.upon(input, outputs=[]) + start.upon(say_hi, outputs=[_start_say_hi]) + + a_mechanism = Mechanism() + [a_greeting] = a_mechanism.say_hi() + self.assertEqual(a_greeting, "hi") + + def test_defaultOutputs(self): + """ + It is possible to write a transition with no outputs + """ + + class Mechanism(object): + m = MethodicalMachine() + + @m.input() + def finish(self): + "final transition" + + @m.state(initial=True) + def start(self): + "a start state" + + @m.state() + def finished(self): + "a final state" + + start.upon(finish, enter=finished) + + Mechanism().finish() + + def test_getArgNames(self): + """ + Type annotations should be included in the set of + """ + spec = ArgSpec( + args=("a", "b"), + varargs=None, + varkw=None, + defaults=None, + kwonlyargs=(), + kwonlydefaults=None, + annotations=(("a", int), ("b", str)), + ) + self.assertEqual( + _getArgNames(spec), + {"a", "b", ("a", int), ("b", str)}, + ) + + def test_filterArgs(self): + """ + filterArgs() should not filter the `args` parameter + if outputSpec accepts `*args`. + """ + inputSpec = _getArgSpec(lambda *args, **kwargs: None) + outputSpec = _getArgSpec(lambda *args, **kwargs: None) + argsIn = () + argsOut, _ = _filterArgs(argsIn, {}, inputSpec, outputSpec) + self.assertIs(argsIn, argsOut) + + def test_multipleInitialStatesFailure(self): + """ + A L{MethodicalMachine} can only have one initial state. + """ + + class WillFail(object): + m = MethodicalMachine() + + @m.state(initial=True) + def firstInitialState(self): + "The first initial state -- this is OK." + + with self.assertRaises(ValueError): + + @m.state(initial=True) + def secondInitialState(self): + "The second initial state -- results in a ValueError." + + def test_multipleTransitionsFailure(self): + """ + A L{MethodicalMachine} can only have one transition per start/event + pair. + """ + + class WillFail(object): + m = MethodicalMachine() + + @m.state(initial=True) + def start(self): + "We start here." + + @m.state() + def end(self): + "Rainbows end." + + @m.input() + def event(self): + "An event." + + start.upon(event, enter=end, outputs=[]) + with self.assertRaises(ValueError): + start.upon(event, enter=end, outputs=[]) + + def test_badTransitionForCurrentState(self): + """ + Calling any input method that lacks a transition for the machine's + current state raises an informative L{NoTransition}. + """ + + class OnlyOnePath(object): + m = MethodicalMachine() + + @m.state(initial=True) + def start(self): + "Start state." + + @m.state() + def end(self): + "End state." + + @m.input() + def advance(self): + "Move from start to end." + + @m.input() + def deadEnd(self): + "A transition from nowhere to nowhere." + + start.upon(advance, end, []) + + machine = OnlyOnePath() + with self.assertRaises(NoTransition) as cm: + machine.deadEnd() + self.assertIn("deadEnd", str(cm.exception)) + self.assertIn("start", str(cm.exception)) + machine.advance() + with self.assertRaises(NoTransition) as cm: + machine.deadEnd() + self.assertIn("deadEnd", str(cm.exception)) + self.assertIn("end", str(cm.exception)) + + def test_saveState(self): + """ + L{MethodicalMachine.serializer} is a decorator that modifies its + decoratee's signature to take a "state" object as its first argument, + which is the "serialized" argument to the L{MethodicalMachine.state} + decorator. + """ + + class Mechanism(object): + m = MethodicalMachine() + + def __init__(self): + self.value = 1 + + @m.state(serialized="first-state", initial=True) + def first(self): + "First state." + + @m.state(serialized="second-state") + def second(self): + "Second state." + + @m.serializer() + def save(self, state): + return { + "machine-state": state, + "some-value": self.value, + } + + self.assertEqual( + Mechanism().save(), + { + "machine-state": "first-state", + "some-value": 1, + }, + ) + + def test_restoreState(self): + """ + L{MethodicalMachine.unserializer} decorates a function that becomes a + machine-state unserializer; its return value is mapped to the + C{serialized} parameter to C{state}, and the L{MethodicalMachine} + associated with that instance's state is updated to that state. + """ + + class Mechanism(object): + m = MethodicalMachine() + + def __init__(self): + self.value = 1 + self.ranOutput = False + + @m.state(serialized="first-state", initial=True) + def first(self): + "First state." + + @m.state(serialized="second-state") + def second(self): + "Second state." + + @m.input() + def input(self): + "an input" + + @m.output() + def output(self): + self.value = 2 + self.ranOutput = True + return 1 + + @m.output() + def output2(self): + return 2 + + first.upon(input, second, [output], collector=lambda x: list(x)[0]) + second.upon(input, second, [output2], collector=lambda x: list(x)[0]) + + @m.serializer() + def save(self, state): + return { + "machine-state": state, + "some-value": self.value, + } + + @m.unserializer() + def _restore(self, blob): + self.value = blob["some-value"] + return blob["machine-state"] + + @classmethod + def fromBlob(cls, blob): + self = cls() + self._restore(blob) + return self + + m1 = Mechanism() + m1.input() + blob = m1.save() + m2 = Mechanism.fromBlob(blob) + self.assertEqual(m2.ranOutput, False) + self.assertEqual(m2.input(), 2) + self.assertEqual( + m2.save(), + { + "machine-state": "second-state", + "some-value": 2, + }, + ) + + +# FIXME: error for wrong types on any call to _oneTransition +# FIXME: better public API for .upon; maybe a context manager? +# FIXME: when transitions are defined, validate that we can always get to +# terminal? do we care about this? +# FIXME: implementation (and use-case/example) for passing args from in to out + +# FIXME: possibly these need some kind of support from core +# FIXME: wildcard state (in all states, when input X, emit Y and go to Z) +# FIXME: wildcard input (in state X, when any input, emit Y and go to Z) +# FIXME: combined wildcards (in any state for any input, emit Y go to Z) diff --git a/psets/9/finance/env/lib/python3.12/site-packages/automat/_test/test_trace.py b/psets/9/finance/env/lib/python3.12/site-packages/automat/_test/test_trace.py new file mode 100644 index 0000000..6533cf1 --- /dev/null +++ b/psets/9/finance/env/lib/python3.12/site-packages/automat/_test/test_trace.py @@ -0,0 +1,142 @@ +from unittest import TestCase +from .._methodical import MethodicalMachine + + +class SampleObject(object): + mm = MethodicalMachine() + + @mm.state(initial=True) + def begin(self): + "initial state" + + @mm.state() + def middle(self): + "middle state" + + @mm.state() + def end(self): + "end state" + + @mm.input() + def go1(self): + "sample input" + + @mm.input() + def go2(self): + "sample input" + + @mm.input() + def back(self): + "sample input" + + @mm.output() + def out(self): + "sample output" + + setTrace = mm._setTrace + + begin.upon(go1, middle, [out]) + middle.upon(go2, end, [out]) + end.upon(back, middle, []) + middle.upon(back, begin, []) + + +class TraceTests(TestCase): + def test_only_inputs(self): + traces = [] + + def tracer(old_state, input, new_state): + traces.append((old_state, input, new_state)) + return None # "I only care about inputs, not outputs" + + s = SampleObject() + s.setTrace(tracer) + + s.go1() + self.assertEqual( + traces, + [ + ("begin", "go1", "middle"), + ], + ) + + s.go2() + self.assertEqual( + traces, + [ + ("begin", "go1", "middle"), + ("middle", "go2", "end"), + ], + ) + s.setTrace(None) + s.back() + self.assertEqual( + traces, + [ + ("begin", "go1", "middle"), + ("middle", "go2", "end"), + ], + ) + s.go2() + self.assertEqual( + traces, + [ + ("begin", "go1", "middle"), + ("middle", "go2", "end"), + ], + ) + + def test_inputs_and_outputs(self): + traces = [] + + def tracer(old_state, input, new_state): + traces.append((old_state, input, new_state, None)) + + def trace_outputs(output): + traces.append((old_state, input, new_state, output)) + + return trace_outputs # "I care about outputs too" + + s = SampleObject() + s.setTrace(tracer) + + s.go1() + self.assertEqual( + traces, + [ + ("begin", "go1", "middle", None), + ("begin", "go1", "middle", "out"), + ], + ) + + s.go2() + self.assertEqual( + traces, + [ + ("begin", "go1", "middle", None), + ("begin", "go1", "middle", "out"), + ("middle", "go2", "end", None), + ("middle", "go2", "end", "out"), + ], + ) + s.setTrace(None) + s.back() + self.assertEqual( + traces, + [ + ("begin", "go1", "middle", None), + ("begin", "go1", "middle", "out"), + ("middle", "go2", "end", None), + ("middle", "go2", "end", "out"), + ], + ) + s.go2() + self.assertEqual( + traces, + [ + ("begin", "go1", "middle", None), + ("begin", "go1", "middle", "out"), + ("middle", "go2", "end", None), + ("middle", "go2", "end", "out"), + ], + ) diff --git a/psets/9/finance/env/lib/python3.12/site-packages/automat/_test/test_type_based.py b/psets/9/finance/env/lib/python3.12/site-packages/automat/_test/test_type_based.py new file mode 100644 index 0000000..2666353 --- /dev/null +++ b/psets/9/finance/env/lib/python3.12/site-packages/automat/_test/test_type_based.py @@ -0,0 +1,534 @@ +from __future__ import annotations + +from dataclasses import dataclass +from typing import Callable, Generic, List, Protocol, TypeVar +from unittest import TestCase, skipIf + +from .. import AlreadyBuiltError, NoTransition, TypeMachineBuilder, pep614 + +try: + from zope.interface import Interface, implementer # type:ignore[import-untyped] +except ImportError: + hasInterface = False +else: + hasInterface = True + + class ISomething(Interface): + def something() -> int: ... # type:ignore[misc,empty-body] + + +T = TypeVar("T") + + +class ProtocolForTesting(Protocol): + + def change(self) -> None: + "Switch to the other state." + + def value(self) -> int: + "Give a value specific to the given state." + + +class ArgTaker(Protocol): + def takeSomeArgs(self, arg1: int = 0, arg2: str = "") -> None: ... + def value(self) -> int: ... + + +class NoOpCore: + "Just an object, you know?" + + +@dataclass +class Gen(Generic[T]): + t: T + + +def buildTestBuilder() -> tuple[ + TypeMachineBuilder[ProtocolForTesting, NoOpCore], + Callable[[NoOpCore], ProtocolForTesting], +]: + builder = TypeMachineBuilder(ProtocolForTesting, NoOpCore) + first = builder.state("first") + second = builder.state("second") + + first.upon(ProtocolForTesting.change).to(second).returns(None) + second.upon(ProtocolForTesting.change).to(first).returns(None) + + @pep614(first.upon(ProtocolForTesting.value).loop()) + def firstValue(machine: ProtocolForTesting, core: NoOpCore) -> int: + return 3 + + @pep614(second.upon(ProtocolForTesting.value).loop()) + def secondValue(machine: ProtocolForTesting, core: NoOpCore) -> int: + return 4 + + return builder, builder.build() + + +builder, machineFactory = buildTestBuilder() + + +def needsSomething(proto: ProtocolForTesting, core: NoOpCore, value: str) -> int: + "we need data to build this state" + return 3 # pragma: no cover + + +def needsNothing(proto: ArgTaker, core: NoOpCore) -> str: + return "state-specific data" # pragma: no cover + + +class SimpleProtocol(Protocol): + def method(self) -> None: + "A method" + + +class Counter(Protocol): + def start(self) -> None: + "enter the counting state" + + def increment(self) -> None: + "increment the counter" + + def stop(self) -> int: + "stop" + + +@dataclass +class Count: + value: int = 0 + + +class TypeMachineTests(TestCase): + + def test_oneTransition(self) -> None: + + machine = machineFactory(NoOpCore()) + + self.assertEqual(machine.value(), 3) + machine.change() + self.assertEqual(machine.value(), 4) + self.assertEqual(machine.value(), 4) + machine.change() + self.assertEqual(machine.value(), 3) + + def test_stateSpecificData(self) -> None: + + builder = TypeMachineBuilder(Counter, NoOpCore) + initial = builder.state("initial") + counting = builder.state("counting", lambda machine, core: Count()) + initial.upon(Counter.start).to(counting).returns(None) + + @pep614(counting.upon(Counter.increment).loop()) + def incf(counter: Counter, core: NoOpCore, count: Count) -> None: + count.value += 1 + + @pep614(counting.upon(Counter.stop).to(initial)) + def finish(counter: Counter, core: NoOpCore, count: Count) -> int: + return count.value + + machineFactory = builder.build() + machine = machineFactory(NoOpCore()) + machine.start() + machine.increment() + machine.increment() + self.assertEqual(machine.stop(), 2) + machine.start() + machine.increment() + self.assertEqual(machine.stop(), 1) + + def test_stateSpecificDataWithoutData(self) -> None: + """ + To facilitate common implementations of transition behavior methods, + sometimes you want to implement a transition within a data state + without taking a data parameter. To do this, pass the 'nodata=True' + parameter to 'upon'. + """ + builder = TypeMachineBuilder(Counter, NoOpCore) + initial = builder.state("initial") + counting = builder.state("counting", lambda machine, core: Count()) + startCalls = [] + + @pep614(initial.upon(Counter.start).to(counting)) + @pep614(counting.upon(Counter.start, nodata=True).loop()) + def start(counter: Counter, core: NoOpCore) -> None: + startCalls.append("started!") + + @pep614(counting.upon(Counter.increment).loop()) + def incf(counter: Counter, core: NoOpCore, count: Count) -> None: + count.value += 1 + + @pep614(counting.upon(Counter.stop).to(initial)) + def finish(counter: Counter, core: NoOpCore, count: Count) -> int: + return count.value + + machineFactory = builder.build() + machine = machineFactory(NoOpCore()) + machine.start() + self.assertEqual(len(startCalls), 1) + machine.start() + self.assertEqual(len(startCalls), 2) + machine.increment() + self.assertEqual(machine.stop(), 1) + + def test_incompleteTransitionDefinition(self) -> None: + builder = TypeMachineBuilder(SimpleProtocol, NoOpCore) + sample = builder.state("sample") + sample.upon(SimpleProtocol.method).loop() # oops, no '.returns(None)' + with self.assertRaises(ValueError) as raised: + builder.build() + self.assertIn( + "incomplete transition from sample to sample upon SimpleProtocol.method", + str(raised.exception), + ) + + def test_dataToData(self) -> None: + builder = TypeMachineBuilder(ProtocolForTesting, NoOpCore) + + @dataclass + class Data1: + value: int + + @dataclass + class Data2: + stuff: List[str] + + initial = builder.state("initial") + counting = builder.state("counting", lambda proto, core: Data1(1)) + appending = builder.state("appending", lambda proto, core: Data2([])) + + initial.upon(ProtocolForTesting.change).to(counting).returns(None) + + @pep614(counting.upon(ProtocolForTesting.value).loop()) + def countup(p: ProtocolForTesting, c: NoOpCore, d: Data1) -> int: + d.value *= 2 + return d.value + + counting.upon(ProtocolForTesting.change).to(appending).returns(None) + + @pep614(appending.upon(ProtocolForTesting.value).loop()) + def appendup(p: ProtocolForTesting, c: NoOpCore, d: Data2) -> int: + d.stuff.extend("abc") + return len(d.stuff) + + machineFactory = builder.build() + machine = machineFactory(NoOpCore()) + machine.change() + self.assertEqual(machine.value(), 2) + self.assertEqual(machine.value(), 4) + machine.change() + self.assertEqual(machine.value(), 3) + self.assertEqual(machine.value(), 6) + + def test_dataFactoryArgs(self) -> None: + """ + Any data factory that takes arguments will constrain the allowed + signature of all protocol methods that transition into that state. + """ + builder = TypeMachineBuilder(ProtocolForTesting, NoOpCore) + initial = builder.state("initial") + data = builder.state("data", needsSomething) + data2 = builder.state("data2", needsSomething) + # toState = initial.to(data) + + # 'assertions' in the form of expected type errors: + # (no data -> data) + uponNoData = initial.upon(ProtocolForTesting.change) + uponNoData.to(data) # type:ignore[arg-type] + + # (data -> data) + uponData = data.upon(ProtocolForTesting.change) + uponData.to(data2) # type:ignore[arg-type] + + def test_dataFactoryNoArgs(self) -> None: + """ + Inverse of C{test_dataFactoryArgs} where the data factory specifically + does I{not} take arguments, but the input specified does. + """ + builder = TypeMachineBuilder(ArgTaker, NoOpCore) + initial = builder.state("initial") + data = builder.state("data", needsNothing) + ( + initial.upon(ArgTaker.takeSomeArgs) + .to(data) # type:ignore[arg-type] + .returns(None) + ) + + def test_invalidTransition(self) -> None: + """ + Invalid transitions raise a NoTransition exception. + """ + builder = TypeMachineBuilder(ProtocolForTesting, NoOpCore) + builder.state("initial") + factory = builder.build() + machine = factory(NoOpCore()) + with self.assertRaises(NoTransition): + machine.change() + + def test_reentrancy(self) -> None: + """ + During the execution of a transition behavior implementation function, + you may invoke other methods on your state machine. However, the + execution of the behavior of those methods will be deferred until the + current behavior method is done executing. In order to implement that + deferral, we restrict the set of methods that can be invoked to those + that return None. + + @note: it may be possible to implement deferral via Awaitables or + Deferreds later, but we are starting simple. + """ + + class SomeMethods(Protocol): + def start(self) -> None: + "Start the machine." + + def later(self) -> None: + "Do some deferrable work." + + builder = TypeMachineBuilder(SomeMethods, NoOpCore) + + initial = builder.state("initial") + second = builder.state("second") + + order = [] + + @pep614(initial.upon(SomeMethods.start).to(second)) + def startup(methods: SomeMethods, core: NoOpCore) -> None: + order.append("startup") + methods.later() + order.append("startup done") + + @pep614(second.upon(SomeMethods.later).loop()) + def later(methods: SomeMethods, core: NoOpCore) -> None: + order.append("later") + + machineFactory = builder.build() + machine = machineFactory(NoOpCore()) + machine.start() + self.assertEqual(order, ["startup", "startup done", "later"]) + + def test_reentrancyNotNoneError(self) -> None: + class SomeMethods(Protocol): + def start(self) -> None: + "Start the machine." + + def later(self) -> int: + "Do some deferrable work." + + builder = TypeMachineBuilder(SomeMethods, NoOpCore) + + initial = builder.state("initial") + second = builder.state("second") + + order = [] + + @pep614(initial.upon(SomeMethods.start).to(second)) + def startup(methods: SomeMethods, core: NoOpCore) -> None: + order.append("startup") + methods.later() + order.append("startup done") # pragma: no cover + + @pep614(second.upon(SomeMethods.later).loop()) + def later(methods: SomeMethods, core: NoOpCore) -> int: + order.append("later") + return 3 + + machineFactory = builder.build() + machine = machineFactory(NoOpCore()) + with self.assertRaises(RuntimeError): + machine.start() + self.assertEqual(order, ["startup"]) + # We do actually do the state transition, which happens *before* the + # output is generated; TODO: maybe we should have exception handling + # that transitions into an error state that requires explicit recovery? + self.assertEqual(machine.later(), 3) + self.assertEqual(order, ["startup", "later"]) + + def test_buildLock(self) -> None: + """ + ``.build()`` locks the builder so it can no longer be modified. + """ + builder = TypeMachineBuilder(ProtocolForTesting, NoOpCore) + state = builder.state("test-state") + state2 = builder.state("state2") + state3 = builder.state("state3") + upon = state.upon(ProtocolForTesting.change) + to = upon.to(state2) + to2 = upon.to(state3) + to.returns(None) + with self.assertRaises(ValueError) as ve: + to2.returns(None) + with self.assertRaises(AlreadyBuiltError): + to.returns(None) + builder.build() + with self.assertRaises(AlreadyBuiltError): + builder.state("hello") + with self.assertRaises(AlreadyBuiltError): + builder.build() + + def test_methodMembership(self) -> None: + """ + Input methods must be members of their protocol. + """ + builder = TypeMachineBuilder(ProtocolForTesting, NoOpCore) + state = builder.state("test-state") + + def stateful(proto: ProtocolForTesting, core: NoOpCore) -> int: + return 4 # pragma: no cover + + state2 = builder.state("state2", stateful) + + def change(self: ProtocolForTesting) -> None: ... + + def rogue(self: ProtocolForTesting) -> int: + return 3 # pragma: no cover + + with self.assertRaises(ValueError): + state.upon(change) + with self.assertRaises(ValueError) as ve: + state2.upon(change) + with self.assertRaises(ValueError): + state.upon(rogue) + + def test_startInAlternateState(self) -> None: + """ + The state machine can be started in an alternate state. + """ + builder = TypeMachineBuilder(ProtocolForTesting, NoOpCore) + one = builder.state("one") + two = builder.state("two") + + @dataclass + class Three: + proto: ProtocolForTesting + core: NoOpCore + value: int = 0 + + three = builder.state("three", Three) + one.upon(ProtocolForTesting.change).to(two).returns(None) + one.upon(ProtocolForTesting.value).loop().returns(1) + two.upon(ProtocolForTesting.change).to(three).returns(None) + two.upon(ProtocolForTesting.value).loop().returns(2) + + @pep614(three.upon(ProtocolForTesting.value).loop()) + def threevalue(proto: ProtocolForTesting, core: NoOpCore, three: Three) -> int: + return 3 + three.value + + onetwothree = builder.build() + + # confirm positive behavior first, particularly the value of the three + # state's change + normal = onetwothree(NoOpCore()) + self.assertEqual(normal.value(), 1) + normal.change() + self.assertEqual(normal.value(), 2) + normal.change() + self.assertEqual(normal.value(), 3) + + # now try deserializing it in each state + self.assertEqual(onetwothree(NoOpCore()).value(), 1) + self.assertEqual(onetwothree(NoOpCore(), two).value(), 2) + self.assertEqual( + onetwothree( + NoOpCore(), three, lambda proto, core: Three(proto, core, 4) + ).value(), + 7, + ) + + def test_genericData(self) -> None: + """ + Test to cover get_origin in generic assertion. + """ + builder = TypeMachineBuilder(ArgTaker, NoOpCore) + one = builder.state("one") + + def dat( + proto: ArgTaker, core: NoOpCore, arg1: int = 0, arg2: str = "" + ) -> Gen[int]: + return Gen(arg1) + + two = builder.state("two", dat) + one.upon(ArgTaker.takeSomeArgs).to(two).returns(None) + + @pep614(two.upon(ArgTaker.value).loop()) + def val(proto: ArgTaker, core: NoOpCore, data: Gen[int]) -> int: + return data.t + + b = builder.build() + m = b(NoOpCore()) + m.takeSomeArgs(3) + self.assertEqual(m.value(), 3) + + @skipIf(not hasInterface, "zope.interface not installed") + def test_interfaceData(self) -> None: + """ + Test to cover providedBy assertion. + """ + builder = TypeMachineBuilder(ArgTaker, NoOpCore) + one = builder.state("one") + + @implementer(ISomething) + @dataclass + class Something: + val: int + + def something(self) -> int: + return self.val + + def dat( + proto: ArgTaker, core: NoOpCore, arg1: int = 0, arg2: str = "" + ) -> ISomething: + return Something(arg1) # type:ignore[return-value] + + two = builder.state("two", dat) + one.upon(ArgTaker.takeSomeArgs).to(two).returns(None) + + @pep614(two.upon(ArgTaker.value).loop()) + def val(proto: ArgTaker, core: NoOpCore, data: ISomething) -> int: + return data.something() # type:ignore[misc] + + b = builder.build() + m = b(NoOpCore()) + m.takeSomeArgs(3) + self.assertEqual(m.value(), 3) + + def test_noMethodsInAltStateDataFactory(self) -> None: + """ + When the state machine is received by a data factory during + construction, it is in an invalid state. It may be invoked after + construction is complete. + """ + builder = TypeMachineBuilder(ProtocolForTesting, NoOpCore) + + @dataclass + class Data: + value: int + proto: ProtocolForTesting + + start = builder.state("start") + data = builder.state("data", lambda proto, core: Data(3, proto)) + + @pep614(data.upon(ProtocolForTesting.value).loop()) + def getval(proto: ProtocolForTesting, core: NoOpCore, data: Data) -> int: + return data.value + + @pep614(start.upon(ProtocolForTesting.value).loop()) + def minusone(proto: ProtocolForTesting, core: NoOpCore) -> int: + return -1 + + factory = builder.build() + self.assertEqual(factory(NoOpCore()).value(), -1) + + def touchproto(proto: ProtocolForTesting, core: NoOpCore) -> Data: + return Data(proto.value(), proto) + + catchdata = [] + + def notouchproto(proto: ProtocolForTesting, core: NoOpCore) -> Data: + catchdata.append(new := Data(4, proto)) + return new + + with self.assertRaises(NoTransition): + factory(NoOpCore(), data, touchproto) + machine = factory(NoOpCore(), data, notouchproto) + self.assertIs(machine, catchdata[0].proto) + self.assertEqual(machine.value(), 4) diff --git a/psets/9/finance/env/lib/python3.12/site-packages/automat/_test/test_visualize.py b/psets/9/finance/env/lib/python3.12/site-packages/automat/_test/test_visualize.py new file mode 100644 index 0000000..552059c --- /dev/null +++ b/psets/9/finance/env/lib/python3.12/site-packages/automat/_test/test_visualize.py @@ -0,0 +1,478 @@ +from __future__ import annotations + +import functools +import os +import subprocess +from dataclasses import dataclass +from typing import Protocol +from unittest import TestCase, skipIf + +from automat import TypeMachineBuilder, pep614 + +from .._methodical import MethodicalMachine +from .._typed import TypeMachine +from .test_discover import isTwistedInstalled + + +def isGraphvizModuleInstalled(): + """ + Is the graphviz Python module installed? + """ + try: + __import__("graphviz") + except ImportError: + return False + else: + return True + + +def isGraphvizInstalled(): + """ + Are the graphviz tools installed? + """ + r, w = os.pipe() + os.close(w) + try: + return not subprocess.call("dot", stdin=r, shell=True) + finally: + os.close(r) + + +def sampleMachine(): + """ + Create a sample L{MethodicalMachine} with some sample states. + """ + mm = MethodicalMachine() + + class SampleObject(object): + @mm.state(initial=True) + def begin(self): + "initial state" + + @mm.state() + def end(self): + "end state" + + @mm.input() + def go(self): + "sample input" + + @mm.output() + def out(self): + "sample output" + + begin.upon(go, end, [out]) + + so = SampleObject() + so.go() + return mm + + +class Sample(Protocol): + def go(self) -> None: ... +class Core: ... + + +def sampleTypeMachine() -> TypeMachine[Sample, Core]: + """ + Create a sample L{TypeMachine} with some sample states. + """ + builder = TypeMachineBuilder(Sample, Core) + begin = builder.state("begin") + + def buildit(proto: Sample, core: Core) -> int: + return 3 # pragma: no cover + + data = builder.state("data", buildit) + end = builder.state("end") + begin.upon(Sample.go).to(data).returns(None) + data.upon(Sample.go).to(end).returns(None) + + @pep614(end.upon(Sample.go).to(begin)) + def out(sample: Sample, core: Core) -> None: ... + + return builder.build() + + +@skipIf(not isGraphvizModuleInstalled(), "Graphviz module is not installed.") +@skipIf(not isTwistedInstalled(), "Twisted is not installed.") +class ElementMakerTests(TestCase): + """ + L{elementMaker} generates HTML representing the specified element. + """ + + def setUp(self): + from .._visualize import elementMaker + + self.elementMaker = elementMaker + + def test_sortsAttrs(self): + """ + L{elementMaker} orders HTML attributes lexicographically. + """ + expected = r'
' + self.assertEqual(expected, self.elementMaker("div", b="2", a="1", c="3")) + + def test_quotesAttrs(self): + """ + L{elementMaker} quotes HTML attributes according to DOT's quoting rule. + + See U{http://www.graphviz.org/doc/info/lang.html}, footnote 1. + """ + expected = r'
' + self.assertEqual( + expected, self.elementMaker("div", b='a " quote', a=1, c="a string") + ) + + def test_noAttrs(self): + """ + L{elementMaker} should render an element with no attributes. + """ + expected = r"
" + self.assertEqual(expected, self.elementMaker("div")) + + +@dataclass +class HTMLElement(object): + """Holds an HTML element, as created by elementMaker.""" + + name: str + children: list[HTMLElement] + attributes: dict[str, str] + + +def findElements(element, predicate): + """ + Recursively collect all elements in an L{HTMLElement} tree that + match the optional predicate. + """ + if predicate(element): + return [element] + elif isLeaf(element): + return [] + + return [ + result + for child in element.children + for result in findElements(child, predicate) + ] + + +def isLeaf(element): + """ + This HTML element is actually leaf node. + """ + return not isinstance(element, HTMLElement) + + +@skipIf(not isGraphvizModuleInstalled(), "Graphviz module is not installed.") +@skipIf(not isTwistedInstalled(), "Twisted is not installed.") +class TableMakerTests(TestCase): + """ + Tests that ensure L{tableMaker} generates HTML tables usable as + labels in DOT graphs. + + For more information, read the "HTML-Like Labels" section of + U{http://www.graphviz.org/doc/info/shapes.html}. + """ + + def fakeElementMaker(self, name, *children, **attributes): + return HTMLElement(name=name, children=children, attributes=attributes) + + def setUp(self): + from .._visualize import tableMaker + + self.inputLabel = "input label" + self.port = "the port" + self.tableMaker = functools.partial(tableMaker, _E=self.fakeElementMaker) + + def test_inputLabelRow(self): + """ + The table returned by L{tableMaker} always contains the input + symbol label in its first row, and that row contains one cell + with a port attribute set to the provided port. + """ + + def hasPort(element): + return not isLeaf(element) and element.attributes.get("port") == self.port + + for outputLabels in ([], ["an output label"]): + table = self.tableMaker(self.inputLabel, outputLabels, port=self.port) + self.assertGreater(len(table.children), 0) + inputLabelRow = table.children[0] + + portCandidates = findElements(table, hasPort) + + self.assertEqual(len(portCandidates), 1) + self.assertEqual(portCandidates[0].name, "td") + self.assertEqual(findElements(inputLabelRow, isLeaf), [self.inputLabel]) + + def test_noOutputLabels(self): + """ + L{tableMaker} does not add a colspan attribute to the input + label's cell or a second row if there no output labels. + """ + table = self.tableMaker("input label", (), port=self.port) + self.assertEqual(len(table.children), 1) + (inputLabelRow,) = table.children + self.assertNotIn("colspan", inputLabelRow.attributes) + + def test_withOutputLabels(self): + """ + L{tableMaker} adds a colspan attribute to the input label's cell + equal to the number of output labels and a second row that + contains the output labels. + """ + table = self.tableMaker( + self.inputLabel, ("output label 1", "output label 2"), port=self.port + ) + + self.assertEqual(len(table.children), 2) + inputRow, outputRow = table.children + + def hasCorrectColspan(element): + return ( + not isLeaf(element) + and element.name == "td" + and element.attributes.get("colspan") == "2" + ) + + self.assertEqual(len(findElements(inputRow, hasCorrectColspan)), 1) + self.assertEqual( + findElements(outputRow, isLeaf), ["output label 1", "output label 2"] + ) + + +@skipIf(not isGraphvizModuleInstalled(), "Graphviz module is not installed.") +@skipIf(not isGraphvizInstalled(), "Graphviz tools are not installed.") +@skipIf(not isTwistedInstalled(), "Twisted is not installed.") +class IntegrationTests(TestCase): + """ + Tests which make sure Graphviz can understand the output produced by + Automat. + """ + + def test_validGraphviz(self) -> None: + """ + C{graphviz} emits valid graphviz data. + """ + digraph = sampleMachine().asDigraph() + text = "".join(digraph).encode("utf-8") + p = subprocess.Popen("dot", stdin=subprocess.PIPE, stdout=subprocess.PIPE) + out, err = p.communicate(text) + self.assertEqual(p.returncode, 0) + + +@skipIf(not isGraphvizModuleInstalled(), "Graphviz module is not installed.") +@skipIf(not isTwistedInstalled(), "Twisted is not installed.") +class SpotChecks(TestCase): + """ + Tests to make sure that the output contains salient features of the machine + being generated. + """ + + def test_containsMachineFeatures(self): + """ + The output of L{graphviz.Digraph} should contain the names of the + states, inputs, outputs in the state machine. + """ + gvout = "".join(sampleMachine().asDigraph()) + self.assertIn("begin", gvout) + self.assertIn("end", gvout) + self.assertIn("go", gvout) + self.assertIn("out", gvout) + + def test_containsTypeMachineFeatures(self): + """ + The output of L{graphviz.Digraph} should contain the names of the states, + inputs, outputs in the state machine. + """ + gvout = "".join(sampleTypeMachine().asDigraph()) + self.assertIn("begin", gvout) + self.assertIn("end", gvout) + self.assertIn("go", gvout) + self.assertIn("data:buildit", gvout) + self.assertIn("out", gvout) + + +class RecordsDigraphActions(object): + """ + Records calls made to L{FakeDigraph}. + """ + + def __init__(self): + self.reset() + + def reset(self): + self.renderCalls = [] + self.saveCalls = [] + + +class FakeDigraph(object): + """ + A fake L{graphviz.Digraph}. Instantiate it with a + L{RecordsDigraphActions}. + """ + + def __init__(self, recorder): + self._recorder = recorder + + def render(self, **kwargs): + self._recorder.renderCalls.append(kwargs) + + def save(self, **kwargs): + self._recorder.saveCalls.append(kwargs) + + +class FakeMethodicalMachine(object): + """ + A fake L{MethodicalMachine}. Instantiate it with a L{FakeDigraph} + """ + + def __init__(self, digraph): + self._digraph = digraph + + def asDigraph(self): + return self._digraph + + +@skipIf(not isGraphvizModuleInstalled(), "Graphviz module is not installed.") +@skipIf(not isGraphvizInstalled(), "Graphviz tools are not installed.") +@skipIf(not isTwistedInstalled(), "Twisted is not installed.") +class VisualizeToolTests(TestCase): + def setUp(self): + self.digraphRecorder = RecordsDigraphActions() + self.fakeDigraph = FakeDigraph(self.digraphRecorder) + + self.fakeProgname = "tool-test" + self.fakeSysPath = ["ignored"] + self.collectedOutput = [] + self.fakeFQPN = "fake.fqpn" + + def collectPrints(self, *args): + self.collectedOutput.append(" ".join(args)) + + def fakeFindMachines(self, fqpn): + yield fqpn, FakeMethodicalMachine(self.fakeDigraph) + + def tool( + self, progname=None, argv=None, syspath=None, findMachines=None, print=None + ): + from .._visualize import tool + + return tool( + _progname=progname or self.fakeProgname, + _argv=argv or [self.fakeFQPN], + _syspath=syspath or self.fakeSysPath, + _findMachines=findMachines or self.fakeFindMachines, + _print=print or self.collectPrints, + ) + + def test_checksCurrentDirectory(self): + """ + L{tool} adds '' to sys.path to ensure + L{automat._discover.findMachines} searches the current + directory. + """ + self.tool(argv=[self.fakeFQPN]) + self.assertEqual(self.fakeSysPath[0], "") + + def test_quietHidesOutput(self): + """ + Passing -q/--quiet hides all output. + """ + self.tool(argv=[self.fakeFQPN, "--quiet"]) + self.assertFalse(self.collectedOutput) + self.tool(argv=[self.fakeFQPN, "-q"]) + self.assertFalse(self.collectedOutput) + + def test_onlySaveDot(self): + """ + Passing an empty string for --image-directory/-i disables + rendering images. + """ + for arg in ("--image-directory", "-i"): + self.digraphRecorder.reset() + self.collectedOutput = [] + + self.tool(argv=[self.fakeFQPN, arg, ""]) + self.assertFalse(any("image" in line for line in self.collectedOutput)) + + self.assertEqual(len(self.digraphRecorder.saveCalls), 1) + (call,) = self.digraphRecorder.saveCalls + self.assertEqual("{}.dot".format(self.fakeFQPN), call["filename"]) + + self.assertFalse(self.digraphRecorder.renderCalls) + + def test_saveOnlyImage(self): + """ + Passing an empty string for --dot-directory/-d disables saving dot + files. + """ + for arg in ("--dot-directory", "-d"): + self.digraphRecorder.reset() + self.collectedOutput = [] + self.tool(argv=[self.fakeFQPN, arg, ""]) + + self.assertFalse(any("dot" in line for line in self.collectedOutput)) + + self.assertEqual(len(self.digraphRecorder.renderCalls), 1) + (call,) = self.digraphRecorder.renderCalls + self.assertEqual("{}.dot".format(self.fakeFQPN), call["filename"]) + self.assertTrue(call["cleanup"]) + + self.assertFalse(self.digraphRecorder.saveCalls) + + def test_saveDotAndImagesInDifferentDirectories(self): + """ + Passing different directories to --image-directory and --dot-directory + writes images and dot files to those directories. + """ + imageDirectory = "image" + dotDirectory = "dot" + self.tool( + argv=[ + self.fakeFQPN, + "--image-directory", + imageDirectory, + "--dot-directory", + dotDirectory, + ] + ) + + self.assertTrue(any("image" in line for line in self.collectedOutput)) + self.assertTrue(any("dot" in line for line in self.collectedOutput)) + + self.assertEqual(len(self.digraphRecorder.renderCalls), 1) + (renderCall,) = self.digraphRecorder.renderCalls + self.assertEqual(renderCall["directory"], imageDirectory) + self.assertTrue(renderCall["cleanup"]) + + self.assertEqual(len(self.digraphRecorder.saveCalls), 1) + (saveCall,) = self.digraphRecorder.saveCalls + self.assertEqual(saveCall["directory"], dotDirectory) + + def test_saveDotAndImagesInSameDirectory(self): + """ + Passing the same directory to --image-directory and --dot-directory + writes images and dot files to that one directory. + """ + directory = "imagesAndDot" + self.tool( + argv=[ + self.fakeFQPN, + "--image-directory", + directory, + "--dot-directory", + directory, + ] + ) + + self.assertTrue(any("image and dot" in line for line in self.collectedOutput)) + + self.assertEqual(len(self.digraphRecorder.renderCalls), 1) + (renderCall,) = self.digraphRecorder.renderCalls + self.assertEqual(renderCall["directory"], directory) + self.assertFalse(renderCall["cleanup"]) + + self.assertFalse(len(self.digraphRecorder.saveCalls)) diff --git a/psets/9/finance/env/lib/python3.12/site-packages/automat/_typed.py b/psets/9/finance/env/lib/python3.12/site-packages/automat/_typed.py new file mode 100644 index 0000000..c5d9e12 --- /dev/null +++ b/psets/9/finance/env/lib/python3.12/site-packages/automat/_typed.py @@ -0,0 +1,736 @@ +# -*- test-case-name: automat._test.test_type_based -*- +from __future__ import annotations + +import sys +from dataclasses import dataclass, field +from typing import ( + TYPE_CHECKING, + get_origin, + Any, + Callable, + Generic, + Iterable, + Literal, + Protocol, + TypeVar, + overload, +) + +if TYPE_CHECKING: + from graphviz import Digraph +try: + from zope.interface.interface import InterfaceClass # type:ignore[import-untyped] +except ImportError: + hasInterface = False +else: + hasInterface = True + +if sys.version_info < (3, 10): + from typing_extensions import Concatenate, ParamSpec, TypeAlias +else: + from typing import Concatenate, ParamSpec, TypeAlias + +from ._core import Automaton, Transitioner +from ._runtimeproto import ( + ProtocolAtRuntime, + _liveSignature, + actuallyDefinedProtocolMethods, + runtime_name, +) + + +class AlreadyBuiltError(Exception): + """ + The L{TypeMachine} is already built, and thus can no longer be + modified. + """ + + +InputProtocol = TypeVar("InputProtocol") +Core = TypeVar("Core") +Data = TypeVar("Data") +P = ParamSpec("P") +P1 = ParamSpec("P1") +R = TypeVar("R") +OtherData = TypeVar("OtherData") +Decorator = Callable[[Callable[P, R]], Callable[P, R]] +FactoryParams = ParamSpec("FactoryParams") +OtherFactoryParams = ParamSpec("OtherFactoryParams") + + +def pep614(t: R) -> R: + """ + This is a workaround for Python 3.8, which has U{some restrictions on its + grammar for decorators }, and makes + C{@state.to(other).upon(Protocol.input)} invalid syntax; for code that + needs to run on these older Python versions, you can do + C{@pep614(state.to(other).upon(Protocol.input))} instead. + """ + return t + + +@dataclass() +class TransitionRegistrar(Generic[P, P1, R]): + """ + This is a record of a transition that need finalizing; it is the result of + calling L{TypeMachineBuilder.state} and then ``.upon(input).to(state)`` on + the result of that. + + It can be used as a decorator, like:: + + registrar = state.upon(Proto.input).to(state2) + @registrar + def inputImplementation(proto: Proto, core: Core) -> Result: ... + + Or, it can be used used to implement a constant return value with + L{TransitionRegistrar.returns}, like:: + + registrar = state.upon(Proto.input).to(state2) + registrar.returns(value) + + Type parameter P: the precise signature of the decorated implementation + callable. + + Type parameter P1: the precise signature of the input method from the + outward-facing state-machine protocol. + + Type parameter R: the return type of both the protocol method and the input + method. + """ + + _signature: Callable[P1, R] + _old: AnyState + _new: AnyState + _nodata: bool = False + _callback: Callable[P, R] | None = None + + def __post_init__(self) -> None: + self._old.builder._registrars.append(self) + + def __call__(self, impl: Callable[P, R]) -> Callable[P, R]: + """ + Finalize it with C{__call__} to indicate that there is an + implementation to the transition, which can be treated as an output. + """ + if self._callback is not None: + raise AlreadyBuiltError( + f"already registered transition from {self._old.name!r} to {self._new.name!r}" + ) + self._callback = impl + builder = self._old.builder + assert builder is self._new.builder, "states must be from the same builder" + builder._automaton.addTransition( + self._old, + self._signature.__name__, + self._new, + tuple(self._new._produceOutputs(impl, self._old, self._nodata)), + ) + return impl + + def returns(self, result: R) -> None: + """ + Finalize it with C{.returns(constant)} to indicate that there is no + method body, and the given result can just be yielded each time after + the state transition. The only output generated in this case would be + the data-construction factory for the target state. + """ + + def constant(*args: object, **kwargs: object) -> R: + return result + + constant.__name__ = f"returns({result})" + self(constant) + + def _checkComplete(self) -> None: + """ + Raise an exception if the user forgot to decorate a method + implementation or supply a return value for this transition. + """ + # TODO: point at the line where `.to`/`.loop`/`.upon` are called so the + # user can more immediately see the incomplete transition + if not self._callback: + raise ValueError( + f"incomplete transition from {self._old.name} to " + f"{self._new.name} upon {self._signature.__qualname__}: " + "remember to use the transition as a decorator or call " + "`.returns` on it." + ) + + +@dataclass +class UponFromNo(Generic[InputProtocol, Core, P, R]): + """ + Type parameter P: the signature of the input method. + """ + + old: TypedState[InputProtocol, Core] | TypedDataState[InputProtocol, Core, Any, ...] + input: Callable[Concatenate[InputProtocol, P], R] + + @overload + def to( + self, state: TypedState[InputProtocol, Core] + ) -> TransitionRegistrar[Concatenate[InputProtocol, Core, P], P, R]: ... + @overload + def to( + self, + state: TypedDataState[InputProtocol, Core, OtherData, P], + ) -> TransitionRegistrar[ + Concatenate[InputProtocol, Core, P], + Concatenate[InputProtocol, P], + R, + ]: ... + def to( + self, + state: ( + TypedState[InputProtocol, Core] + | TypedDataState[InputProtocol, Core, Any, P] + ), + ) -> ( + TransitionRegistrar[Concatenate[InputProtocol, Core, P], P, R] + | TransitionRegistrar[ + Concatenate[InputProtocol, Core, P], + Concatenate[InputProtocol, P], + R, + ] + ): + """ + Declare a state transition to a new state. + """ + return TransitionRegistrar(self.input, self.old, state, True) + + def loop(self) -> TransitionRegistrar[ + Concatenate[InputProtocol, Core, P], + Concatenate[InputProtocol, P], + R, + ]: + """ + Register a transition back to the same state. + """ + return TransitionRegistrar(self.input, self.old, self.old, True) + + +@dataclass +class UponFromData(Generic[InputProtocol, Core, P, R, Data]): + """ + Type parameter P: the signature of the input method. + """ + + old: TypedDataState[InputProtocol, Core, Data, ...] + input: Callable[Concatenate[InputProtocol, P], R] + + @overload + def to( + self, state: TypedState[InputProtocol, Core] + ) -> TransitionRegistrar[ + Concatenate[InputProtocol, Core, Data, P], Concatenate[InputProtocol, P], R + ]: ... + @overload + def to( + self, + state: TypedDataState[InputProtocol, Core, OtherData, P], + ) -> TransitionRegistrar[ + Concatenate[InputProtocol, Core, Data, P], + Concatenate[InputProtocol, P], + R, + ]: ... + def to( + self, + state: ( + TypedState[InputProtocol, Core] + | TypedDataState[InputProtocol, Core, Any, P] + ), + ) -> ( + TransitionRegistrar[Concatenate[InputProtocol, Core, P], P, R] + | TransitionRegistrar[ + Concatenate[InputProtocol, Core, Data, P], + Concatenate[InputProtocol, P], + R, + ] + ): + """ + Declare a state transition to a new state. + """ + return TransitionRegistrar(self.input, self.old, state) + + def loop(self) -> TransitionRegistrar[ + Concatenate[InputProtocol, Core, Data, P], + Concatenate[InputProtocol, P], + R, + ]: + """ + Register a transition back to the same state. + """ + return TransitionRegistrar(self.input, self.old, self.old) + + +@dataclass(frozen=True) +class TypedState(Generic[InputProtocol, Core]): + """ + The result of L{.state() }. + """ + + name: str + builder: TypeMachineBuilder[InputProtocol, Core] = field(repr=False) + + def upon( + self, input: Callable[Concatenate[InputProtocol, P], R] + ) -> UponFromNo[InputProtocol, Core, P, R]: + ".upon()" + self.builder._checkMembership(input) + return UponFromNo(self, input) + + def _produceOutputs( + self, + impl: Callable[..., object], + old: ( + TypedDataState[InputProtocol, Core, OtherData, OtherFactoryParams] + | TypedState[InputProtocol, Core] + ), + nodata: bool = False, + ) -> Iterable[SomeOutput]: + yield MethodOutput._fromImpl(impl, isinstance(old, TypedDataState)) + + +@dataclass(frozen=True) +class TypedDataState(Generic[InputProtocol, Core, Data, FactoryParams]): + name: str + builder: TypeMachineBuilder[InputProtocol, Core] = field(repr=False) + factory: Callable[Concatenate[InputProtocol, Core, FactoryParams], Data] + + @overload + def upon( + self, input: Callable[Concatenate[InputProtocol, P], R] + ) -> UponFromData[InputProtocol, Core, P, R, Data]: ... + @overload + def upon( + self, input: Callable[Concatenate[InputProtocol, P], R], nodata: Literal[False] + ) -> UponFromData[InputProtocol, Core, P, R, Data]: ... + @overload + def upon( + self, input: Callable[Concatenate[InputProtocol, P], R], nodata: Literal[True] + ) -> UponFromNo[InputProtocol, Core, P, R]: ... + def upon( + self, + input: Callable[Concatenate[InputProtocol, P], R], + nodata: bool = False, + ) -> ( + UponFromData[InputProtocol, Core, P, R, Data] + | UponFromNo[InputProtocol, Core, P, R] + ): + self.builder._checkMembership(input) + if nodata: + return UponFromNo(self, input) + else: + return UponFromData(self, input) + + def _produceOutputs( + self, + impl: Callable[..., object], + old: ( + TypedDataState[InputProtocol, Core, OtherData, OtherFactoryParams] + | TypedState[InputProtocol, Core] + ), + nodata: bool, + ) -> Iterable[SomeOutput]: + if self is not old: + yield DataOutput(self.factory) + yield MethodOutput._fromImpl( + impl, isinstance(old, TypedDataState) and not nodata + ) + + +AnyState: TypeAlias = "TypedState[Any, Any] | TypedDataState[Any, Any, Any, Any]" + + +@dataclass +class TypedInput: + name: str + + +class SomeOutput(Protocol): + """ + A state machine output. + """ + + @property + def name(self) -> str: + "read-only name property" + + def __call__(*args: Any, **kwargs: Any) -> Any: ... + + def __hash__(self) -> int: + "must be hashable" + + +@dataclass +class InputImplementer(Generic[InputProtocol, Core]): + """ + An L{InputImplementer} implements an input protocol in terms of a + state machine. + + When the factory returned from L{TypeMachine} + """ + + __automat_core__: Core + __automat_transitioner__: Transitioner[ + TypedState[InputProtocol, Core] + | TypedDataState[InputProtocol, Core, object, ...], + str, + SomeOutput, + ] + __automat_data__: object | None = None + __automat_postponed__: list[Callable[[], None]] | None = None + + +def implementMethod( + method: Callable[..., object], +) -> Callable[..., object]: + """ + Construct a function for populating in the synthetic provider of the Input + Protocol to a L{TypeMachineBuilder}. It should have a signature matching that + of the C{method} parameter, a function from that protocol. + """ + methodInput = method.__name__ + # side-effects can be re-ordered until later. If you need to compute a + # value in your method, then obviously it can't be invoked reentrantly. + returnAnnotation = _liveSignature(method).return_annotation + returnsNone = returnAnnotation is None + + def implementation( + self: InputImplementer[InputProtocol, Core], *args: object, **kwargs: object + ) -> object: + transitioner = self.__automat_transitioner__ + dataAtStart = self.__automat_data__ + if self.__automat_postponed__ is not None: + if not returnsNone: + raise RuntimeError( + f"attempting to reentrantly run {method.__qualname__} " + f"but it wants to return {returnAnnotation!r} not None" + ) + + def rerunme() -> None: + implementation(self, *args, **kwargs) + + self.__automat_postponed__.append(rerunme) + return None + postponed = self.__automat_postponed__ = [] + try: + [outputs, tracer] = transitioner.transition(methodInput) + result: Any = None + for output in outputs: + # here's the idea: there will be a state-setup output and a + # state-teardown output. state-setup outputs are added to the + # *beginning* of any entry into a state, so that by the time you + # are running the *implementation* of a method that has entered + # that state, the protocol is in a self-consistent state and can + # run reentrant outputs. not clear that state-teardown outputs are + # necessary + result = output(self, dataAtStart, *args, **kwargs) + finally: + self.__automat_postponed__ = None + while postponed: + postponed.pop(0)() + return result + + implementation.__qualname__ = implementation.__name__ = ( + f"" + ) + return implementation + + +@dataclass(frozen=True) +class MethodOutput(Generic[Core]): + """ + This is the thing that goes into the automaton's outputs list, and thus + (per the implementation of L{implementMethod}) takes the 'self' of the + InputImplementer instance (i.e. the synthetic protocol implementation) and the + previous result computed by the former output, which will be None + initially. + """ + + method: Callable[..., Any] + requiresData: bool + _assertion: Callable[[object], None] + + @classmethod + def _fromImpl( + cls: type[MethodOutput[Core]], method: Callable[..., Any], requiresData: bool + ) -> MethodOutput[Core]: + parameter = None + annotation: type[object] = object + + def assertion(data: object) -> None: + """ + No assertion about the data. + """ + + # Do our best to compute the declared signature, so that we caan verify + # it's the right type. We can't always do that. + try: + sig = _liveSignature(method) + except NameError: + ... + # An inner function may refer to type aliases that only appear as + # local variables, and those are just lost here; give up. + else: + if requiresData: + # 0: self, 1: self.__automat_core__, 2: self.__automat_data__ + declaredParams = list(sig.parameters.values()) + if len(declaredParams) >= 3: + parameter = declaredParams[2] + annotation = parameter.annotation + origin = get_origin(annotation) + if origin is not None: + annotation = origin + if hasInterface and isinstance(annotation, InterfaceClass): + + def assertion(data: object) -> None: + assert annotation.providedBy(data), ( + f"expected {parameter} to provide {annotation} " + f"but got {type(data)} instead" + ) + + else: + + def assertion(data: object) -> None: + assert isinstance(data, annotation), ( + f"expected {parameter} to be {annotation} " + f"but got {type(data)} instead" + ) + + return cls(method, requiresData, assertion) + + @property + def name(self) -> str: + return f"{self.method.__name__}" + + def __call__( + self, + machine: InputImplementer[InputProtocol, Core], + dataAtStart: Data, + /, + *args: object, + **kwargs: object, + ) -> object: + extraArgs = [machine, machine.__automat_core__] + if self.requiresData: + self._assertion(dataAtStart) + extraArgs += [dataAtStart] + # if anything is invoked reentrantly here, then we can't possibly have + # set __automat_data__ and the data argument to the reentrant method + # will be wrong. we *need* to split out the construction / state-enter + # hook, because it needs to run separately. + return self.method(*extraArgs, *args, **kwargs) + + +@dataclass(frozen=True) +class DataOutput(Generic[Data]): + """ + Construct an output for the given data objects. + """ + + dataFactory: Callable[..., Data] + + @property + def name(self) -> str: + return f"data:{self.dataFactory.__name__}" + + def __call__( + realself, + self: InputImplementer[InputProtocol, Core], + dataAtStart: object, + *args: object, + **kwargs: object, + ) -> Data: + newData = realself.dataFactory(self, self.__automat_core__, *args, **kwargs) + self.__automat_data__ = newData + return newData + + +INVALID_WHILE_DESERIALIZING: TypedState[Any, Any] = TypedState( + "automat:invalid-while-deserializing", + None, # type:ignore[arg-type] +) + + +@dataclass(frozen=True) +class TypeMachine(Generic[InputProtocol, Core]): + """ + A L{TypeMachine} is a factory for instances of C{InputProtocol}. + """ + + __automat_type__: type[InputImplementer[InputProtocol, Core]] + __automat_automaton__: Automaton[ + TypedState[InputProtocol, Core] | TypedDataState[InputProtocol, Core, Any, ...], + str, + SomeOutput, + ] + + @overload + def __call__(self, core: Core) -> InputProtocol: ... + @overload + def __call__( + self, core: Core, state: TypedState[InputProtocol, Core] + ) -> InputProtocol: ... + @overload + def __call__( + self, + core: Core, + state: TypedDataState[InputProtocol, Core, OtherData, ...], + dataFactory: Callable[[InputProtocol, Core], OtherData], + ) -> InputProtocol: ... + + def __call__( + self, + core: Core, + state: ( + TypedState[InputProtocol, Core] + | TypedDataState[InputProtocol, Core, OtherData, ...] + | None + ) = None, + dataFactory: Callable[[InputProtocol, Core], OtherData] | None = None, + ) -> InputProtocol: + """ + Construct an instance of C{InputProtocol} from an instance of the + C{Core} protocol. + """ + if state is None: + state = initial = self.__automat_automaton__.initialState + elif isinstance(state, TypedDataState): + assert dataFactory is not None, "data state requires a data factory" + # Ensure that the machine is in a state with *no* transitions while + # we are doing the initial construction of its state-specific data. + initial = INVALID_WHILE_DESERIALIZING + else: + initial = state + + internals: InputImplementer[InputProtocol, Core] = self.__automat_type__( + core, txnr := Transitioner(self.__automat_automaton__, initial) + ) + result: InputProtocol = internals # type:ignore[assignment] + + if dataFactory is not None: + internals.__automat_data__ = dataFactory(result, core) + txnr._state = state + return result + + def asDigraph(self) -> Digraph: + from ._visualize import makeDigraph + + return makeDigraph( + self.__automat_automaton__, + stateAsString=lambda state: state.name, + inputAsString=lambda input: input, + outputAsString=lambda output: output.name, + ) + + +@dataclass(eq=False) +class TypeMachineBuilder(Generic[InputProtocol, Core]): + """ + The main entry-point into Automat, used to construct a factory for + instances of C{InputProtocol} that take an instance of C{Core}. + + Describe the machine with L{TypeMachineBuilder.state} L{.upon + } L{.to + }, then build it with + L{TypeMachineBuilder.build}, like so:: + + from typing import Protocol + class Inputs(Protocol): + def method(self) -> None: ... + class Core: ... + + from automat import TypeMachineBuilder + builder = TypeMachineBuilder(Inputs, Core) + state = builder.state("state") + state.upon(Inputs.method).loop().returns(None) + Machine = builder.build() + + machine = Machine(Core()) + machine.method() + """ + + # Public constructor parameters. + inputProtocol: ProtocolAtRuntime[InputProtocol] + coreType: type[Core] + + # Internal state, not in the constructor. + _automaton: Automaton[ + TypedState[InputProtocol, Core] | TypedDataState[InputProtocol, Core, Any, ...], + str, + SomeOutput, + ] = field(default_factory=Automaton, repr=False, init=False) + _initial: bool = field(default=True, init=False) + _registrars: list[TransitionRegistrar[..., ..., Any]] = field( + default_factory=list, init=False + ) + _built: bool = field(default=False, init=False) + + @overload + def state(self, name: str) -> TypedState[InputProtocol, Core]: ... + @overload + def state( + self, + name: str, + dataFactory: Callable[Concatenate[InputProtocol, Core, P], Data], + ) -> TypedDataState[InputProtocol, Core, Data, P]: ... + def state( + self, + name: str, + dataFactory: Callable[Concatenate[InputProtocol, Core, P], Data] | None = None, + ) -> TypedState[InputProtocol, Core] | TypedDataState[InputProtocol, Core, Data, P]: + """ + Construct a state. + """ + if self._built: + raise AlreadyBuiltError( + "Cannot add states to an already-built state machine." + ) + if dataFactory is None: + state = TypedState(name, self) + if self._initial: + self._initial = False + self._automaton.initialState = state + return state + else: + assert not self._initial, "initial state cannot require state-specific data" + return TypedDataState(name, self, dataFactory) + + def build(self) -> TypeMachine[InputProtocol, Core]: + """ + Create a L{TypeMachine}, and prevent further modification to the state + machine being built. + """ + # incompleteness check + if self._built: + raise AlreadyBuiltError("Cannot build a state machine twice.") + self._built = True + + for registrar in self._registrars: + registrar._checkComplete() + + # We were only hanging on to these for error-checking purposes, so we + # can drop them now. + del self._registrars[:] + + runtimeType: type[InputImplementer[InputProtocol, Core]] = type( + f"Typed<{runtime_name(self.inputProtocol)}>", + tuple([InputImplementer]), + { + method_name: implementMethod(getattr(self.inputProtocol, method_name)) + for method_name in actuallyDefinedProtocolMethods(self.inputProtocol) + }, + ) + + return TypeMachine(runtimeType, self._automaton) + + def _checkMembership(self, input: Callable[..., object]) -> None: + """ + Ensure that ``input`` is a valid member function of the input protocol, + not just a function that happens to take the right first argument. + """ + if (checked := getattr(self.inputProtocol, input.__name__, None)) is not input: + raise ValueError( + f"{input.__qualname__} is not a member of {self.inputProtocol.__module__}.{self.inputProtocol.__name__}" + ) diff --git a/psets/9/finance/env/lib/python3.12/site-packages/automat/_visualize.py b/psets/9/finance/env/lib/python3.12/site-packages/automat/_visualize.py new file mode 100644 index 0000000..a2b35e5 --- /dev/null +++ b/psets/9/finance/env/lib/python3.12/site-packages/automat/_visualize.py @@ -0,0 +1,230 @@ +from __future__ import annotations + +import argparse +import sys +from functools import wraps +from typing import Callable, Iterator + +import graphviz + +from ._core import Automaton, Input, Output, State +from ._discover import findMachines +from ._methodical import MethodicalMachine +from ._typed import TypeMachine, InputProtocol, Core + + +def _gvquote(s: str) -> str: + return '"{}"'.format(s.replace('"', r"\"")) + + +def _gvhtml(s: str) -> str: + return "<{}>".format(s) + + +def elementMaker(name: str, *children: str, **attrs: str) -> str: + """ + Construct a string from the HTML element description. + """ + formattedAttrs = " ".join( + "{}={}".format(key, _gvquote(str(value))) + for key, value in sorted(attrs.items()) + ) + formattedChildren = "".join(children) + return "<{name} {attrs}>{children}".format( + name=name, attrs=formattedAttrs, children=formattedChildren + ) + + +def tableMaker( + inputLabel: str, + outputLabels: list[str], + port: str, + _E: Callable[..., str] = elementMaker, +) -> str: + """ + Construct an HTML table to label a state transition. + """ + colspan = {} + if outputLabels: + colspan["colspan"] = str(len(outputLabels)) + + inputLabelCell = _E( + "td", + _E("font", inputLabel, face="menlo-italic"), + color="purple", + port=port, + **colspan, + ) + + pointSize = {"point-size": "9"} + outputLabelCells = [ + _E("td", _E("font", outputLabel, **pointSize), color="pink") + for outputLabel in outputLabels + ] + + rows = [_E("tr", inputLabelCell)] + + if outputLabels: + rows.append(_E("tr", *outputLabelCells)) + + return _E("table", *rows) + + +def escapify(x: Callable[[State], str]) -> Callable[[State], str]: + @wraps(x) + def impl(t: State) -> str: + return x(t).replace("<", "<").replace(">", ">") + + return impl + + +def makeDigraph( + automaton: Automaton[State, Input, Output], + inputAsString: Callable[[Input], str] = repr, + outputAsString: Callable[[Output], str] = repr, + stateAsString: Callable[[State], str] = repr, +) -> graphviz.Digraph: + """ + Produce a L{graphviz.Digraph} object from an automaton. + """ + + inputAsString = escapify(inputAsString) + outputAsString = escapify(outputAsString) + stateAsString = escapify(stateAsString) + + digraph = graphviz.Digraph( + graph_attr={"pack": "true", "dpi": "100"}, + node_attr={"fontname": "Menlo"}, + edge_attr={"fontname": "Menlo"}, + ) + + for state in automaton.states(): + if state is automaton.initialState: + stateShape = "bold" + fontName = "Menlo-Bold" + else: + stateShape = "" + fontName = "Menlo" + digraph.node( + stateAsString(state), + fontame=fontName, + shape="ellipse", + style=stateShape, + color="blue", + ) + for n, eachTransition in enumerate(automaton.allTransitions()): + inState, inputSymbol, outState, outputSymbols = eachTransition + thisTransition = "t{}".format(n) + inputLabel = inputAsString(inputSymbol) + + port = "tableport" + table = tableMaker( + inputLabel, + [outputAsString(outputSymbol) for outputSymbol in outputSymbols], + port=port, + ) + + digraph.node(thisTransition, label=_gvhtml(table), margin="0.2", shape="none") + + digraph.edge( + stateAsString(inState), + "{}:{}:w".format(thisTransition, port), + arrowhead="none", + ) + digraph.edge("{}:{}:e".format(thisTransition, port), stateAsString(outState)) + + return digraph + + +def tool( + _progname: str = sys.argv[0], + _argv: list[str] = sys.argv[1:], + _syspath: list[str] = sys.path, + _findMachines: Callable[ + [str], + Iterator[tuple[str, MethodicalMachine | TypeMachine[InputProtocol, Core]]], + ] = findMachines, + _print: Callable[..., None] = print, +) -> None: + """ + Entry point for command line utility. + """ + + DESCRIPTION = """ + Visualize automat.MethodicalMachines as graphviz graphs. + """ + EPILOG = """ + You must have the graphviz tool suite installed. Please visit + http://www.graphviz.org for more information. + """ + if _syspath[0]: + _syspath.insert(0, "") + argumentParser = argparse.ArgumentParser( + prog=_progname, description=DESCRIPTION, epilog=EPILOG + ) + argumentParser.add_argument( + "fqpn", + help="A Fully Qualified Path name" " representing where to find machines.", + ) + argumentParser.add_argument( + "--quiet", "-q", help="suppress output", default=False, action="store_true" + ) + argumentParser.add_argument( + "--dot-directory", + "-d", + help="Where to write out .dot files.", + default=".automat_visualize", + ) + argumentParser.add_argument( + "--image-directory", + "-i", + help="Where to write out image files.", + default=".automat_visualize", + ) + argumentParser.add_argument( + "--image-type", + "-t", + help="The image format.", + choices=graphviz.FORMATS, + default="png", + ) + argumentParser.add_argument( + "--view", + "-v", + help="View rendered graphs with" " default image viewer", + default=False, + action="store_true", + ) + args = argumentParser.parse_args(_argv) + + explicitlySaveDot = args.dot_directory and ( + not args.image_directory or args.image_directory != args.dot_directory + ) + if args.quiet: + + def _print(*args): + pass + + for fqpn, machine in _findMachines(args.fqpn): + _print(fqpn, "...discovered") + + digraph = machine.asDigraph() + + if explicitlySaveDot: + digraph.save(filename="{}.dot".format(fqpn), directory=args.dot_directory) + _print(fqpn, "...wrote dot into", args.dot_directory) + + if args.image_directory: + deleteDot = not args.dot_directory or explicitlySaveDot + digraph.format = args.image_type + digraph.render( + filename="{}.dot".format(fqpn), + directory=args.image_directory, + view=args.view, + cleanup=deleteDot, + ) + if deleteDot: + msg = "...wrote image into" + else: + msg = "...wrote image and dot into" + _print(fqpn, msg, args.image_directory) diff --git a/psets/9/finance/env/lib/python3.12/site-packages/automat/py.typed b/psets/9/finance/env/lib/python3.12/site-packages/automat/py.typed new file mode 100644 index 0000000..e69de29 diff --git a/psets/9/finance/env/lib/python3.12/site-packages/blinker-1.9.0.dist-info/INSTALLER b/psets/9/finance/env/lib/python3.12/site-packages/blinker-1.9.0.dist-info/INSTALLER new file mode 100644 index 0000000..a1b589e --- /dev/null +++ b/psets/9/finance/env/lib/python3.12/site-packages/blinker-1.9.0.dist-info/INSTALLER @@ -0,0 +1 @@ +pip diff --git a/psets/9/finance/env/lib/python3.12/site-packages/blinker-1.9.0.dist-info/LICENSE.txt b/psets/9/finance/env/lib/python3.12/site-packages/blinker-1.9.0.dist-info/LICENSE.txt new file mode 100644 index 0000000..79c9825 --- /dev/null +++ b/psets/9/finance/env/lib/python3.12/site-packages/blinker-1.9.0.dist-info/LICENSE.txt @@ -0,0 +1,20 @@ +Copyright 2010 Jason Kirtland + +Permission is hereby granted, free of charge, to any person obtaining a +copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be included +in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS +OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, +TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. diff --git a/psets/9/finance/env/lib/python3.12/site-packages/blinker-1.9.0.dist-info/METADATA b/psets/9/finance/env/lib/python3.12/site-packages/blinker-1.9.0.dist-info/METADATA new file mode 100644 index 0000000..6d343f5 --- /dev/null +++ b/psets/9/finance/env/lib/python3.12/site-packages/blinker-1.9.0.dist-info/METADATA @@ -0,0 +1,60 @@ +Metadata-Version: 2.3 +Name: blinker +Version: 1.9.0 +Summary: Fast, simple object-to-object and broadcast signaling +Author: Jason Kirtland +Maintainer-email: Pallets Ecosystem +Requires-Python: >=3.9 +Description-Content-Type: text/markdown +Classifier: Development Status :: 5 - Production/Stable +Classifier: License :: OSI Approved :: MIT License +Classifier: Programming Language :: Python +Classifier: Typing :: Typed +Project-URL: Chat, https://discord.gg/pallets +Project-URL: Documentation, https://blinker.readthedocs.io +Project-URL: Source, https://github.com/pallets-eco/blinker/ + +# Blinker + +Blinker provides a fast dispatching system that allows any number of +interested parties to subscribe to events, or "signals". + + +## Pallets Community Ecosystem + +> [!IMPORTANT]\ +> This project is part of the Pallets Community Ecosystem. Pallets is the open +> source organization that maintains Flask; Pallets-Eco enables community +> maintenance of related projects. If you are interested in helping maintain +> this project, please reach out on [the Pallets Discord server][discord]. +> +> [discord]: https://discord.gg/pallets + + +## Example + +Signal receivers can subscribe to specific senders or receive signals +sent by any sender. + +```pycon +>>> from blinker import signal +>>> started = signal('round-started') +>>> def each(round): +... print(f"Round {round}") +... +>>> started.connect(each) + +>>> def round_two(round): +... print("This is round two.") +... +>>> started.connect(round_two, sender=2) + +>>> for round in range(1, 4): +... started.send(round) +... +Round 1! +Round 2! +This is round two. +Round 3! +``` + diff --git a/psets/9/finance/env/lib/python3.12/site-packages/blinker-1.9.0.dist-info/RECORD b/psets/9/finance/env/lib/python3.12/site-packages/blinker-1.9.0.dist-info/RECORD new file mode 100644 index 0000000..d4f985b --- /dev/null +++ b/psets/9/finance/env/lib/python3.12/site-packages/blinker-1.9.0.dist-info/RECORD @@ -0,0 +1,12 @@ +blinker-1.9.0.dist-info/INSTALLER,sha256=zuuue4knoyJ-UwPPXg8fezS7VCrXJQrAP7zeNuwvFQg,4 +blinker-1.9.0.dist-info/LICENSE.txt,sha256=nrc6HzhZekqhcCXSrhvjg5Ykx5XphdTw6Xac4p-spGc,1054 +blinker-1.9.0.dist-info/METADATA,sha256=uIRiM8wjjbHkCtbCyTvctU37IAZk0kEe5kxAld1dvzA,1633 +blinker-1.9.0.dist-info/RECORD,, +blinker-1.9.0.dist-info/WHEEL,sha256=CpUCUxeHQbRN5UGRQHYRJorO5Af-Qy_fHMctcQ8DSGI,82 +blinker/__init__.py,sha256=I2EdZqpy4LyjX17Hn1yzJGWCjeLaVaPzsMgHkLfj_cQ,317 +blinker/__pycache__/__init__.cpython-312.pyc,, +blinker/__pycache__/_utilities.cpython-312.pyc,, +blinker/__pycache__/base.cpython-312.pyc,, +blinker/_utilities.py,sha256=0J7eeXXTUx0Ivf8asfpx0ycVkp0Eqfqnj117x2mYX9E,1675 +blinker/base.py,sha256=QpDuvXXcwJF49lUBcH5BiST46Rz9wSG7VW_p7N_027M,19132 +blinker/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0 diff --git a/psets/9/finance/env/lib/python3.12/site-packages/blinker-1.9.0.dist-info/WHEEL b/psets/9/finance/env/lib/python3.12/site-packages/blinker-1.9.0.dist-info/WHEEL new file mode 100644 index 0000000..e3c6fee --- /dev/null +++ b/psets/9/finance/env/lib/python3.12/site-packages/blinker-1.9.0.dist-info/WHEEL @@ -0,0 +1,4 @@ +Wheel-Version: 1.0 +Generator: flit 3.10.1 +Root-Is-Purelib: true +Tag: py3-none-any diff --git a/psets/9/finance/env/lib/python3.12/site-packages/blinker/__init__.py b/psets/9/finance/env/lib/python3.12/site-packages/blinker/__init__.py new file mode 100644 index 0000000..1772fa4 --- /dev/null +++ b/psets/9/finance/env/lib/python3.12/site-packages/blinker/__init__.py @@ -0,0 +1,17 @@ +from __future__ import annotations + +from .base import ANY +from .base import default_namespace +from .base import NamedSignal +from .base import Namespace +from .base import Signal +from .base import signal + +__all__ = [ + "ANY", + "default_namespace", + "NamedSignal", + "Namespace", + "Signal", + "signal", +] diff --git a/psets/9/finance/env/lib/python3.12/site-packages/blinker/__pycache__/__init__.cpython-312.pyc b/psets/9/finance/env/lib/python3.12/site-packages/blinker/__pycache__/__init__.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..ccfc8c5a3edd32d4c3fc19f64a952e34b22579af GIT binary patch literal 500 zcmaKoy-EZz5XUFCd%Jsgh*$`MSg6$%8b7cQR1mDMv2rb9?vh)B+3c~&2?sVlg}t3G zV&fYuY$X=giFQ^_R&abt8fP7vdJb(Z}G~^^D z1Vl>&x|IiM&~S(xreVWvyxU- zjVT;=sxWqrZ}PF=bZ~*&l8|FQ)s7jSOFQ8s>GKEZh;x-0uF>sy_xCLN3rF@RAu8K= zWf^&iy(C^bUi>5m{chD|Y&><-QZiNs7^}h|xAOnGDrSsp&DaxsVhMa*(%d+D#+@{D zR0w4U*05H?Y7Hy6KEk-yx{u36%=!kA Ck$t=X literal 0 HcmV?d00001 diff --git a/psets/9/finance/env/lib/python3.12/site-packages/blinker/__pycache__/_utilities.cpython-312.pyc b/psets/9/finance/env/lib/python3.12/site-packages/blinker/__pycache__/_utilities.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..8b066d29e5e7830b472be5895e3ca8b7237aa1df GIT binary patch literal 2727 zcmb6b-)j^{c;BzD5ziqZPJ!r8aA8VxwvL;?>aN5 z-f=A{wRl0S@u4ISKD1CMV*d_b`jQZ#vMLm6ANr<5QTo(xX7A#~YM}%B%{Slo&FnYd z&-t~hD}i9#YJ4_xIfl?5V$mLIh~TyF09iy1a5STH<%<18@_83YVb3bZ%j>hrbLM%=k z!?rw+8IeHR5yO>d*(8^cv?E837~!9W_7%(JeObe08wpZuoL0j#{v|Kj zuv5gSnA6^UUSsjf!Q@S~G;@r#;u7B{XkVx$C*y zB`jB|(JuH;JstWh*V1e|(Aawbp3R{<$;`sR#Y5K)tt1ET^llZ{5?|@vyPVqlAl*AZ zGhbe^SJQi%%ALMlP33BGKDlswMc;8J)6-0>!4YVKV}voKV|oAy-C_zMIckU|0l9%` z2BvHzP#N)xa>2w#!=PeYpqr-ayWBMEnRUHGf&pwMYz=yE-riKN#Az?A?3TX(g`j{> zs_+^hpu$VzVk}gJZUGt4M-&DoHa^#Yk_z3RK}Z-Bk|_Y7L8kX=ZN9dwZ~qS^`atwm zN)&OY8dSt%rxIz?oFN=S$)Yn5G4(C$#^@x!E_S6ug}OH{#;?Vjjb(kOR4J=U;|2<( zR1gbOo9ZCjV$goT=>UL09WDDL8<7i1ZsGM!yjt&VGqh3m^-oDwSQI3KT%`R-nDKV-LVz}@DxCwG>F{0 zAzGqvhK!b5fGi@u9!Y1{>jE%Z<9TJE`?=UD2SgY&uNOzVhHQ`%wtr!?<%&>CxJVB< z8iZC{}&&yTC+#iy(1XyNAfw3KZAp;NEVyRcFL&C2N+Lu0wOc*e{qL0+>UOb);v0 z)3&W>+m@8uTHoUs>h4(>TpYeOyqekdQ_l~_em?!<>DApM%bAg7edK|*X<_iXa(!%} zep}n~5QKZ13D}cLH|@)B&y9xZ+UZ|Wj1|#OJ_qD~L_w<40}b5v4tPd`gXCyHZ+cFb z1rV}tAMogq0K$b-{2vld*dx$IBc6t$zOg1s)4=nBj)2f%_?R%z9J;5aJ1lcAvtwy+ z>B4GeXjvb6kW4q(!pYTS|FYWOE(r1;vG4^Tv%Q|Mb0;l!MubYJUQ8-NMNrcN0P4H# z+%Zr}NK8zC4in>(lf#Cn7?Var&f!T=VgxVSEy_Z%3NHyL3lt2Cf{b1EJct(YQp#D= zcAyA=ZE1-h#%mR5d;#Wxb{^hN;-11L(mH`QUaJsz9)uc+9FhSdEpY>di5)hM!(lBt zLWO}uDzkS1JXA2o_tBm|(ayUleHZoIN89eBf#21xxucg(eSNBFe=|CVpT>6LzDEea Q+TjfDeX>`@1M=*D0N5vA{Qv*} literal 0 HcmV?d00001 diff --git a/psets/9/finance/env/lib/python3.12/site-packages/blinker/__pycache__/base.cpython-312.pyc b/psets/9/finance/env/lib/python3.12/site-packages/blinker/__pycache__/base.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..b17e2ee67c9a0670760a0ca48ee89b2d627ee1b3 GIT binary patch literal 21970 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 z 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 literal 0 HcmV?d00001 diff --git a/psets/9/finance/env/lib/python3.12/site-packages/blinker/_utilities.py b/psets/9/finance/env/lib/python3.12/site-packages/blinker/_utilities.py new file mode 100644 index 0000000..000c902 --- /dev/null +++ b/psets/9/finance/env/lib/python3.12/site-packages/blinker/_utilities.py @@ -0,0 +1,64 @@ +from __future__ import annotations + +import collections.abc as c +import inspect +import typing as t +from weakref import ref +from weakref import WeakMethod + +T = t.TypeVar("T") + + +class Symbol: + """A constant symbol, nicer than ``object()``. Repeated calls return the + same instance. + + >>> Symbol('foo') is Symbol('foo') + True + >>> Symbol('foo') + foo + """ + + symbols: t.ClassVar[dict[str, Symbol]] = {} + + def __new__(cls, name: str) -> Symbol: + if name in cls.symbols: + return cls.symbols[name] + + obj = super().__new__(cls) + cls.symbols[name] = obj + return obj + + def __init__(self, name: str) -> None: + self.name = name + + def __repr__(self) -> str: + return self.name + + def __getnewargs__(self) -> tuple[t.Any, ...]: + return (self.name,) + + +def make_id(obj: object) -> c.Hashable: + """Get a stable identifier for a receiver or sender, to be used as a dict + key or in a set. + """ + if inspect.ismethod(obj): + # The id of a bound method is not stable, but the id of the unbound + # function and instance are. + return id(obj.__func__), id(obj.__self__) + + if isinstance(obj, (str, int)): + # Instances with the same value always compare equal and have the same + # hash, even if the id may change. + return obj + + # Assume other types are not hashable but will always be the same instance. + return id(obj) + + +def make_ref(obj: T, callback: c.Callable[[ref[T]], None] | None = None) -> ref[T]: + if inspect.ismethod(obj): + return WeakMethod(obj, callback) # type: ignore[arg-type, return-value] + + return ref(obj, callback) diff --git a/psets/9/finance/env/lib/python3.12/site-packages/blinker/base.py b/psets/9/finance/env/lib/python3.12/site-packages/blinker/base.py new file mode 100644 index 0000000..d051b94 --- /dev/null +++ b/psets/9/finance/env/lib/python3.12/site-packages/blinker/base.py @@ -0,0 +1,512 @@ +from __future__ import annotations + +import collections.abc as c +import sys +import typing as t +import weakref +from collections import defaultdict +from contextlib import contextmanager +from functools import cached_property +from inspect import iscoroutinefunction + +from ._utilities import make_id +from ._utilities import make_ref +from ._utilities import Symbol + +F = t.TypeVar("F", bound=c.Callable[..., t.Any]) + +ANY = Symbol("ANY") +"""Symbol for "any sender".""" + +ANY_ID = 0 + + +class Signal: + """A notification emitter. + + :param doc: The docstring for the signal. + """ + + ANY = ANY + """An alias for the :data:`~blinker.ANY` sender symbol.""" + + set_class: type[set[t.Any]] = set + """The set class to use for tracking connected receivers and senders. + Python's ``set`` is unordered. If receivers must be dispatched in the order + they were connected, an ordered set implementation can be used. + + .. versionadded:: 1.7 + """ + + @cached_property + def receiver_connected(self) -> Signal: + """Emitted at the end of each :meth:`connect` call. + + The signal sender is the signal instance, and the :meth:`connect` + arguments are passed through: ``receiver``, ``sender``, and ``weak``. + + .. versionadded:: 1.2 + """ + return Signal(doc="Emitted after a receiver connects.") + + @cached_property + def receiver_disconnected(self) -> Signal: + """Emitted at the end of each :meth:`disconnect` call. + + The sender is the signal instance, and the :meth:`disconnect` arguments + are passed through: ``receiver`` and ``sender``. + + This signal is emitted **only** when :meth:`disconnect` is called + explicitly. This signal cannot be emitted by an automatic disconnect + when a weakly referenced receiver or sender goes out of scope, as the + instance is no longer be available to be used as the sender for this + signal. + + An alternative approach is available by subscribing to + :attr:`receiver_connected` and setting up a custom weakref cleanup + callback on weak receivers and senders. + + .. versionadded:: 1.2 + """ + return Signal(doc="Emitted after a receiver disconnects.") + + def __init__(self, doc: str | None = None) -> None: + if doc: + self.__doc__ = doc + + self.receivers: dict[ + t.Any, weakref.ref[c.Callable[..., t.Any]] | c.Callable[..., t.Any] + ] = {} + """The map of connected receivers. Useful to quickly check if any + receivers are connected to the signal: ``if s.receivers:``. The + structure and data is not part of the public API, but checking its + boolean value is. + """ + + self.is_muted: bool = False + self._by_receiver: dict[t.Any, set[t.Any]] = defaultdict(self.set_class) + self._by_sender: dict[t.Any, set[t.Any]] = defaultdict(self.set_class) + self._weak_senders: dict[t.Any, weakref.ref[t.Any]] = {} + + def connect(self, receiver: F, sender: t.Any = ANY, weak: bool = True) -> F: + """Connect ``receiver`` to be called when the signal is sent by + ``sender``. + + :param receiver: The callable to call when :meth:`send` is called with + the given ``sender``, passing ``sender`` as a positional argument + along with any extra keyword arguments. + :param sender: Any object or :data:`ANY`. ``receiver`` will only be + called when :meth:`send` is called with this sender. If ``ANY``, the + receiver will be called for any sender. A receiver may be connected + to multiple senders by calling :meth:`connect` multiple times. + :param weak: Track the receiver with a :mod:`weakref`. The receiver will + be automatically disconnected when it is garbage collected. When + connecting a receiver defined within a function, set to ``False``, + otherwise it will be disconnected when the function scope ends. + """ + receiver_id = make_id(receiver) + sender_id = ANY_ID if sender is ANY else make_id(sender) + + if weak: + self.receivers[receiver_id] = make_ref( + receiver, self._make_cleanup_receiver(receiver_id) + ) + else: + self.receivers[receiver_id] = receiver + + self._by_sender[sender_id].add(receiver_id) + self._by_receiver[receiver_id].add(sender_id) + + if sender is not ANY and sender_id not in self._weak_senders: + # store a cleanup for weakref-able senders + try: + self._weak_senders[sender_id] = make_ref( + sender, self._make_cleanup_sender(sender_id) + ) + except TypeError: + pass + + if "receiver_connected" in self.__dict__ and self.receiver_connected.receivers: + try: + self.receiver_connected.send( + self, receiver=receiver, sender=sender, weak=weak + ) + except TypeError: + # TODO no explanation or test for this + self.disconnect(receiver, sender) + raise + + return receiver + + def connect_via(self, sender: t.Any, weak: bool = False) -> c.Callable[[F], F]: + """Connect the decorated function to be called when the signal is sent + by ``sender``. + + The decorated function will be called when :meth:`send` is called with + the given ``sender``, passing ``sender`` as a positional argument along + with any extra keyword arguments. + + :param sender: Any object or :data:`ANY`. ``receiver`` will only be + called when :meth:`send` is called with this sender. If ``ANY``, the + receiver will be called for any sender. A receiver may be connected + to multiple senders by calling :meth:`connect` multiple times. + :param weak: Track the receiver with a :mod:`weakref`. The receiver will + be automatically disconnected when it is garbage collected. When + connecting a receiver defined within a function, set to ``False``, + otherwise it will be disconnected when the function scope ends.= + + .. versionadded:: 1.1 + """ + + def decorator(fn: F) -> F: + self.connect(fn, sender, weak) + return fn + + return decorator + + @contextmanager + def connected_to( + self, receiver: c.Callable[..., t.Any], sender: t.Any = ANY + ) -> c.Generator[None, None, None]: + """A context manager that temporarily connects ``receiver`` to the + signal while a ``with`` block executes. When the block exits, the + receiver is disconnected. Useful for tests. + + :param receiver: The callable to call when :meth:`send` is called with + the given ``sender``, passing ``sender`` as a positional argument + along with any extra keyword arguments. + :param sender: Any object or :data:`ANY`. ``receiver`` will only be + called when :meth:`send` is called with this sender. If ``ANY``, the + receiver will be called for any sender. + + .. versionadded:: 1.1 + """ + self.connect(receiver, sender=sender, weak=False) + + try: + yield None + finally: + self.disconnect(receiver) + + @contextmanager + def muted(self) -> c.Generator[None, None, None]: + """A context manager that temporarily disables the signal. No receivers + will be called if the signal is sent, until the ``with`` block exits. + Useful for tests. + """ + self.is_muted = True + + try: + yield None + finally: + self.is_muted = False + + def send( + self, + sender: t.Any | None = None, + /, + *, + _async_wrapper: c.Callable[ + [c.Callable[..., c.Coroutine[t.Any, t.Any, t.Any]]], c.Callable[..., t.Any] + ] + | None = None, + **kwargs: t.Any, + ) -> list[tuple[c.Callable[..., t.Any], t.Any]]: + """Call all receivers that are connected to the given ``sender`` + or :data:`ANY`. Each receiver is called with ``sender`` as a positional + argument along with any extra keyword arguments. Return a list of + ``(receiver, return value)`` tuples. + + The order receivers are called is undefined, but can be influenced by + setting :attr:`set_class`. + + If a receiver raises an exception, that exception will propagate up. + This makes debugging straightforward, with an assumption that correctly + implemented receivers will not raise. + + :param sender: Call receivers connected to this sender, in addition to + those connected to :data:`ANY`. + :param _async_wrapper: Will be called on any receivers that are async + coroutines to turn them into sync callables. For example, could run + the receiver with an event loop. + :param kwargs: Extra keyword arguments to pass to each receiver. + + .. versionchanged:: 1.7 + Added the ``_async_wrapper`` argument. + """ + if self.is_muted: + return [] + + results = [] + + for receiver in self.receivers_for(sender): + if iscoroutinefunction(receiver): + if _async_wrapper is None: + raise RuntimeError("Cannot send to a coroutine function.") + + result = _async_wrapper(receiver)(sender, **kwargs) + else: + result = receiver(sender, **kwargs) + + results.append((receiver, result)) + + return results + + async def send_async( + self, + sender: t.Any | None = None, + /, + *, + _sync_wrapper: c.Callable[ + [c.Callable[..., t.Any]], c.Callable[..., c.Coroutine[t.Any, t.Any, t.Any]] + ] + | None = None, + **kwargs: t.Any, + ) -> list[tuple[c.Callable[..., t.Any], t.Any]]: + """Await all receivers that are connected to the given ``sender`` + or :data:`ANY`. Each receiver is called with ``sender`` as a positional + argument along with any extra keyword arguments. Return a list of + ``(receiver, return value)`` tuples. + + The order receivers are called is undefined, but can be influenced by + setting :attr:`set_class`. + + If a receiver raises an exception, that exception will propagate up. + This makes debugging straightforward, with an assumption that correctly + implemented receivers will not raise. + + :param sender: Call receivers connected to this sender, in addition to + those connected to :data:`ANY`. + :param _sync_wrapper: Will be called on any receivers that are sync + callables to turn them into async coroutines. For example, + could call the receiver in a thread. + :param kwargs: Extra keyword arguments to pass to each receiver. + + .. versionadded:: 1.7 + """ + if self.is_muted: + return [] + + results = [] + + for receiver in self.receivers_for(sender): + if not iscoroutinefunction(receiver): + if _sync_wrapper is None: + raise RuntimeError("Cannot send to a non-coroutine function.") + + result = await _sync_wrapper(receiver)(sender, **kwargs) + else: + result = await receiver(sender, **kwargs) + + results.append((receiver, result)) + + return results + + def has_receivers_for(self, sender: t.Any) -> bool: + """Check if there is at least one receiver that will be called with the + given ``sender``. A receiver connected to :data:`ANY` will always be + called, regardless of sender. Does not check if weakly referenced + receivers are still live. See :meth:`receivers_for` for a stronger + search. + + :param sender: Check for receivers connected to this sender, in addition + to those connected to :data:`ANY`. + """ + if not self.receivers: + return False + + if self._by_sender[ANY_ID]: + return True + + if sender is ANY: + return False + + return make_id(sender) in self._by_sender + + def receivers_for( + self, sender: t.Any + ) -> c.Generator[c.Callable[..., t.Any], None, None]: + """Yield each receiver to be called for ``sender``, in addition to those + to be called for :data:`ANY`. Weakly referenced receivers that are not + live will be disconnected and skipped. + + :param sender: Yield receivers connected to this sender, in addition + to those connected to :data:`ANY`. + """ + # TODO: test receivers_for(ANY) + if not self.receivers: + return + + sender_id = make_id(sender) + + if sender_id in self._by_sender: + ids = self._by_sender[ANY_ID] | self._by_sender[sender_id] + else: + ids = self._by_sender[ANY_ID].copy() + + for receiver_id in ids: + receiver = self.receivers.get(receiver_id) + + if receiver is None: + continue + + if isinstance(receiver, weakref.ref): + strong = receiver() + + if strong is None: + self._disconnect(receiver_id, ANY_ID) + continue + + yield strong + else: + yield receiver + + def disconnect(self, receiver: c.Callable[..., t.Any], sender: t.Any = ANY) -> None: + """Disconnect ``receiver`` from being called when the signal is sent by + ``sender``. + + :param receiver: A connected receiver callable. + :param sender: Disconnect from only this sender. By default, disconnect + from all senders. + """ + sender_id: c.Hashable + + if sender is ANY: + sender_id = ANY_ID + else: + sender_id = make_id(sender) + + receiver_id = make_id(receiver) + self._disconnect(receiver_id, sender_id) + + if ( + "receiver_disconnected" in self.__dict__ + and self.receiver_disconnected.receivers + ): + self.receiver_disconnected.send(self, receiver=receiver, sender=sender) + + def _disconnect(self, receiver_id: c.Hashable, sender_id: c.Hashable) -> None: + if sender_id == ANY_ID: + if self._by_receiver.pop(receiver_id, None) is not None: + for bucket in self._by_sender.values(): + bucket.discard(receiver_id) + + self.receivers.pop(receiver_id, None) + else: + self._by_sender[sender_id].discard(receiver_id) + self._by_receiver[receiver_id].discard(sender_id) + + def _make_cleanup_receiver( + self, receiver_id: c.Hashable + ) -> c.Callable[[weakref.ref[c.Callable[..., t.Any]]], None]: + """Create a callback function to disconnect a weakly referenced + receiver when it is garbage collected. + """ + + def cleanup(ref: weakref.ref[c.Callable[..., t.Any]]) -> None: + # If the interpreter is shutting down, disconnecting can result in a + # weird ignored exception. Don't call it in that case. + if not sys.is_finalizing(): + self._disconnect(receiver_id, ANY_ID) + + return cleanup + + def _make_cleanup_sender( + self, sender_id: c.Hashable + ) -> c.Callable[[weakref.ref[t.Any]], None]: + """Create a callback function to disconnect all receivers for a weakly + referenced sender when it is garbage collected. + """ + assert sender_id != ANY_ID + + def cleanup(ref: weakref.ref[t.Any]) -> None: + self._weak_senders.pop(sender_id, None) + + for receiver_id in self._by_sender.pop(sender_id, ()): + self._by_receiver[receiver_id].discard(sender_id) + + return cleanup + + def _cleanup_bookkeeping(self) -> None: + """Prune unused sender/receiver bookkeeping. Not threadsafe. + + Connecting & disconnecting leaves behind a small amount of bookkeeping + data. Typical workloads using Blinker, for example in most web apps, + Flask, CLI scripts, etc., are not adversely affected by this + bookkeeping. + + With a long-running process performing dynamic signal routing with high + volume, e.g. connecting to function closures, senders are all unique + object instances. Doing all of this over and over may cause memory usage + to grow due to extraneous bookkeeping. (An empty ``set`` for each stale + sender/receiver pair.) + + This method will prune that bookkeeping away, with the caveat that such + pruning is not threadsafe. The risk is that cleanup of a fully + disconnected receiver/sender pair occurs while another thread is + connecting that same pair. If you are in the highly dynamic, unique + receiver/sender situation that has lead you to this method, that failure + mode is perhaps not a big deal for you. + """ + for mapping in (self._by_sender, self._by_receiver): + for ident, bucket in list(mapping.items()): + if not bucket: + mapping.pop(ident, None) + + def _clear_state(self) -> None: + """Disconnect all receivers and senders. Useful for tests.""" + self._weak_senders.clear() + self.receivers.clear() + self._by_sender.clear() + self._by_receiver.clear() + + +class NamedSignal(Signal): + """A named generic notification emitter. The name is not used by the signal + itself, but matches the key in the :class:`Namespace` that it belongs to. + + :param name: The name of the signal within the namespace. + :param doc: The docstring for the signal. + """ + + def __init__(self, name: str, doc: str | None = None) -> None: + super().__init__(doc) + + #: The name of this signal. + self.name: str = name + + def __repr__(self) -> str: + base = super().__repr__() + return f"{base[:-1]}; {self.name!r}>" # noqa: E702 + + +class Namespace(dict[str, NamedSignal]): + """A dict mapping names to signals.""" + + def signal(self, name: str, doc: str | None = None) -> NamedSignal: + """Return the :class:`NamedSignal` for the given ``name``, creating it + if required. Repeated calls with the same name return the same signal. + + :param name: The name of the signal. + :param doc: The docstring of the signal. + """ + if name not in self: + self[name] = NamedSignal(name, doc) + + return self[name] + + +class _PNamespaceSignal(t.Protocol): + def __call__(self, name: str, doc: str | None = None) -> NamedSignal: ... + + +default_namespace: Namespace = Namespace() +"""A default :class:`Namespace` for creating named signals. :func:`signal` +creates a :class:`NamedSignal` in this namespace. +""" + +signal: _PNamespaceSignal = default_namespace.signal +"""Return a :class:`NamedSignal` in :data:`default_namespace` with the given +``name``, creating it if required. Repeated calls with the same name return the +same signal. +""" diff --git a/psets/9/finance/env/lib/python3.12/site-packages/blinker/py.typed b/psets/9/finance/env/lib/python3.12/site-packages/blinker/py.typed new file mode 100644 index 0000000..e69de29 diff --git a/psets/9/finance/env/lib/python3.12/site-packages/cachelib-0.13.0.dist-info/INSTALLER b/psets/9/finance/env/lib/python3.12/site-packages/cachelib-0.13.0.dist-info/INSTALLER new file mode 100644 index 0000000..a1b589e --- /dev/null +++ b/psets/9/finance/env/lib/python3.12/site-packages/cachelib-0.13.0.dist-info/INSTALLER @@ -0,0 +1 @@ +pip diff --git a/psets/9/finance/env/lib/python3.12/site-packages/cachelib-0.13.0.dist-info/LICENSE.rst b/psets/9/finance/env/lib/python3.12/site-packages/cachelib-0.13.0.dist-info/LICENSE.rst new file mode 100644 index 0000000..8f60923 --- /dev/null +++ b/psets/9/finance/env/lib/python3.12/site-packages/cachelib-0.13.0.dist-info/LICENSE.rst @@ -0,0 +1,28 @@ +Copyright 2018 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/psets/9/finance/env/lib/python3.12/site-packages/cachelib-0.13.0.dist-info/METADATA b/psets/9/finance/env/lib/python3.12/site-packages/cachelib-0.13.0.dist-info/METADATA new file mode 100644 index 0000000..340a15e --- /dev/null +++ b/psets/9/finance/env/lib/python3.12/site-packages/cachelib-0.13.0.dist-info/METADATA @@ -0,0 +1,64 @@ +Metadata-Version: 2.1 +Name: cachelib +Version: 0.13.0 +Summary: A collection of cache libraries in the same API interface. +Home-page: https://github.com/pallets-eco/cachelib/ +Maintainer: Pallets +Maintainer-email: contact@palletsprojects.com +License: BSD-3-Clause +Project-URL: Donate, https://palletsprojects.com/donate +Project-URL: Documentation, https://cachelib.readthedocs.io/ +Project-URL: Changes, https://cachelib.readthedocs.io/changes/ +Project-URL: Source Code, https://github.com/pallets-eco/cachelib/ +Project-URL: Issue Tracker, https://github.com/pallets-eco/cachelib/issues/ +Project-URL: Twitter, https://twitter.com/PalletsTeam +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.8 +Description-Content-Type: text/x-rst +License-File: LICENSE.rst + +CacheLib +======== + +A collection of cache libraries in the same API interface. Extracted +from Werkzeug. + + +Installing +---------- + +Install and update using `pip`_: + +.. code-block:: text + + $ pip install -U cachelib + +.. _pip: https://pip.pypa.io/en/stable/getting-started/ + + +Donate +------ + +The Pallets organization develops and supports Flask and the libraries +it uses. In order to grow the community of contributors and users, and +allow the maintainers to devote more time to the projects, `please +donate today`_. + +.. _please donate today: https://palletsprojects.com/donate + + +Links +----- + +- Documentation: https://cachelib.readthedocs.io/ +- Changes: https://cachelib.readthedocs.io/changes/ +- PyPI Releases: https://pypi.org/project/cachelib/ +- Source Code: https://github.com/pallets/cachelib/ +- Issue Tracker: https://github.com/pallets/cachelib/issues/ +- Twitter: https://twitter.com/PalletsTeam +- Chat: https://discord.gg/pallets diff --git a/psets/9/finance/env/lib/python3.12/site-packages/cachelib-0.13.0.dist-info/RECORD b/psets/9/finance/env/lib/python3.12/site-packages/cachelib-0.13.0.dist-info/RECORD new file mode 100644 index 0000000..ed64a7d --- /dev/null +++ b/psets/9/finance/env/lib/python3.12/site-packages/cachelib-0.13.0.dist-info/RECORD @@ -0,0 +1,27 @@ +cachelib-0.13.0.dist-info/INSTALLER,sha256=zuuue4knoyJ-UwPPXg8fezS7VCrXJQrAP7zeNuwvFQg,4 +cachelib-0.13.0.dist-info/LICENSE.rst,sha256=zUGBIIEtwmJiga4CfoG2SCKdFmtaynRyzs1RADjTbn0,1475 +cachelib-0.13.0.dist-info/METADATA,sha256=lqDsbA03sUETX-dGoDR1uDqqXtyu1m0sS0wBjCDEeXE,1960 +cachelib-0.13.0.dist-info/RECORD,, +cachelib-0.13.0.dist-info/WHEEL,sha256=oiQVh_5PnQM0E3gPdiz09WCNmwiHDMaGer_elqB3coM,92 +cachelib-0.13.0.dist-info/top_level.txt,sha256=AYC4q8wgGd_hR_F2YcDkmtQm41gv9-5AThKuQtNPEXk,9 +cachelib/__init__.py,sha256=xTX_F13-FA58DjBGip4XZeCSlEo6B4c4VTRi49MBywY,575 +cachelib/__pycache__/__init__.cpython-312.pyc,, +cachelib/__pycache__/base.cpython-312.pyc,, +cachelib/__pycache__/dynamodb.cpython-312.pyc,, +cachelib/__pycache__/file.cpython-312.pyc,, +cachelib/__pycache__/memcached.cpython-312.pyc,, +cachelib/__pycache__/mongodb.cpython-312.pyc,, +cachelib/__pycache__/redis.cpython-312.pyc,, +cachelib/__pycache__/serializers.cpython-312.pyc,, +cachelib/__pycache__/simple.cpython-312.pyc,, +cachelib/__pycache__/uwsgi.cpython-312.pyc,, +cachelib/base.py,sha256=3_B-cB1VEh_x-VzH9g3qvzdqCxDX2ywDzQ7a_aYFJlE,6731 +cachelib/dynamodb.py,sha256=fSmp8G7V0yBcRC2scdIhz8d0D2-9OMZEwQ9AcBONyC8,8512 +cachelib/file.py,sha256=xu6m7nzTMcca_wYS0oM4iOxLarQHZFrhUnQnFYansy4,12270 +cachelib/memcached.py,sha256=KyUN4wblVPf2XNLYk15kwN9QTfkFK6jrpVGrj4NAoFA,7160 +cachelib/mongodb.py,sha256=b9l8fTKMFm8hAXFn748GKertHUASSVDBgPgrtGaZ6cA,6901 +cachelib/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0 +cachelib/redis.py,sha256=hSKV9fVD7gzk1X_B3Ac9XJYN3G3F6eYBoreqDo9pces,6295 +cachelib/serializers.py,sha256=MXk1moN6ljOPUFQ0E0D129mZlrDDwuQ5DvInNkitvoI,3343 +cachelib/simple.py,sha256=8UPp95_oc3bLeW_gzFUzdppIKV8hV_o_yQYoKb8gVMk,3422 +cachelib/uwsgi.py,sha256=4DX3C9QGvB6mVcg1d7qpLIEkI6bccuq-8M6I_YbPicY,2563 diff --git a/psets/9/finance/env/lib/python3.12/site-packages/cachelib-0.13.0.dist-info/WHEEL b/psets/9/finance/env/lib/python3.12/site-packages/cachelib-0.13.0.dist-info/WHEEL new file mode 100644 index 0000000..98c0d20 --- /dev/null +++ b/psets/9/finance/env/lib/python3.12/site-packages/cachelib-0.13.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/psets/9/finance/env/lib/python3.12/site-packages/cachelib-0.13.0.dist-info/top_level.txt b/psets/9/finance/env/lib/python3.12/site-packages/cachelib-0.13.0.dist-info/top_level.txt new file mode 100644 index 0000000..6e3a9b9 --- /dev/null +++ b/psets/9/finance/env/lib/python3.12/site-packages/cachelib-0.13.0.dist-info/top_level.txt @@ -0,0 +1 @@ +cachelib diff --git a/psets/9/finance/env/lib/python3.12/site-packages/cachelib/__init__.py b/psets/9/finance/env/lib/python3.12/site-packages/cachelib/__init__.py new file mode 100644 index 0000000..5699a44 --- /dev/null +++ b/psets/9/finance/env/lib/python3.12/site-packages/cachelib/__init__.py @@ -0,0 +1,22 @@ +from cachelib.base import BaseCache +from cachelib.base import NullCache +from cachelib.dynamodb import DynamoDbCache +from cachelib.file import FileSystemCache +from cachelib.memcached import MemcachedCache +from cachelib.mongodb import MongoDbCache +from cachelib.redis import RedisCache +from cachelib.simple import SimpleCache +from cachelib.uwsgi import UWSGICache + +__all__ = [ + "BaseCache", + "NullCache", + "SimpleCache", + "FileSystemCache", + "MemcachedCache", + "RedisCache", + "UWSGICache", + "DynamoDbCache", + "MongoDbCache", +] +__version__ = "0.13.0" diff --git a/psets/9/finance/env/lib/python3.12/site-packages/cachelib/__pycache__/__init__.cpython-312.pyc b/psets/9/finance/env/lib/python3.12/site-packages/cachelib/__pycache__/__init__.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..8c89b793fbd1f0a8ebb87c361bca0a9487f94095 GIT binary patch literal 749 zcmYjNO>fgM7`FS7=A&u5Au(}A6RObSj)?=(1QJvr4%>kWAuJ>-O}xy)cB(ktRI~&9 z3hvzaE&PK>Il+b7#BQ9hjgs}1{p5My*YC%ZA7SVNZNIMGXU{qS{4`Eu+P8Ldr9WRm z3R1{{fEYrh=GmS9JA8MbCiwgN0*Y zV8AmF80Z^tHGFbr(cw`vJDuLCLc0NH%V?>!+_tH9+C*xlq)XditKdv4vV*GK_N{0n z+2PgXHer;=V^`**~RZSS}9s8^aPzT8OwwsDld@MjaHlTJeNn&;UlD2Ne@0Xu()4?2Q}FL U)ANJQ=fU+|Fy8wT6nnblAET?zVgLXD literal 0 HcmV?d00001 diff --git a/psets/9/finance/env/lib/python3.12/site-packages/cachelib/__pycache__/base.cpython-312.pyc b/psets/9/finance/env/lib/python3.12/site-packages/cachelib/__pycache__/base.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..5a8046ff3acaf3f13e58fb7cece0478c1b5573b5 GIT binary patch literal 9190 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 S&hcnm?Z4ReX9YJg)jt4@r~lCa literal 0 HcmV?d00001 diff --git a/psets/9/finance/env/lib/python3.12/site-packages/cachelib/__pycache__/dynamodb.cpython-312.pyc b/psets/9/finance/env/lib/python3.12/site-packages/cachelib/__pycache__/dynamodb.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..7d862687a70859ccd4cb466f2ed417ff382465c8 GIT binary patch literal 11693 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 QZ!&av<;?FXd=py#2aWcQO#lD@ literal 0 HcmV?d00001 diff --git a/psets/9/finance/env/lib/python3.12/site-packages/cachelib/__pycache__/file.cpython-312.pyc b/psets/9/finance/env/lib/python3.12/site-packages/cachelib/__pycache__/file.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..3b34c15c5b1413896221acb6c0bedfb169f684ca GIT binary patch literal 17550 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 E1ERt7%m4rY literal 0 HcmV?d00001 diff --git a/psets/9/finance/env/lib/python3.12/site-packages/cachelib/__pycache__/mongodb.cpython-312.pyc b/psets/9/finance/env/lib/python3.12/site-packages/cachelib/__pycache__/mongodb.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..1ae9cbce8770dde687dc1b10435484c9d826476e GIT binary patch literal 11470 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 literal 0 HcmV?d00001 diff --git a/psets/9/finance/env/lib/python3.12/site-packages/cachelib/__pycache__/simple.cpython-312.pyc b/psets/9/finance/env/lib/python3.12/site-packages/cachelib/__pycache__/simple.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..52d89027941cf9b751298e5f47ec4687601d5b3a GIT binary patch literal 6442 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 literal 0 HcmV?d00001 diff --git a/psets/9/finance/env/lib/python3.12/site-packages/cachelib/base.py b/psets/9/finance/env/lib/python3.12/site-packages/cachelib/base.py new file mode 100644 index 0000000..e6a6d7e --- /dev/null +++ b/psets/9/finance/env/lib/python3.12/site-packages/cachelib/base.py @@ -0,0 +1,185 @@ +import typing as _t + + +class BaseCache: + """Baseclass for the cache systems. All the cache systems implement this + API or a superset of it. + + :param default_timeout: the default timeout (in seconds) that is used if + no timeout is specified on :meth:`set`. A timeout + of 0 indicates that the cache never expires. + """ + + def __init__(self, default_timeout: int = 300): + self.default_timeout = default_timeout + + def _normalize_timeout(self, timeout: _t.Optional[int]) -> int: + if timeout is None: + timeout = self.default_timeout + return timeout + + def get(self, key: str) -> _t.Any: + """Look up key in the cache and return the value for it. + + :param key: the key to be looked up. + :returns: The value if it exists and is readable, else ``None``. + """ + return None + + def delete(self, key: str) -> bool: + """Delete `key` from the cache. + + :param key: the key to delete. + :returns: Whether the key existed and has been deleted. + :rtype: boolean + """ + return True + + def get_many(self, *keys: str) -> _t.List[_t.Any]: + """Returns a list of values for the given keys. + For each key an item in the list is created:: + + foo, bar = cache.get_many("foo", "bar") + + Has the same error handling as :meth:`get`. + + :param keys: The function accepts multiple keys as positional + arguments. + """ + return [self.get(k) for k in keys] + + def get_dict(self, *keys: str) -> _t.Dict[str, _t.Any]: + """Like :meth:`get_many` but return a dict:: + + d = cache.get_dict("foo", "bar") + foo = d["foo"] + bar = d["bar"] + + :param keys: The function accepts multiple keys as positional + arguments. + """ + return dict(zip(keys, self.get_many(*keys))) # noqa: B905 + + def set( + self, key: str, value: _t.Any, timeout: _t.Optional[int] = None + ) -> _t.Optional[bool]: + """Add a new key/value to the cache (overwrites value, if key already + exists in the cache). + + :param key: the key to set + :param value: the value for the key + :param timeout: the cache timeout for the key in seconds (if not + specified, it uses the default timeout). A timeout of + 0 indicates that the cache never expires. + :returns: ``True`` if key has been updated, ``False`` for backend + errors. Pickling errors, however, will raise a subclass of + ``pickle.PickleError``. + :rtype: boolean + """ + return True + + def add(self, key: str, value: _t.Any, timeout: _t.Optional[int] = None) -> bool: + """Works like :meth:`set` but does not overwrite the values of already + existing keys. + + :param key: the key to set + :param value: the value for the key + :param timeout: the cache timeout for the key in seconds (if not + specified, it uses the default timeout). A timeout of + 0 indicates that the cache never expires. + :returns: Same as :meth:`set`, but also ``False`` for already + existing keys. + :rtype: boolean + """ + return True + + def set_many( + self, mapping: _t.Dict[str, _t.Any], timeout: _t.Optional[int] = None + ) -> _t.List[_t.Any]: + """Sets multiple keys and values from a mapping. + + :param mapping: a mapping with the keys/values to set. + :param timeout: the cache timeout for the key in seconds (if not + specified, it uses the default timeout). A timeout of + 0 indicates that the cache never expires. + :returns: A list containing all keys successfully set + :rtype: boolean + """ + set_keys = [] + for key, value in mapping.items(): + if self.set(key, value, timeout): + set_keys.append(key) + return set_keys + + def delete_many(self, *keys: str) -> _t.List[_t.Any]: + """Deletes multiple keys at once. + + :param keys: The function accepts multiple keys as positional + arguments. + :returns: A list containing all successfully deleted keys + :rtype: boolean + """ + deleted_keys = [] + for key in keys: + if self.delete(key): + deleted_keys.append(key) + return deleted_keys + + def has(self, key: str) -> bool: + """Checks if a key exists in the cache without returning it. This is a + cheap operation that bypasses loading the actual data on the backend. + + :param key: the key to check + """ + raise NotImplementedError( + "%s doesn't have an efficient implementation of `has`. That " + "means it is impossible to check whether a key exists without " + "fully loading the key's data. Consider using `self.get` " + "explicitly if you don't care about performance." + ) + + def clear(self) -> bool: + """Clears the cache. Keep in mind that not all caches support + completely clearing the cache. + + :returns: Whether the cache has been cleared. + :rtype: boolean + """ + return True + + def inc(self, key: str, delta: int = 1) -> _t.Optional[int]: + """Increments the value of a key by `delta`. If the key does + not yet exist it is initialized with `delta`. + + For supporting caches this is an atomic operation. + + :param key: the key to increment. + :param delta: the delta to add. + :returns: The new value or ``None`` for backend errors. + """ + value = (self.get(key) or 0) + delta + return value if self.set(key, value) else None + + def dec(self, key: str, delta: int = 1) -> _t.Optional[int]: + """Decrements the value of a key by `delta`. If the key does + not yet exist it is initialized with `-delta`. + + For supporting caches this is an atomic operation. + + :param key: the key to increment. + :param delta: the delta to subtract. + :returns: The new value or `None` for backend errors. + """ + value = (self.get(key) or 0) - delta + return value if self.set(key, value) else None + + +class NullCache(BaseCache): + """A cache that doesn't cache. This can be useful for unit testing. + + :param default_timeout: a dummy parameter that is ignored but exists + for API compatibility with other caches. + """ + + def has(self, key: str) -> bool: + return False diff --git a/psets/9/finance/env/lib/python3.12/site-packages/cachelib/dynamodb.py b/psets/9/finance/env/lib/python3.12/site-packages/cachelib/dynamodb.py new file mode 100644 index 0000000..5f7a55b --- /dev/null +++ b/psets/9/finance/env/lib/python3.12/site-packages/cachelib/dynamodb.py @@ -0,0 +1,226 @@ +import datetime +import typing as _t + +from cachelib.base import BaseCache +from cachelib.serializers import DynamoDbSerializer + +CREATED_AT_FIELD = "created_at" +RESPONSE_FIELD = "response" + + +class DynamoDbCache(BaseCache): + """ + Implementation of cachelib.BaseCache that uses an AWS DynamoDb table + as the backend. + + Your server process will require dynamodb:GetItem and dynamodb:PutItem + IAM permissions on the cache table. + + Limitations: DynamoDB table items are limited to 400 KB in size. Since + this class stores cached items in a table, the max size of a cache entry + will be slightly less than 400 KB, since the cache key and expiration + time fields are also part of the item. + + :param table_name: The name of the DynamoDB table to use + :param default_timeout: Set the timeout in seconds after which cache entries + expire + :param key_field: The name of the hash_key attribute in the DynamoDb + table. This must be a string attribute. + :param expiration_time_field: The name of the table attribute to store the + expiration time in. This will be an int + attribute. The timestamp will be stored as + seconds past the epoch. If you configure + this as the TTL field, then DynamoDB will + automatically delete expired entries. + :param key_prefix: A prefix that should be added to all keys. + + """ + + serializer = DynamoDbSerializer() + + def __init__( + self, + table_name: _t.Optional[str] = "python-cache", + default_timeout: int = 300, + key_field: _t.Optional[str] = "cache_key", + expiration_time_field: _t.Optional[str] = "expiration_time", + key_prefix: _t.Optional[str] = None, + **kwargs: _t.Any + ): + super().__init__(default_timeout) + + try: + import boto3 # type: ignore + except ImportError as err: + raise RuntimeError("no boto3 module found") from err + + self._table_name = table_name + self._key_field = key_field + self._expiration_time_field = expiration_time_field + self.key_prefix = key_prefix or "" + self._dynamo = boto3.resource("dynamodb", **kwargs) + self._attr = boto3.dynamodb.conditions.Attr + + try: + self._table = self._dynamo.Table(table_name) + self._table.load() + # catch this exception (triggered if the table doesn't exist) + except Exception: + table = self._dynamo.create_table( + AttributeDefinitions=[ + {"AttributeName": key_field, "AttributeType": "S"} + ], + TableName=table_name, + KeySchema=[ + {"AttributeName": key_field, "KeyType": "HASH"}, + ], + BillingMode="PAY_PER_REQUEST", + ) + table.wait_until_exists() + dynamo = boto3.client("dynamodb", **kwargs) + dynamo.update_time_to_live( + TableName=table_name, + TimeToLiveSpecification={ + "Enabled": True, + "AttributeName": expiration_time_field, + }, + ) + self._table = self._dynamo.Table(table_name) + self._table.load() + + def _utcnow(self) -> _t.Any: + """Return a tz-aware UTC datetime representing the current time""" + return datetime.datetime.utcnow().replace(tzinfo=datetime.timezone.utc) + + def _get_item(self, key: str, attributes: _t.Optional[list] = None) -> _t.Any: + """ + Get an item from the cache table, optionally limiting the returned + attributes. + + :param key: The cache key of the item to fetch + + :param attributes: An optional list of attributes to fetch. If not + given, all attributes are fetched. The + expiration_time field will always be added to the + list of fetched attributes. + :return: The table item for key if it exists and is not expired, else + None + """ + kwargs = {} + if attributes: + if self._expiration_time_field not in attributes: + attributes = list(attributes) + [self._expiration_time_field] + kwargs = dict(ProjectionExpression=",".join(attributes)) + + response = self._table.get_item(Key={self._key_field: key}, **kwargs) + cache_item = response.get("Item") + + if cache_item: + now = int(self._utcnow().timestamp()) + if cache_item.get(self._expiration_time_field, now + 100) > now: + return cache_item + + return None + + def get(self, key: str) -> _t.Any: + """ + Get a cache item + + :param key: The cache key of the item to fetch + :return: cache value if not expired, else None + """ + cache_item = self._get_item(self.key_prefix + key) + if cache_item: + response = cache_item[RESPONSE_FIELD] + value = self.serializer.loads(response) + return value + return None + + def delete(self, key: str) -> bool: + """ + Deletes an item from the cache. This is a no-op if the item doesn't + exist + + :param key: Key of the item to delete. + :return: True if the key existed and was deleted + """ + try: + self._table.delete_item( + Key={self._key_field: self.key_prefix + key}, + ConditionExpression=self._attr(self._key_field).exists(), + ) + return True + except self._dynamo.meta.client.exceptions.ConditionalCheckFailedException: + return False + + def _set( + self, + key: str, + value: _t.Any, + timeout: _t.Optional[int] = None, + overwrite: _t.Optional[bool] = True, + ) -> _t.Any: + """ + Store a cache item, with the option to not overwrite existing items + + :param key: Cache key to use + :param value: a serializable object + :param timeout: The timeout in seconds for the cached item, to override + the default + :param overwrite: If true, overwrite any existing cache item with key. + If false, the new value will only be stored if no + non-expired cache item exists with key. + :return: True if the new item was stored. + """ + timeout = self._normalize_timeout(timeout) + now = self._utcnow() + + kwargs = {} + if not overwrite: + # Cause the put to fail if a non-expired item with this key + # already exists + + cond = self._attr(self._key_field).not_exists() | self._attr( + self._expiration_time_field + ).lte(int(now.timestamp())) + kwargs = dict(ConditionExpression=cond) + + try: + dump = self.serializer.dumps(value) + item = { + self._key_field: key, + CREATED_AT_FIELD: now.isoformat(), + RESPONSE_FIELD: dump, + } + if timeout > 0: + expiration_time = now + datetime.timedelta(seconds=timeout) + item[self._expiration_time_field] = int(expiration_time.timestamp()) + self._table.put_item(Item=item, **kwargs) + return True + except Exception: + return False + + def set(self, key: str, value: _t.Any, timeout: _t.Optional[int] = None) -> _t.Any: + return self._set(self.key_prefix + key, value, timeout=timeout, overwrite=True) + + def add(self, key: str, value: _t.Any, timeout: _t.Optional[int] = None) -> _t.Any: + return self._set(self.key_prefix + key, value, timeout=timeout, overwrite=False) + + def has(self, key: str) -> bool: + return ( + self._get_item(self.key_prefix + key, [self._expiration_time_field]) + is not None + ) + + def clear(self) -> bool: + paginator = self._dynamo.meta.client.get_paginator("scan") + pages = paginator.paginate( + TableName=self._table_name, ProjectionExpression=self._key_field + ) + + with self._table.batch_writer() as batch: + for page in pages: + for item in page["Items"]: + batch.delete_item(Key=item) + + return True diff --git a/psets/9/finance/env/lib/python3.12/site-packages/cachelib/file.py b/psets/9/finance/env/lib/python3.12/site-packages/cachelib/file.py new file mode 100644 index 0000000..4c5011f --- /dev/null +++ b/psets/9/finance/env/lib/python3.12/site-packages/cachelib/file.py @@ -0,0 +1,348 @@ +import errno +import hashlib +import logging +import os +import platform +import stat +import struct +import tempfile +import typing as _t +from contextlib import contextmanager +from pathlib import Path +from time import sleep +from time import time + +from cachelib.base import BaseCache +from cachelib.serializers import FileSystemSerializer + + +def _lazy_md5(string: bytes = b"") -> _t.Any: + """Don't access ``hashlib.md5`` until runtime. FIPS builds may not include + md5, in which case the import and use as a default would fail before the + developer can configure something else. + """ + return hashlib.md5(string) + + +class FileSystemCache(BaseCache): + """A cache that stores the items on the file system. This cache depends + on being the only user of the `cache_dir`. Make absolutely sure that + nobody but this cache stores files there or otherwise the cache will + randomly delete files therein. + + :param cache_dir: the directory where cache files are stored. + :param threshold: the maximum number of items the cache stores before + it starts deleting some. A threshold value of 0 + indicates no threshold. + :param default_timeout: the default timeout that is used if no timeout is + specified on :meth:`~BaseCache.set`. A timeout of + 0 indicates that the cache never expires. + :param mode: the file mode wanted for the cache files, default 0600 + :param hash_method: Default hashlib.md5. The hash method used to + generate the filename for cached results. + Default is lazy loaded and can be overriden by + seeting `_default_hash_method` + """ + + #: used for temporary files by the FileSystemCache + _fs_transaction_suffix = ".__wz_cache" + #: keep amount of files in a cache element + _fs_count_file = "__wz_cache_count" + #: default file name hashing method + _default_hash_method = staticmethod(_lazy_md5) + + serializer = FileSystemSerializer() + + def __init__( + self, + cache_dir: str, + threshold: int = 500, + default_timeout: int = 300, + mode: _t.Optional[int] = None, + hash_method: _t.Any = None, + ): + BaseCache.__init__(self, default_timeout) + self._path = cache_dir + self._threshold = threshold + + self._hash_method = self._default_hash_method + if hash_method is not None: + self._hash_method = hash_method + + # Mode set by user takes precedence. If no mode has + # been given, we need to set the correct default based + # on user platform. + self._mode = mode + if self._mode is None: + self._mode = self._get_compatible_platform_mode() + + try: + os.makedirs(self._path) + except OSError as ex: + if ex.errno != errno.EEXIST: + raise + + # If there are many files and a zero threshold, + # the list_dir can slow initialisation massively + if self._threshold != 0: + self._update_count(value=len(list(self._list_dir()))) + + def _get_compatible_platform_mode(self) -> int: + mode = 0o600 # nix systems + if platform.system() == "Windows": + mode = stat.S_IWRITE + return mode + + @property + def _file_count(self) -> int: + return self.get(self._fs_count_file) or 0 + + def _update_count( + self, delta: _t.Optional[int] = None, value: _t.Optional[int] = None + ) -> None: + # If we have no threshold, don't count files + if self._threshold == 0: + return + if delta: + new_count = self._file_count + delta + else: + new_count = value or 0 + self.set(self._fs_count_file, new_count, mgmt_element=True) + + def _normalize_timeout(self, timeout: _t.Optional[int]) -> int: + timeout = BaseCache._normalize_timeout(self, timeout) + if timeout != 0: + timeout = int(time()) + timeout + return int(timeout) + + def _is_mgmt(self, name: str) -> bool: + fshash = self._get_filename(self._fs_count_file).split(os.sep)[-1] + return name == fshash or name.endswith(self._fs_transaction_suffix) + + def _list_dir(self) -> _t.Generator[str, None, None]: + """return a list of (fully qualified) cache filenames""" + return ( + os.path.join(self._path, fn) + for fn in os.listdir(self._path) + if not self._is_mgmt(fn) + ) + + def _over_threshold(self) -> bool: + return self._threshold != 0 and self._file_count > self._threshold + + def _remove_expired(self, now: float) -> None: + for fname in self._list_dir(): + try: + with self._safe_stream_open(fname, "rb") as f: + expires = struct.unpack("I", f.read(4))[0] + if expires != 0 and expires < now: + os.remove(fname) + self._update_count(delta=-1) + except FileNotFoundError: + pass + except (OSError, EOFError, struct.error): + logging.warning( + "Exception raised while handling cache file '%s'", + fname, + exc_info=True, + ) + + def _remove_older(self) -> bool: + exp_fname_tuples = [] + for fname in self._list_dir(): + try: + with self._safe_stream_open(fname, "rb") as f: + timestamp = struct.unpack("I", f.read(4))[0] + exp_fname_tuples.append((timestamp, fname)) + except FileNotFoundError: + pass + except (OSError, EOFError, struct.error): + logging.warning( + "Exception raised while handling cache file '%s'", + fname, + exc_info=True, + ) + fname_sorted = ( + fname for _, fname in sorted(exp_fname_tuples, key=lambda item: item[0]) + ) + for fname in fname_sorted: + try: + os.remove(fname) + self._update_count(delta=-1) + except FileNotFoundError: + pass + except OSError: + logging.warning( + "Exception raised while handling cache file '%s'", + fname, + exc_info=True, + ) + return False + if not self._over_threshold(): + break + return True + + def _prune(self) -> None: + if self._over_threshold(): + now = time() + self._remove_expired(now) + # if still over threshold + if self._over_threshold(): + self._remove_older() + + def clear(self) -> bool: + for i, fname in enumerate(self._list_dir()): + try: + os.remove(fname) + except FileNotFoundError: + pass + except OSError: + logging.warning( + "Exception raised while handling cache file '%s'", + fname, + exc_info=True, + ) + self._update_count(delta=-i) + return False + self._update_count(value=0) + return True + + def _get_filename(self, key: str) -> str: + if isinstance(key, str): + bkey = key.encode("utf-8") # XXX unicode review + bkey_hash = self._hash_method(bkey).hexdigest() + else: + raise TypeError(f"Key must be a string, received type {type(key)}") + return os.path.join(self._path, bkey_hash) + + def get(self, key: str) -> _t.Any: + filename = self._get_filename(key) + try: + with self._safe_stream_open(filename, "rb") as f: + pickle_time = struct.unpack("I", f.read(4))[0] + if pickle_time == 0 or pickle_time >= time(): + return self.serializer.load(f) + except FileNotFoundError: + pass + except (OSError, EOFError, struct.error): + logging.warning( + "Exception raised while handling cache file '%s'", + filename, + exc_info=True, + ) + return None + + def add(self, key: str, value: _t.Any, timeout: _t.Optional[int] = None) -> bool: + filename = self._get_filename(key) + if not os.path.exists(filename): + return self.set(key, value, timeout) + return False + + def set( + self, + key: str, + value: _t.Any, + timeout: _t.Optional[int] = None, + mgmt_element: bool = False, + ) -> bool: + # Management elements have no timeout + if mgmt_element: + timeout = 0 + # Don't prune on management element update, to avoid loop + else: + self._prune() + + timeout = self._normalize_timeout(timeout) + filename = self._get_filename(key) + overwrite = os.path.isfile(filename) + + try: + fd, tmp = tempfile.mkstemp( + suffix=self._fs_transaction_suffix, dir=self._path + ) + with os.fdopen(fd, "wb") as f: + f.write(struct.pack("I", timeout)) + self.serializer.dump(value, f) + + self._run_safely(os.replace, tmp, filename) + self._run_safely(os.chmod, filename, self._mode) + + fsize = Path(filename).stat().st_size + except OSError: + logging.warning( + "Exception raised while handling cache file '%s'", + filename, + exc_info=True, + ) + return False + else: + # Management elements should not count towards threshold + if not overwrite and not mgmt_element: + self._update_count(delta=1) + return fsize > 0 # function should fail if file is empty + + def delete(self, key: str, mgmt_element: bool = False) -> bool: + try: + os.remove(self._get_filename(key)) + except FileNotFoundError: # if file doesn't exist we consider it deleted + return True + except OSError: + logging.warning("Exception raised while handling cache file", exc_info=True) + return False + else: + # Management elements should not count towards threshold + if not mgmt_element: + self._update_count(delta=-1) + return True + + def has(self, key: str) -> bool: + filename = self._get_filename(key) + try: + with self._safe_stream_open(filename, "rb") as f: + pickle_time = struct.unpack("I", f.read(4))[0] + if pickle_time == 0 or pickle_time >= time(): + return True + else: + return False + except FileNotFoundError: # if there is no file there is no key + return False + except (OSError, EOFError, struct.error): + logging.warning( + "Exception raised while handling cache file '%s'", + filename, + exc_info=True, + ) + return False + + def _run_safely(self, fn: _t.Callable, *args: _t.Any, **kwargs: _t.Any) -> _t.Any: + """On Windows os.replace, os.chmod and open can yield + permission errors if executed by two different processes.""" + if platform.system() == "Windows": + output = None + wait_step = 0.001 + max_sleep_time = 10.0 + total_sleep_time = 0.0 + + while total_sleep_time < max_sleep_time: + try: + output = fn(*args, **kwargs) + except PermissionError: + sleep(wait_step) + total_sleep_time += wait_step + wait_step *= 2 + else: + break + else: + output = fn(*args, **kwargs) + + return output + + @contextmanager + def _safe_stream_open(self, path: str, mode: str) -> _t.Generator: + fs = self._run_safely(open, path, mode) + if fs is None: + raise OSError + try: + yield fs + finally: + fs.close() diff --git a/psets/9/finance/env/lib/python3.12/site-packages/cachelib/memcached.py b/psets/9/finance/env/lib/python3.12/site-packages/cachelib/memcached.py new file mode 100644 index 0000000..7c2f70a --- /dev/null +++ b/psets/9/finance/env/lib/python3.12/site-packages/cachelib/memcached.py @@ -0,0 +1,196 @@ +import re +import typing as _t +from time import time + +from cachelib.base import BaseCache + + +_test_memcached_key = re.compile(r"[^\x00-\x21\xff]{1,250}$").match + + +class MemcachedCache(BaseCache): + """A cache that uses memcached as backend. + + The first argument can either be an object that resembles the API of a + :class:`memcache.Client` or a tuple/list of server addresses. In the + event that a tuple/list is passed, Werkzeug tries to import the best + available memcache library. + + This cache looks into the following packages/modules to find bindings for + memcached: + + - ``pylibmc`` + - ``google.appengine.api.memcached`` + - ``memcached`` + - ``libmc`` + + Implementation notes: This cache backend works around some limitations in + memcached to simplify the interface. For example unicode keys are encoded + to utf-8 on the fly. Methods such as :meth:`~BaseCache.get_dict` return + the keys in the same format as passed. Furthermore all get methods + silently ignore key errors to not cause problems when untrusted user data + is passed to the get methods which is often the case in web applications. + + :param servers: a list or tuple of server addresses or alternatively + a :class:`memcache.Client` or a compatible client. + :param default_timeout: the default timeout that is used if no timeout is + specified on :meth:`~BaseCache.set`. A timeout of + 0 indicates that the cache never expires. + :param key_prefix: a prefix that is added before all keys. This makes it + possible to use the same memcached server for different + applications. Keep in mind that + :meth:`~BaseCache.clear` will also clear keys with a + different prefix. + """ + + def __init__( + self, + servers: _t.Any = None, + default_timeout: int = 300, + key_prefix: _t.Optional[str] = None, + ): + BaseCache.__init__(self, default_timeout) + if servers is None or isinstance(servers, (list, tuple)): + if servers is None: + servers = ["127.0.0.1:11211"] + self._client = self.import_preferred_memcache_lib(servers) + if self._client is None: + raise RuntimeError("no memcache module found") + else: + # NOTE: servers is actually an already initialized memcache + # client. + self._client = servers + + self.key_prefix = key_prefix + + def _normalize_key(self, key: str) -> str: + if self.key_prefix: + key = self.key_prefix + key + return key + + def _normalize_timeout(self, timeout: _t.Optional[int]) -> int: + timeout = BaseCache._normalize_timeout(self, timeout) + if timeout > 0: + timeout = int(time()) + timeout + return timeout + + def get(self, key: str) -> _t.Any: + key = self._normalize_key(key) + # memcached doesn't support keys longer than that. Because often + # checks for so long keys can occur because it's tested from user + # submitted data etc we fail silently for getting. + if _test_memcached_key(key): + return self._client.get(key) + + def get_dict(self, *keys: str) -> _t.Dict[str, _t.Any]: + key_mapping = {} + for key in keys: + encoded_key = self._normalize_key(key) + if _test_memcached_key(key): + key_mapping[encoded_key] = key + _keys = list(key_mapping) + d = rv = self._client.get_multi(_keys) # type: _t.Dict[str, _t.Any] + if self.key_prefix: + rv = {} + for key, value in d.items(): + rv[key_mapping[key]] = value + if len(rv) < len(keys): + for key in keys: + if key not in rv: + rv[key] = None + return rv + + def add(self, key: str, value: _t.Any, timeout: _t.Optional[int] = None) -> bool: + key = self._normalize_key(key) + timeout = self._normalize_timeout(timeout) + return bool(self._client.add(key, value, timeout)) + + def set( + self, key: str, value: _t.Any, timeout: _t.Optional[int] = None + ) -> _t.Optional[bool]: + key = self._normalize_key(key) + timeout = self._normalize_timeout(timeout) + return bool(self._client.set(key, value, timeout)) + + def get_many(self, *keys: str) -> _t.List[_t.Any]: + d = self.get_dict(*keys) + return [d[key] for key in keys] + + def set_many( + self, mapping: _t.Dict[str, _t.Any], timeout: _t.Optional[int] = None + ) -> _t.List[_t.Any]: + new_mapping = {} + for key, value in mapping.items(): + key = self._normalize_key(key) + new_mapping[key] = value + + timeout = self._normalize_timeout(timeout) + failed_keys = self._client.set_multi( + new_mapping, timeout + ) # type: _t.List[_t.Any] + k_normkey = zip(mapping.keys(), new_mapping.keys()) # noqa: B905 + return [k for k, nkey in k_normkey if nkey not in failed_keys] + + def delete(self, key: str) -> bool: + key = self._normalize_key(key) + if _test_memcached_key(key): + return bool(self._client.delete(key)) + return False + + def delete_many(self, *keys: str) -> _t.List[_t.Any]: + new_keys = [] + for key in keys: + key = self._normalize_key(key) + if _test_memcached_key(key): + new_keys.append(key) + self._client.delete_multi(new_keys) + return [k for k in new_keys if not self.has(k)] + + def has(self, key: str) -> bool: + key = self._normalize_key(key) + if _test_memcached_key(key): + return bool(self._client.append(key, "")) + return False + + def clear(self) -> bool: + return bool(self._client.flush_all()) + + def inc(self, key: str, delta: int = 1) -> _t.Optional[int]: + key = self._normalize_key(key) + value = (self._client.get(key) or 0) + delta + return value if self.set(key, value) else None + + def dec(self, key: str, delta: int = 1) -> _t.Optional[int]: + key = self._normalize_key(key) + value = (self._client.get(key) or 0) - delta + return value if self.set(key, value) else None + + def import_preferred_memcache_lib(self, servers: _t.Any) -> _t.Any: + """Returns an initialized memcache client. Used by the constructor.""" + try: + import pylibmc # type: ignore + except ImportError: + pass + else: + return pylibmc.Client(servers) + + try: + from google.appengine.api import memcache # type: ignore + except ImportError: + pass + else: + return memcache.Client() + + try: + import memcache # type: ignore + except ImportError: + pass + else: + return memcache.Client(servers) + + try: + import libmc # type: ignore + except ImportError: + pass + else: + return libmc.Client(servers) diff --git a/psets/9/finance/env/lib/python3.12/site-packages/cachelib/mongodb.py b/psets/9/finance/env/lib/python3.12/site-packages/cachelib/mongodb.py new file mode 100644 index 0000000..ac18642 --- /dev/null +++ b/psets/9/finance/env/lib/python3.12/site-packages/cachelib/mongodb.py @@ -0,0 +1,202 @@ +import datetime +import logging +import typing as _t + +from cachelib.base import BaseCache +from cachelib.serializers import BaseSerializer + + +class MongoDbCache(BaseCache): + """ + Implementation of cachelib.BaseCache that uses mongodb collection + as the backend. + + Limitations: maximum MongoDB document size is 16mb + + :param client: mongodb client or connection string + :param db: mongodb database name + :param collection: mongodb collection name + :param default_timeout: Set the timeout in seconds after which cache entries + expire + :param key_prefix: A prefix that should be added to all keys. + + """ + + serializer = BaseSerializer() + + def __init__( + self, + client: _t.Any = None, + db: _t.Optional[str] = "cache-db", + collection: _t.Optional[str] = "cache-collection", + default_timeout: int = 300, + key_prefix: _t.Optional[str] = None, + **kwargs: _t.Any + ): + super().__init__(default_timeout) + try: + import pymongo # type: ignore + except ImportError: + logging.warning("no pymongo module found") + + if client is None or isinstance(client, str): + client = pymongo.MongoClient(host=client) + self.client = client[db][collection] + index_info = self.client.index_information() + all_keys = { + subkey[0] for value in index_info.values() for subkey in value["key"] + } + if "id" not in all_keys: + self.client.create_index("id", unique=True) + self.key_prefix = key_prefix or "" + self.collection = collection + + def _utcnow(self) -> _t.Any: + """Return a tz-aware UTC datetime representing the current time""" + return datetime.datetime.utcnow().replace(tzinfo=datetime.timezone.utc) + + def _expire_records(self) -> _t.Any: + res = self.client.delete_many({"expiration": {"$lte": self._utcnow()}}) + return res + + def get(self, key: str) -> _t.Any: + """ + Get a cache item + + :param key: The cache key of the item to fetch + :return: cache value if not expired, else None + """ + self._expire_records() + record = self.client.find_one({"id": self.key_prefix + key}) + value = None + if record: + value = self.serializer.loads(record["val"]) + return value + + def delete(self, key: str) -> bool: + """ + Deletes an item from the cache. This is a no-op if the item doesn't + exist + + :param key: Key of the item to delete. + :return: True if the key existed and was deleted + """ + res = self.client.delete_one({"id": self.key_prefix + key}) + deleted = bool(res.deleted_count > 0) + return deleted + + def _set( + self, + key: str, + value: _t.Any, + timeout: _t.Optional[int] = None, + overwrite: _t.Optional[bool] = True, + ) -> _t.Any: + """ + Store a cache item, with the option to not overwrite existing items + + :param key: Cache key to use + :param value: a serializable object + :param timeout: The timeout in seconds for the cached item, to override + the default + :param overwrite: If true, overwrite any existing cache item with key. + If false, the new value will only be stored if no + non-expired cache item exists with key. + :return: True if the new item was stored. + """ + timeout = self._normalize_timeout(timeout) + now = self._utcnow() + + if not overwrite: + # fail if a non-expired item with this key + # already exists + if self.has(key): + return False + + dump = self.serializer.dumps(value) + record = {"id": self.key_prefix + key, "val": dump} + + if timeout > 0: + record["expiration"] = now + datetime.timedelta(seconds=timeout) + self.client.update_one({"id": self.key_prefix + key}, {"$set": record}, True) + return True + + def set(self, key: str, value: _t.Any, timeout: _t.Optional[int] = None) -> _t.Any: + self._expire_records() + return self._set(key, value, timeout=timeout, overwrite=True) + + def set_many( + self, mapping: _t.Dict[str, _t.Any], timeout: _t.Optional[int] = None + ) -> _t.List[_t.Any]: + self._expire_records() + from pymongo import UpdateOne + + operations = [] + now = self._utcnow() + timeout = self._normalize_timeout(timeout) + for key, val in mapping.items(): + dump = self.serializer.dumps(val) + + record = {"id": self.key_prefix + key, "val": dump} + + if timeout > 0: + record["expiration"] = now + datetime.timedelta(seconds=timeout) + operations.append( + UpdateOne({"id": self.key_prefix + key}, {"$set": record}, upsert=True), + ) + + result = self.client.bulk_write(operations) + keys = list(mapping.keys()) + if result.bulk_api_result["nUpserted"] != len(keys): + query = self.client.find( + {"id": {"$in": [self.key_prefix + key for key in keys]}} + ) + keys = [] + for item in query: + keys.append(item["id"]) + return keys + + def get_many(self, *keys: str) -> _t.List[_t.Any]: + results = self.get_dict(*keys) + values = [] + for key in keys: + values.append(results.get(key, None)) + return values + + def get_dict(self, *keys: str) -> _t.Dict[str, _t.Any]: + self._expire_records() + query = self.client.find( + {"id": {"$in": [self.key_prefix + key for key in keys]}} + ) + results = dict.fromkeys(keys, None) + for item in query: + value = self.serializer.loads(item["val"]) + results[item["id"][len(self.key_prefix) :]] = value + return results + + def add(self, key: str, value: _t.Any, timeout: _t.Optional[int] = None) -> _t.Any: + self._expire_records() + return self._set(key, value, timeout=timeout, overwrite=False) + + def has(self, key: str) -> bool: + self._expire_records() + record = self.get(key) + return record is not None + + def delete_many(self, *keys: str) -> _t.List[_t.Any]: + self._expire_records() + res = list(keys) + filter = {"id": {"$in": [self.key_prefix + key for key in keys]}} + result = self.client.delete_many(filter) + + if result.deleted_count != len(keys): + existing_keys = [ + item["id"][len(self.key_prefix) :] for item in self.client.find(filter) + ] + res = [item for item in keys if item not in existing_keys] + + return res + + def clear(self) -> bool: + self.client.drop() + return True diff --git a/psets/9/finance/env/lib/python3.12/site-packages/cachelib/py.typed b/psets/9/finance/env/lib/python3.12/site-packages/cachelib/py.typed new file mode 100644 index 0000000..e69de29 diff --git a/psets/9/finance/env/lib/python3.12/site-packages/cachelib/redis.py b/psets/9/finance/env/lib/python3.12/site-packages/cachelib/redis.py new file mode 100644 index 0000000..8e38115 --- /dev/null +++ b/psets/9/finance/env/lib/python3.12/site-packages/cachelib/redis.py @@ -0,0 +1,159 @@ +import typing as _t + +from cachelib.base import BaseCache +from cachelib.serializers import RedisSerializer + + +class RedisCache(BaseCache): + """Uses the Redis key-value store as a cache backend. + + The first argument can be either a string denoting address of the Redis + server or an object resembling an instance of a redis.Redis class. + + Note: Python Redis API already takes care of encoding unicode strings on + the fly. + + :param host: address of the Redis server or an object which API is + compatible with the official Python Redis client (redis-py). + :param port: port number on which Redis server listens for connections. + :param password: password authentication for the Redis server. + :param db: db (zero-based numeric index) on Redis Server to connect. + :param default_timeout: the default timeout that is used if no timeout is + specified on :meth:`~BaseCache.set`. A timeout of + 0 indicates that the cache never expires. + :param key_prefix: A prefix that should be added to all keys. + + Any additional keyword arguments will be passed to ``redis.Redis``. + """ + + _read_client: _t.Any = None + _write_client: _t.Any = None + serializer = RedisSerializer() + + def __init__( + self, + host: _t.Any = "localhost", + port: int = 6379, + password: _t.Optional[str] = None, + db: int = 0, + default_timeout: int = 300, + key_prefix: _t.Optional[_t.Union[str, _t.Callable[[], str]]] = None, + **kwargs: _t.Any, + ): + BaseCache.__init__(self, default_timeout) + if host is None: + raise ValueError("RedisCache host parameter may not be None") + if isinstance(host, str): + try: + import redis + except ImportError as err: + raise RuntimeError("no redis module found") from err + if kwargs.get("decode_responses", None): + raise ValueError("decode_responses is not supported by RedisCache.") + self._write_client = self._read_client = redis.Redis( + host=host, port=port, password=password, db=db, **kwargs + ) + else: + self._read_client = self._write_client = host + self.key_prefix = key_prefix or "" + + def _get_prefix(self) -> str: + return ( + self.key_prefix if isinstance(self.key_prefix, str) else self.key_prefix() + ) + + def _normalize_timeout(self, timeout: _t.Optional[int]) -> int: + """Normalize timeout by setting it to default of 300 if + not defined (None) or -1 if explicitly set to zero. + + :param timeout: timeout to normalize. + """ + timeout = BaseCache._normalize_timeout(self, timeout) + if timeout == 0: + timeout = -1 + return timeout + + def get(self, key: str) -> _t.Any: + return self.serializer.loads( + self._read_client.get(f"{self._get_prefix()}{key}") + ) + + def get_many(self, *keys: str) -> _t.List[_t.Any]: + if self.key_prefix: + prefixed_keys = [f"{self._get_prefix()}{key}" for key in keys] + else: + prefixed_keys = list(keys) + return [self.serializer.loads(x) for x in self._read_client.mget(prefixed_keys)] + + def set(self, key: str, value: _t.Any, timeout: _t.Optional[int] = None) -> _t.Any: + timeout = self._normalize_timeout(timeout) + dump = self.serializer.dumps(value) + if timeout == -1: + result = self._write_client.set( + name=f"{self._get_prefix()}{key}", value=dump + ) + else: + result = self._write_client.setex( + name=f"{self._get_prefix()}{key}", value=dump, time=timeout + ) + return result + + def add(self, key: str, value: _t.Any, timeout: _t.Optional[int] = None) -> _t.Any: + timeout = self._normalize_timeout(timeout) + dump = self.serializer.dumps(value) + created = self._write_client.setnx( + name=f"{self._get_prefix()}{key}", value=dump + ) + # handle case where timeout is explicitly set to zero + if created and timeout != -1: + self._write_client.expire(name=f"{self._get_prefix()}{key}", time=timeout) + return created + + def set_many( + self, mapping: _t.Dict[str, _t.Any], timeout: _t.Optional[int] = None + ) -> _t.List[_t.Any]: + timeout = self._normalize_timeout(timeout) + # Use transaction=False to batch without calling redis MULTI + # which is not supported by twemproxy + pipe = self._write_client.pipeline(transaction=False) + + for key, value in mapping.items(): + dump = self.serializer.dumps(value) + if timeout == -1: + pipe.set(name=f"{self._get_prefix()}{key}", value=dump) + else: + pipe.setex(name=f"{self._get_prefix()}{key}", value=dump, time=timeout) + results = pipe.execute() + return [k for k, was_set in zip(mapping.keys(), results) if was_set] + + def delete(self, key: str) -> bool: + return bool(self._write_client.delete(f"{self._get_prefix()}{key}")) + + def delete_many(self, *keys: str) -> _t.List[_t.Any]: + if not keys: + return [] + if self.key_prefix: + prefixed_keys = [f"{self._get_prefix()}{key}" for key in keys] + else: + prefixed_keys = [k for k in keys] + self._write_client.delete(*prefixed_keys) + return [k for k in prefixed_keys if not self.has(k)] + + def has(self, key: str) -> bool: + return bool(self._read_client.exists(f"{self._get_prefix()}{key}")) + + def clear(self) -> bool: + status = 0 + if self.key_prefix: + keys = self._read_client.keys(self._get_prefix() + "*") + if keys: + status = self._write_client.delete(*keys) + else: + status = self._write_client.flushdb() + return bool(status) + + def inc(self, key: str, delta: int = 1) -> _t.Any: + return self._write_client.incr(name=f"{self._get_prefix()}{key}", amount=delta) + + def dec(self, key: str, delta: int = 1) -> _t.Any: + return self._write_client.incr(name=f"{self._get_prefix()}{key}", amount=-delta) diff --git a/psets/9/finance/env/lib/python3.12/site-packages/cachelib/serializers.py b/psets/9/finance/env/lib/python3.12/site-packages/cachelib/serializers.py new file mode 100644 index 0000000..370e4fd --- /dev/null +++ b/psets/9/finance/env/lib/python3.12/site-packages/cachelib/serializers.py @@ -0,0 +1,112 @@ +import logging +import pickle +import typing as _t + + +class BaseSerializer: + """This is the base interface for all default serializers. + + BaseSerializer.load and BaseSerializer.dump will + default to pickle.load and pickle.dump. This is currently + used only by FileSystemCache which dumps/loads to/from a file stream. + """ + + def _warn(self, e: pickle.PickleError) -> None: + logging.warning( + f"An exception has been raised during a pickling operation: {e}" + ) + + def dump( + self, value: int, f: _t.IO, protocol: int = pickle.HIGHEST_PROTOCOL + ) -> None: + try: + pickle.dump(value, f, protocol) + except (pickle.PickleError, pickle.PicklingError) as e: + self._warn(e) + + def load(self, f: _t.BinaryIO) -> _t.Any: + try: + data = pickle.load(f) + except pickle.PickleError as e: + self._warn(e) + return None + else: + return data + + """BaseSerializer.loads and BaseSerializer.dumps + work on top of pickle.loads and pickle.dumps. Dumping/loading + strings and byte strings is the default for most cache types. + """ + + def dumps(self, value: _t.Any, protocol: int = pickle.HIGHEST_PROTOCOL) -> bytes: + try: + serialized = pickle.dumps(value, protocol) + except (pickle.PickleError, pickle.PicklingError) as e: + self._warn(e) + return serialized + + def loads(self, bvalue: bytes) -> _t.Any: + try: + data = pickle.loads(bvalue) + except pickle.PickleError as e: + self._warn(e) + return None + else: + return data + + +"""Default serializers for each cache type. + +The following classes can be used to further customize +serialiation behaviour. Alternatively, any serializer can be +overriden in order to use a custom serializer with a different +strategy altogether. +""" + + +class UWSGISerializer(BaseSerializer): + """Default serializer for UWSGICache.""" + + +class SimpleSerializer(BaseSerializer): + """Default serializer for SimpleCache.""" + + +class FileSystemSerializer(BaseSerializer): + """Default serializer for FileSystemCache.""" + + +class RedisSerializer(BaseSerializer): + """Default serializer for RedisCache.""" + + def dumps(self, value: _t.Any, protocol: int = pickle.HIGHEST_PROTOCOL) -> bytes: + """Dumps an object into a string for redis, using pickle by default.""" + return b"!" + pickle.dumps(value, protocol) + + def loads(self, value: _t.Optional[bytes]) -> _t.Any: + """The reversal of :meth:`dump_object`. This might be called with + None. + """ + if value is None: + return None + if value.startswith(b"!"): + try: + return pickle.loads(value[1:]) + except pickle.PickleError: + return None + try: + return int(value) + except ValueError: + # before 0.8 we did not have serialization. Still support that. + return value + + +class DynamoDbSerializer(RedisSerializer): + """Default serializer for DynamoDbCache.""" + + def loads(self, value: _t.Any) -> _t.Any: + """The reversal of :meth:`dump_object`. This might be called with + None. + """ + value = value.value + return super().loads(value) diff --git a/psets/9/finance/env/lib/python3.12/site-packages/cachelib/simple.py b/psets/9/finance/env/lib/python3.12/site-packages/cachelib/simple.py new file mode 100644 index 0000000..b1b713b --- /dev/null +++ b/psets/9/finance/env/lib/python3.12/site-packages/cachelib/simple.py @@ -0,0 +1,100 @@ +import typing as _t +from time import time + +from cachelib.base import BaseCache +from cachelib.serializers import SimpleSerializer + + +class SimpleCache(BaseCache): + """Simple memory cache for single process environments. This class exists + mainly for the development server and is not 100% thread safe. It tries + to use as many atomic operations as possible and no locks for simplicity + but it could happen under heavy load that keys are added multiple times. + + :param threshold: the maximum number of items the cache stores before + it starts deleting some. + :param default_timeout: the default timeout that is used if no timeout is + specified on :meth:`~BaseCache.set`. A timeout of + 0 indicates that the cache never expires. + """ + + serializer = SimpleSerializer() + + def __init__( + self, + threshold: int = 500, + default_timeout: int = 300, + ): + BaseCache.__init__(self, default_timeout) + self._cache: _t.Dict[str, _t.Any] = {} + self._threshold = threshold or 500 # threshold = 0 + + def _over_threshold(self) -> bool: + return len(self._cache) > self._threshold + + def _remove_expired(self, now: float) -> None: + toremove = [k for k, (expires, _) in self._cache.items() if expires < now] + for k in toremove: + self._cache.pop(k, None) + + def _remove_older(self) -> None: + k_ordered = ( + k for k, v in sorted(self._cache.items(), key=lambda item: item[1][0]) + ) + for k in k_ordered: + self._cache.pop(k, None) + if not self._over_threshold(): + break + + def _prune(self) -> None: + if self._over_threshold(): + now = time() + self._remove_expired(now) + # remove older items if still over threshold + if self._over_threshold(): + self._remove_older() + + def _normalize_timeout(self, timeout: _t.Optional[int]) -> int: + timeout = BaseCache._normalize_timeout(self, timeout) + if timeout > 0: + timeout = int(time()) + timeout + return timeout + + def get(self, key: str) -> _t.Any: + try: + expires, value = self._cache[key] + if expires == 0 or expires > time(): + return self.serializer.loads(value) + except KeyError: + return None + + def set( + self, key: str, value: _t.Any, timeout: _t.Optional[int] = None + ) -> _t.Optional[bool]: + expires = self._normalize_timeout(timeout) + self._prune() + self._cache[key] = (expires, self.serializer.dumps(value)) + return True + + def add(self, key: str, value: _t.Any, timeout: _t.Optional[int] = None) -> bool: + expires = self._normalize_timeout(timeout) + self._prune() + item = (expires, self.serializer.dumps(value)) + if key in self._cache: + return False + self._cache.setdefault(key, item) + return True + + def delete(self, key: str) -> bool: + return self._cache.pop(key, None) is not None + + def has(self, key: str) -> bool: + try: + expires, value = self._cache[key] + return bool(expires == 0 or expires > time()) + except KeyError: + return False + + def clear(self) -> bool: + self._cache.clear() + return not bool(self._cache) diff --git a/psets/9/finance/env/lib/python3.12/site-packages/cachelib/uwsgi.py b/psets/9/finance/env/lib/python3.12/site-packages/cachelib/uwsgi.py new file mode 100644 index 0000000..9d2600c --- /dev/null +++ b/psets/9/finance/env/lib/python3.12/site-packages/cachelib/uwsgi.py @@ -0,0 +1,83 @@ +import platform +import typing as _t + +from cachelib.base import BaseCache +from cachelib.serializers import UWSGISerializer + + +class UWSGICache(BaseCache): + """Implements the cache using uWSGI's caching framework. + + .. note:: + This class cannot be used when running under PyPy, because the uWSGI + API implementation for PyPy is lacking the needed functionality. + + :param default_timeout: The default timeout in seconds. + :param cache: The name of the caching instance to connect to, for + example: mycache@localhost:3031, defaults to an empty string, which + means uWSGI will cache in the local instance. If the cache is in the + same instance as the werkzeug app, you only have to provide the name of + the cache. + """ + + serializer = UWSGISerializer() + + def __init__( + self, + default_timeout: int = 300, + cache: str = "", + ): + BaseCache.__init__(self, default_timeout) + + if platform.python_implementation() == "PyPy": + raise RuntimeError( + "uWSGI caching does not work under PyPy, see " + "the docs for more details." + ) + + try: + import uwsgi # type: ignore + + self._uwsgi = uwsgi + except ImportError as err: + raise RuntimeError( + "uWSGI could not be imported, are you running under uWSGI?" + ) from err + + self.cache = cache + + def get(self, key: str) -> _t.Any: + rv = self._uwsgi.cache_get(key, self.cache) + if rv is None: + return + return self.serializer.loads(rv) + + def delete(self, key: str) -> bool: + return bool(self._uwsgi.cache_del(key, self.cache)) + + def set( + self, key: str, value: _t.Any, timeout: _t.Optional[int] = None + ) -> _t.Optional[bool]: + result = self._uwsgi.cache_update( + key, + self.serializer.dumps(value), + self._normalize_timeout(timeout), + self.cache, + ) # type: bool + return result + + def add(self, key: str, value: _t.Any, timeout: _t.Optional[int] = None) -> bool: + return bool( + self._uwsgi.cache_set( + key, + self.serializer.dumps(value), + self._normalize_timeout(timeout), + self.cache, + ) + ) + + def clear(self) -> bool: + return bool(self._uwsgi.cache_clear(self.cache)) + + def has(self, key: str) -> bool: + return self._uwsgi.cache_exists(key, self.cache) is not None diff --git a/psets/9/finance/env/lib/python3.12/site-packages/certifi-2024.8.30.dist-info/INSTALLER b/psets/9/finance/env/lib/python3.12/site-packages/certifi-2024.8.30.dist-info/INSTALLER new file mode 100644 index 0000000..a1b589e --- /dev/null +++ b/psets/9/finance/env/lib/python3.12/site-packages/certifi-2024.8.30.dist-info/INSTALLER @@ -0,0 +1 @@ +pip diff --git a/psets/9/finance/env/lib/python3.12/site-packages/certifi-2024.8.30.dist-info/LICENSE b/psets/9/finance/env/lib/python3.12/site-packages/certifi-2024.8.30.dist-info/LICENSE new file mode 100644 index 0000000..62b076c --- /dev/null +++ b/psets/9/finance/env/lib/python3.12/site-packages/certifi-2024.8.30.dist-info/LICENSE @@ -0,0 +1,20 @@ +This package contains a modified version of ca-bundle.crt: + +ca-bundle.crt -- Bundle of CA Root Certificates + +This is a bundle of X.509 certificates of public Certificate Authorities +(CA). These were automatically extracted from Mozilla's root certificates +file (certdata.txt). This file can be found in the mozilla source tree: +https://hg.mozilla.org/mozilla-central/file/tip/security/nss/lib/ckfw/builtins/certdata.txt +It contains the certificates in PEM format and therefore +can be directly used with curl / libcurl / php_curl, or with +an Apache+mod_ssl webserver for SSL client authentication. +Just configure this file as the SSLCACertificateFile.# + +***** BEGIN LICENSE BLOCK ***** +This Source Code Form is subject to the terms of the Mozilla Public License, +v. 2.0. If a copy of the MPL was not distributed with this file, You can obtain +one at http://mozilla.org/MPL/2.0/. + +***** END LICENSE BLOCK ***** +@(#) $RCSfile: certdata.txt,v $ $Revision: 1.80 $ $Date: 2011/11/03 15:11:58 $ diff --git a/psets/9/finance/env/lib/python3.12/site-packages/certifi-2024.8.30.dist-info/METADATA b/psets/9/finance/env/lib/python3.12/site-packages/certifi-2024.8.30.dist-info/METADATA new file mode 100644 index 0000000..0a3a772 --- /dev/null +++ b/psets/9/finance/env/lib/python3.12/site-packages/certifi-2024.8.30.dist-info/METADATA @@ -0,0 +1,67 @@ +Metadata-Version: 2.1 +Name: certifi +Version: 2024.8.30 +Summary: Python package for providing Mozilla's CA Bundle. +Home-page: https://github.com/certifi/python-certifi +Author: Kenneth Reitz +Author-email: me@kennethreitz.com +License: MPL-2.0 +Project-URL: Source, https://github.com/certifi/python-certifi +Classifier: Development Status :: 5 - Production/Stable +Classifier: Intended Audience :: Developers +Classifier: License :: OSI Approved :: Mozilla Public License 2.0 (MPL 2.0) +Classifier: Natural Language :: English +Classifier: Programming Language :: Python +Classifier: Programming Language :: Python :: 3 +Classifier: Programming Language :: Python :: 3 :: Only +Classifier: Programming Language :: Python :: 3.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 +Requires-Python: >=3.6 +License-File: LICENSE + +Certifi: Python SSL Certificates +================================ + +Certifi provides Mozilla's carefully curated collection of Root Certificates for +validating the trustworthiness of SSL certificates while verifying the identity +of TLS hosts. It has been extracted from the `Requests`_ project. + +Installation +------------ + +``certifi`` is available on PyPI. Simply install it with ``pip``:: + + $ pip install certifi + +Usage +----- + +To reference the installed certificate authority (CA) bundle, you can use the +built-in function:: + + >>> import certifi + + >>> certifi.where() + '/usr/local/lib/python3.7/site-packages/certifi/cacert.pem' + +Or from the command line:: + + $ python -m certifi + /usr/local/lib/python3.7/site-packages/certifi/cacert.pem + +Enjoy! + +.. _`Requests`: https://requests.readthedocs.io/en/master/ + +Addition/Removal of Certificates +-------------------------------- + +Certifi does not support any addition/removal or other modification of the +CA trust store content. This project is intended to provide a reliable and +highly portable root of trust to python deployments. Look to upstream projects +for methods to use alternate trust. diff --git a/psets/9/finance/env/lib/python3.12/site-packages/certifi-2024.8.30.dist-info/RECORD b/psets/9/finance/env/lib/python3.12/site-packages/certifi-2024.8.30.dist-info/RECORD new file mode 100644 index 0000000..88c23e6 --- /dev/null +++ b/psets/9/finance/env/lib/python3.12/site-packages/certifi-2024.8.30.dist-info/RECORD @@ -0,0 +1,14 @@ +certifi-2024.8.30.dist-info/INSTALLER,sha256=zuuue4knoyJ-UwPPXg8fezS7VCrXJQrAP7zeNuwvFQg,4 +certifi-2024.8.30.dist-info/LICENSE,sha256=6TcW2mucDVpKHfYP5pWzcPBpVgPSH2-D8FPkLPwQyvc,989 +certifi-2024.8.30.dist-info/METADATA,sha256=GhBHRVUN6a4ZdUgE_N5wmukJfyuoE-QyIl8Y3ifNQBM,2222 +certifi-2024.8.30.dist-info/RECORD,, +certifi-2024.8.30.dist-info/WHEEL,sha256=UvcQYKBHoFqaQd6LKyqHw9fxEolWLQnlzP0h_LgJAfI,91 +certifi-2024.8.30.dist-info/top_level.txt,sha256=KMu4vUCfsjLrkPbSNdgdekS-pVJzBAJFO__nI8NF6-U,8 +certifi/__init__.py,sha256=p_GYZrjUwPBUhpLlCZoGb0miKBKSqDAyZC5DvIuqbHQ,94 +certifi/__main__.py,sha256=xBBoj905TUWBLRGANOcf7oi6e-3dMP4cEoG9OyMs11g,243 +certifi/__pycache__/__init__.cpython-312.pyc,, +certifi/__pycache__/__main__.cpython-312.pyc,, +certifi/__pycache__/core.cpython-312.pyc,, +certifi/cacert.pem,sha256=lO3rZukXdPyuk6BWUJFOKQliWaXH6HGh9l1GGrUgG0c,299427 +certifi/core.py,sha256=qRDDFyXVJwTB_EmoGppaXU_R9qCZvhl-EzxPMuV3nTA,4426 +certifi/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0 diff --git a/psets/9/finance/env/lib/python3.12/site-packages/certifi-2024.8.30.dist-info/WHEEL b/psets/9/finance/env/lib/python3.12/site-packages/certifi-2024.8.30.dist-info/WHEEL new file mode 100644 index 0000000..57e56b7 --- /dev/null +++ b/psets/9/finance/env/lib/python3.12/site-packages/certifi-2024.8.30.dist-info/WHEEL @@ -0,0 +1,5 @@ +Wheel-Version: 1.0 +Generator: setuptools (74.0.0) +Root-Is-Purelib: true +Tag: py3-none-any + diff --git a/psets/9/finance/env/lib/python3.12/site-packages/certifi-2024.8.30.dist-info/top_level.txt b/psets/9/finance/env/lib/python3.12/site-packages/certifi-2024.8.30.dist-info/top_level.txt new file mode 100644 index 0000000..963eac5 --- /dev/null +++ b/psets/9/finance/env/lib/python3.12/site-packages/certifi-2024.8.30.dist-info/top_level.txt @@ -0,0 +1 @@ +certifi diff --git a/psets/9/finance/env/lib/python3.12/site-packages/certifi/__init__.py b/psets/9/finance/env/lib/python3.12/site-packages/certifi/__init__.py new file mode 100644 index 0000000..f61d77f --- /dev/null +++ b/psets/9/finance/env/lib/python3.12/site-packages/certifi/__init__.py @@ -0,0 +1,4 @@ +from .core import contents, where + +__all__ = ["contents", "where"] +__version__ = "2024.08.30" diff --git a/psets/9/finance/env/lib/python3.12/site-packages/certifi/__main__.py b/psets/9/finance/env/lib/python3.12/site-packages/certifi/__main__.py new file mode 100644 index 0000000..8945b5d --- /dev/null +++ b/psets/9/finance/env/lib/python3.12/site-packages/certifi/__main__.py @@ -0,0 +1,12 @@ +import argparse + +from certifi import contents, where + +parser = argparse.ArgumentParser() +parser.add_argument("-c", "--contents", action="store_true") +args = parser.parse_args() + +if args.contents: + print(contents()) +else: + print(where()) diff --git a/psets/9/finance/env/lib/python3.12/site-packages/certifi/__pycache__/__init__.cpython-312.pyc b/psets/9/finance/env/lib/python3.12/site-packages/certifi/__pycache__/__init__.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..df09190116321eaa53131f0cb522a46ca040381d GIT binary patch literal 315 zcmYjMJxjzu5Z%p(cP5;j2sUb&!c5F5D2SD{y%AjE?p|&&*@WHoj+~AD13Q0%zs1H< z(kNKj3D;S<0R><2=FPnMV4g>#09kz8o)?#W?2|t@zhb#<#Uo;f;SyCi!Z)Rz9(9i=1vqYiYPNy7T8#uDEh-U3r!kL7JrdadH@sle5V0JX-&^y8$72 zSrXEPgv_|oqLzd_p`{%~-xp9x1E;xN4YX!L7C`ku0*&TI!x2n`%q8W(TD9H}^TJe* literal 0 HcmV?d00001 diff --git a/psets/9/finance/env/lib/python3.12/site-packages/certifi/__pycache__/__main__.cpython-312.pyc b/psets/9/finance/env/lib/python3.12/site-packages/certifi/__pycache__/__main__.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..303fc95370ab8028c1635ee208ce7f4868aadfab GIT binary patch literal 630 zcmZuuO=}b}7*6JU2DcR#VezymqAPCW2Ofl05PB{ibv+Dml1{VkWQHWGZ1qqCQR&5- z{sd+HCth4y*%~hu58_Se&6CM?r+YDwyicCzdEdNAJ~tW(FyrU52l zcn1g|Z~%HXIs;fZJ*RMcE(8vspdZyqi#VRco=^RLW5L&mxWps=r(oC mt-bKvj(6yWuhw3yee>csmv^sx_0Ik<=;H3BmmA`=DgF;*@|pGk literal 0 HcmV?d00001 diff --git a/psets/9/finance/env/lib/python3.12/site-packages/certifi/__pycache__/core.cpython-312.pyc b/psets/9/finance/env/lib/python3.12/site-packages/certifi/__pycache__/core.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..c55411f20629d25710b8c582362dc1d236ea4e96 GIT binary patch literal 3191 zcmbVO&2JmW6`%bgmlVmBM2ey<*CG@-B^(gNogyh0I}U&NlTMl zc4iz|j#B85gMG4!6txaPp+gTgoI{TJ69S|M(M&*N;{pa6An=U=4FvG1?=5#JN>L8& zBj&xw*_qjy-}}8c`(->HB_RL#U~&1K0kHTdkUrmO|3)C>9x+LQn1U&mg@WK&u^^gh zQ~pRUNS07igK4|gRIdM#5PAqkhssJNR0vhVg|I+OQCFcwOv#EaiDnp9=<|IQ{MefK z6YE8~>qTL`cp*{I3fhm>>+4xB)>+TnZ-1fRvjc?zu<`O>C0R%c#7bHNrIWk64m{l3 zA^1}mf)PfMAiW(N> z_L4nOTZ{gsE79n}ip{bW$GlOtvee=?Xq9F8ij}pijO*pH&TXffEjvcXah9@%jw?;n ztV-6QS(~%0;Z(U*Nl^C)2i=hp_U;oC!fuj>{u6<$ zk(@A_6WzYz^o8lS=N5|73x9CcV$r&3^J4JBUGyQ)_WD{ocb&zJ2#Ffx}4ccZSn1eujNw|d6^TR;R&80qha%5ofVhtvgInM znE}0B>7w&5=;}phW0809;W)|@Q+No;fl>;0Y_B%O;AvoWnFnb_csFHA@!nY-|DoU2 zok_SBj4Jg9-mc|?fgj8edSW|I9!Rrp*vIolbeB81s2dA{dF{f&Wr};D2~e(Da_nkN z=PMM?>q?AMHv+K+lF?$(4MBV%?5;|!Wt%~t7Y&Lyc&O6|&QexaENW5Aq#WAu&2 z$eXukp2P<4UcGbmldE6FPJgS7?5HE&oAyKyqlB&fJ5UfoKRyJCSAficOz+03)Qv7I z;EO4JDhIOxOJ$ZqwImcVcNLu(w*5eGRjb-zdrtBIq)19PLM`1a0#tlIG-{BqGz$YK zps|-h0gbiP=3+w|ZE7d$+R6Jz8rmC8?R;H3|HX+N?R-O<+fnCyVpF8kGsGN-EqlQl zg+F@`k)gvw6ir$WGk*U5+Sx_nSR1fvbnzaf0)2yo_?$Qi|M1bEKxhXA@RUs$N z(x1WmbCN4NHLL2y$dxfYath7C6M702o`Svt%9Tx>>kQ$}qId% zG5ELRAD`I1{B?Z%v()3{@V%+OPJMjt2Z+RqBUzI*nrosm&$ZZ(W zn;<3sSkT>-gW%u@uqOenKkO;K2d;8JGOc5Y^4~ZQ`8?~@mz?5?4x?kRyc;%cTGcBS zUb%R8K^2y>CPpufL?CIj^7r()duda-dVl7 zerJ8_!q$32JH4Zx{&7Y9U-?e4iv1+p|BMeYY(WJ>V!}7YE#(GZ8h^_T!8KzWJU8ry zi$&8h;EWPmW1XbOe0O8-Ta-aQ6z%Gg<0kD&&7mB=BPN1GV7r%?cXfH?q*FgUV6ymj z1e6{_^dOmAEP z{%*{)`eZ4`f;r*r$VsTMAg%LNeV7qo None: + _CACERT_CTX.__exit__(None, None, None) # type: ignore[union-attr] + + +if sys.version_info >= (3, 11): + + from importlib.resources import as_file, files + + _CACERT_CTX = None + _CACERT_PATH = None + + def where() -> str: + # This is slightly terrible, but we want to delay extracting the file + # in cases where we're inside of a zipimport situation until someone + # actually calls where(), but we don't want to re-extract the file + # on every call of where(), so we'll do it once then store it in a + # global variable. + global _CACERT_CTX + global _CACERT_PATH + if _CACERT_PATH is None: + # This is slightly janky, the importlib.resources API wants you to + # manage the cleanup of this file, so it doesn't actually return a + # path, it returns a context manager that will give you the path + # when you enter it and will do any cleanup when you leave it. In + # the common case of not needing a temporary file, it will just + # return the file system location and the __exit__() is a no-op. + # + # We also have to hold onto the actual context manager, because + # it will do the cleanup whenever it gets garbage collected, so + # we will also store that at the global level as well. + _CACERT_CTX = as_file(files("certifi").joinpath("cacert.pem")) + _CACERT_PATH = str(_CACERT_CTX.__enter__()) + atexit.register(exit_cacert_ctx) + + return _CACERT_PATH + + def contents() -> str: + return files("certifi").joinpath("cacert.pem").read_text(encoding="ascii") + +elif sys.version_info >= (3, 7): + + from importlib.resources import path as get_path, read_text + + _CACERT_CTX = None + _CACERT_PATH = None + + def where() -> str: + # This is slightly terrible, but we want to delay extracting the + # file in cases where we're inside of a zipimport situation until + # someone actually calls where(), but we don't want to re-extract + # the file on every call of where(), so we'll do it once then store + # it in a global variable. + global _CACERT_CTX + global _CACERT_PATH + if _CACERT_PATH is None: + # This is slightly janky, the importlib.resources API wants you + # to manage the cleanup of this file, so it doesn't actually + # return a path, it returns a context manager that will give + # you the path when you enter it and will do any cleanup when + # you leave it. In the common case of not needing a temporary + # file, it will just return the file system location and the + # __exit__() is a no-op. + # + # We also have to hold onto the actual context manager, because + # it will do the cleanup whenever it gets garbage collected, so + # we will also store that at the global level as well. + _CACERT_CTX = get_path("certifi", "cacert.pem") + _CACERT_PATH = str(_CACERT_CTX.__enter__()) + atexit.register(exit_cacert_ctx) + + return _CACERT_PATH + + def contents() -> str: + return read_text("certifi", "cacert.pem", encoding="ascii") + +else: + import os + import types + from typing import Union + + Package = Union[types.ModuleType, str] + Resource = Union[str, "os.PathLike"] + + # This fallback will work for Python versions prior to 3.7 that lack the + # importlib.resources module but relies on the existing `where` function + # so won't address issues with environments like PyOxidizer that don't set + # __file__ on modules. + def read_text( + package: Package, + resource: Resource, + encoding: str = 'utf-8', + errors: str = 'strict' + ) -> str: + with open(where(), encoding=encoding) as data: + return data.read() + + # If we don't have importlib.resources, then we will just do the old logic + # of assuming we're on the filesystem and munge the path directly. + def where() -> str: + f = os.path.dirname(__file__) + + return os.path.join(f, "cacert.pem") + + def contents() -> str: + return read_text("certifi", "cacert.pem", encoding="ascii") diff --git a/psets/9/finance/env/lib/python3.12/site-packages/certifi/py.typed b/psets/9/finance/env/lib/python3.12/site-packages/certifi/py.typed new file mode 100644 index 0000000..e69de29 diff --git a/psets/9/finance/env/lib/python3.12/site-packages/charset_normalizer-3.4.0.dist-info/INSTALLER b/psets/9/finance/env/lib/python3.12/site-packages/charset_normalizer-3.4.0.dist-info/INSTALLER new file mode 100644 index 0000000..a1b589e --- /dev/null +++ b/psets/9/finance/env/lib/python3.12/site-packages/charset_normalizer-3.4.0.dist-info/INSTALLER @@ -0,0 +1 @@ +pip diff --git a/psets/9/finance/env/lib/python3.12/site-packages/charset_normalizer-3.4.0.dist-info/LICENSE b/psets/9/finance/env/lib/python3.12/site-packages/charset_normalizer-3.4.0.dist-info/LICENSE new file mode 100644 index 0000000..ad82355 --- /dev/null +++ b/psets/9/finance/env/lib/python3.12/site-packages/charset_normalizer-3.4.0.dist-info/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2019 TAHRI Ahmed R. + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. \ No newline at end of file diff --git a/psets/9/finance/env/lib/python3.12/site-packages/charset_normalizer-3.4.0.dist-info/METADATA b/psets/9/finance/env/lib/python3.12/site-packages/charset_normalizer-3.4.0.dist-info/METADATA new file mode 100644 index 0000000..b19096b --- /dev/null +++ b/psets/9/finance/env/lib/python3.12/site-packages/charset_normalizer-3.4.0.dist-info/METADATA @@ -0,0 +1,695 @@ +Metadata-Version: 2.1 +Name: charset-normalizer +Version: 3.4.0 +Summary: The Real First Universal Charset Detector. Open, modern and actively maintained alternative to Chardet. +Home-page: https://github.com/Ousret/charset_normalizer +Author: Ahmed TAHRI +Author-email: tahri.ahmed@proton.me +License: MIT +Project-URL: Bug Reports, https://github.com/Ousret/charset_normalizer/issues +Project-URL: Documentation, https://charset-normalizer.readthedocs.io/en/latest +Keywords: encoding,charset,charset-detector,detector,normalization,unicode,chardet,detect +Classifier: Development Status :: 5 - Production/Stable +Classifier: License :: OSI Approved :: MIT License +Classifier: Intended Audience :: Developers +Classifier: Topic :: Software Development :: Libraries :: Python Modules +Classifier: Operating System :: OS Independent +Classifier: Programming Language :: Python +Classifier: Programming Language :: Python :: 3 +Classifier: Programming Language :: Python :: 3.7 +Classifier: Programming Language :: Python :: 3.8 +Classifier: Programming Language :: Python :: 3.9 +Classifier: Programming Language :: Python :: 3.10 +Classifier: Programming Language :: Python :: 3.11 +Classifier: Programming Language :: Python :: 3.12 +Classifier: Programming Language :: Python :: 3.13 +Classifier: Programming Language :: Python :: Implementation :: PyPy +Classifier: Topic :: Text Processing :: Linguistic +Classifier: Topic :: Utilities +Classifier: Typing :: Typed +Requires-Python: >=3.7.0 +Description-Content-Type: text/markdown +License-File: LICENSE +Provides-Extra: unicode_backport + +

Charset Detection, for Everyone 👋

+ +

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

+

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

+

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

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

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

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

+Reading Normalized TextCat Reading Text +

+ +*\*\* : They are clearly using specific code for a specific encoding even if covering most of used one*
+Did you got there because of the logs? See [https://charset-normalizer.readthedocs.io/en/latest/user/miscellaneous.html](https://charset-normalizer.readthedocs.io/en/latest/user/miscellaneous.html) + +## ⚡ Performance + +This package offer better performance than its counterpart Chardet. Here are some numbers. + +| Package | Accuracy | Mean per file (ms) | File per sec (est) | +|-----------------------------------------------|:--------:|:------------------:|:------------------:| +| [chardet](https://github.com/chardet/chardet) | 86 % | 200 ms | 5 file/sec | +| charset-normalizer | **98 %** | **10 ms** | 100 file/sec | + +| Package | 99th percentile | 95th percentile | 50th percentile | +|-----------------------------------------------|:---------------:|:---------------:|:---------------:| +| [chardet](https://github.com/chardet/chardet) | 1200 ms | 287 ms | 23 ms | +| charset-normalizer | 100 ms | 50 ms | 5 ms | + +Chardet's performance on larger file (1MB+) are very poor. Expect huge difference on large payload. + +> Stats are generated using 400+ files using default parameters. More details on used files, see GHA workflows. +> And yes, these results might change at any time. The dataset can be updated to include more files. +> The actual delays heavily depends on your CPU capabilities. The factors should remain the same. +> Keep in mind that the stats are generous and that Chardet accuracy vs our is measured using Chardet initial capability +> (eg. Supported Encoding) Challenge-them if you want. + +## ✨ Installation + +Using pip: + +```sh +pip install charset-normalizer -U +``` + +## 🚀 Basic Usage + +### CLI +This package comes with a CLI. + +``` +usage: normalizer [-h] [-v] [-a] [-n] [-m] [-r] [-f] [-t THRESHOLD] + file [file ...] + +The Real First Universal Charset Detector. Discover originating encoding used +on text file. Normalize text to unicode. + +positional arguments: + files File(s) to be analysed + +optional arguments: + -h, --help show this help message and exit + -v, --verbose Display complementary information about file if any. + Stdout will contain logs about the detection process. + -a, --with-alternative + Output complementary possibilities if any. Top-level + JSON WILL be a list. + -n, --normalize Permit to normalize input file. If not set, program + does not write anything. + -m, --minimal Only output the charset detected to STDOUT. Disabling + JSON output. + -r, --replace Replace file when trying to normalize it instead of + creating a new one. + -f, --force Replace file without asking if you are sure, use this + flag with caution. + -t THRESHOLD, --threshold THRESHOLD + Define a custom maximum amount of chaos allowed in + decoded content. 0. <= chaos <= 1. + --version Show version information and exit. +``` + +```bash +normalizer ./data/sample.1.fr.srt +``` + +or + +```bash +python -m charset_normalizer ./data/sample.1.fr.srt +``` + +🎉 Since version 1.4.0 the CLI produce easily usable stdout result in JSON format. + +```json +{ + "path": "/home/default/projects/charset_normalizer/data/sample.1.fr.srt", + "encoding": "cp1252", + "encoding_aliases": [ + "1252", + "windows_1252" + ], + "alternative_encodings": [ + "cp1254", + "cp1256", + "cp1258", + "iso8859_14", + "iso8859_15", + "iso8859_16", + "iso8859_3", + "iso8859_9", + "latin_1", + "mbcs" + ], + "language": "French", + "alphabets": [ + "Basic Latin", + "Latin-1 Supplement" + ], + "has_sig_or_bom": false, + "chaos": 0.149, + "coherence": 97.152, + "unicode_path": null, + "is_preferred": true +} +``` + +### Python +*Just print out normalized text* +```python +from charset_normalizer import from_path + +results = from_path('./my_subtitle.srt') + +print(str(results.best())) +``` + +*Upgrade your code without effort* +```python +from charset_normalizer import detect +``` + +The above code will behave the same as **chardet**. We ensure that we offer the best (reasonable) BC result possible. + +See the docs for advanced usage : [readthedocs.io](https://charset-normalizer.readthedocs.io/en/latest/) + +## 😇 Why + +When I started using Chardet, I noticed that it was not suited to my expectations, and I wanted to propose a +reliable alternative using a completely different method. Also! I never back down on a good challenge! + +I **don't care** about the **originating charset** encoding, because **two different tables** can +produce **two identical rendered string.** +What I want is to get readable text, the best I can. + +In a way, **I'm brute forcing text decoding.** How cool is that ? 😎 + +Don't confuse package **ftfy** with charset-normalizer or chardet. ftfy goal is to repair unicode string whereas charset-normalizer to convert raw file in unknown encoding to unicode. + +## 🍰 How + + - Discard all charset encoding table that could not fit the binary content. + - Measure noise, or the mess once opened (by chunks) with a corresponding charset encoding. + - Extract matches with the lowest mess detected. + - Additionally, we measure coherence / probe for a language. + +**Wait a minute**, what is noise/mess and coherence according to **YOU ?** + +*Noise :* I opened hundred of text files, **written by humans**, with the wrong encoding table. **I observed**, then +**I established** some ground rules about **what is obvious** when **it seems like** a mess. + I know that my interpretation of what is noise is probably incomplete, feel free to contribute in order to + improve or rewrite it. + +*Coherence :* For each language there is on earth, we have computed ranked letter appearance occurrences (the best we can). So I thought +that intel is worth something here. So I use those records against decoded text to check if I can detect intelligent design. + +## ⚡ Known limitations + + - Language detection is unreliable when text contains two or more languages sharing identical letters. (eg. HTML (english tags) + Turkish content (Sharing Latin characters)) + - Every charset detector heavily depends on sufficient content. In common cases, do not bother run detection on very tiny content. + +## ⚠️ About Python EOLs + +**If you are running:** + +- Python >=2.7,<3.5: Unsupported +- Python 3.5: charset-normalizer < 2.1 +- Python 3.6: charset-normalizer < 3.1 +- Python 3.7: charset-normalizer < 4.0 + +Upgrade your Python interpreter as soon as possible. + +## 👤 Contributing + +Contributions, issues and feature requests are very much welcome.
+Feel free to check [issues page](https://github.com/ousret/charset_normalizer/issues) if you want to contribute. + +## 📝 License + +Copyright © [Ahmed TAHRI @Ousret](https://github.com/Ousret).
+This project is [MIT](https://github.com/Ousret/charset_normalizer/blob/master/LICENSE) licensed. + +Characters frequencies used in this project © 2012 [Denny Vrandečić](http://simia.net/letters/) + +## 💼 For Enterprise + +Professional support for charset-normalizer is available as part of the [Tidelift +Subscription][1]. Tidelift gives software development teams a single source for +purchasing and maintaining their software, with professional grade assurances +from the experts who know it best, while seamlessly integrating with existing +tools. + +[1]: https://tidelift.com/subscription/pkg/pypi-charset-normalizer?utm_source=pypi-charset-normalizer&utm_medium=readme + +# Changelog +All notable changes to charset-normalizer will be documented in this file. This project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). +The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/). + +## [3.4.0](https://github.com/Ousret/charset_normalizer/compare/3.3.2...3.4.0) (2024-10-08) + +### Added +- Argument `--no-preemptive` in the CLI to prevent the detector to search for hints. +- Support for Python 3.13 (#512) + +### Fixed +- Relax the TypeError exception thrown when trying to compare a CharsetMatch with anything else than a CharsetMatch. +- Improved the general reliability of the detector based on user feedbacks. (#520) (#509) (#498) (#407) (#537) +- Declared charset in content (preemptive detection) not changed when converting to utf-8 bytes. (#381) + +## [3.3.2](https://github.com/Ousret/charset_normalizer/compare/3.3.1...3.3.2) (2023-10-31) + +### Fixed +- Unintentional memory usage regression when using large payload that match several encoding (#376) +- Regression on some detection case showcased in the documentation (#371) + +### Added +- Noise (md) probe that identify malformed arabic representation due to the presence of letters in isolated form (credit to my wife) + +## [3.3.1](https://github.com/Ousret/charset_normalizer/compare/3.3.0...3.3.1) (2023-10-22) + +### Changed +- Optional mypyc compilation upgraded to version 1.6.1 for Python >= 3.8 +- Improved the general detection reliability based on reports from the community + +## [3.3.0](https://github.com/Ousret/charset_normalizer/compare/3.2.0...3.3.0) (2023-09-30) + +### Added +- Allow to execute the CLI (e.g. normalizer) through `python -m charset_normalizer.cli` or `python -m charset_normalizer` +- Support for 9 forgotten encoding that are supported by Python but unlisted in `encoding.aliases` as they have no alias (#323) + +### Removed +- (internal) Redundant utils.is_ascii function and unused function is_private_use_only +- (internal) charset_normalizer.assets is moved inside charset_normalizer.constant + +### Changed +- (internal) Unicode code blocks in constants are updated using the latest v15.0.0 definition to improve detection +- Optional mypyc compilation upgraded to version 1.5.1 for Python >= 3.8 + +### Fixed +- Unable to properly sort CharsetMatch when both chaos/noise and coherence were close due to an unreachable condition in \_\_lt\_\_ (#350) + +## [3.2.0](https://github.com/Ousret/charset_normalizer/compare/3.1.0...3.2.0) (2023-06-07) + +### Changed +- Typehint for function `from_path` no longer enforce `PathLike` as its first argument +- Minor improvement over the global detection reliability + +### Added +- Introduce function `is_binary` that relies on main capabilities, and optimized to detect binaries +- Propagate `enable_fallback` argument throughout `from_bytes`, `from_path`, and `from_fp` that allow a deeper control over the detection (default True) +- Explicit support for Python 3.12 + +### Fixed +- Edge case detection failure where a file would contain 'very-long' camel cased word (Issue #289) + +## [3.1.0](https://github.com/Ousret/charset_normalizer/compare/3.0.1...3.1.0) (2023-03-06) + +### Added +- Argument `should_rename_legacy` for legacy function `detect` and disregard any new arguments without errors (PR #262) + +### Removed +- Support for Python 3.6 (PR #260) + +### Changed +- Optional speedup provided by mypy/c 1.0.1 + +## [3.0.1](https://github.com/Ousret/charset_normalizer/compare/3.0.0...3.0.1) (2022-11-18) + +### Fixed +- Multi-bytes cutter/chunk generator did not always cut correctly (PR #233) + +### Changed +- Speedup provided by mypy/c 0.990 on Python >= 3.7 + +## [3.0.0](https://github.com/Ousret/charset_normalizer/compare/2.1.1...3.0.0) (2022-10-20) + +### Added +- Extend the capability of explain=True when cp_isolation contains at most two entries (min one), will log in details of the Mess-detector results +- Support for alternative language frequency set in charset_normalizer.assets.FREQUENCIES +- Add parameter `language_threshold` in `from_bytes`, `from_path` and `from_fp` to adjust the minimum expected coherence ratio +- `normalizer --version` now specify if current version provide extra speedup (meaning mypyc compilation whl) + +### Changed +- Build with static metadata using 'build' frontend +- Make the language detection stricter +- Optional: Module `md.py` can be compiled using Mypyc to provide an extra speedup up to 4x faster than v2.1 + +### Fixed +- CLI with opt --normalize fail when using full path for files +- TooManyAccentuatedPlugin induce false positive on the mess detection when too few alpha character have been fed to it +- Sphinx warnings when generating the documentation + +### Removed +- Coherence detector no longer return 'Simple English' instead return 'English' +- Coherence detector no longer return 'Classical Chinese' instead return 'Chinese' +- Breaking: Method `first()` and `best()` from CharsetMatch +- UTF-7 will no longer appear as "detected" without a recognized SIG/mark (is unreliable/conflict with ASCII) +- Breaking: Class aliases CharsetDetector, CharsetDoctor, CharsetNormalizerMatch and CharsetNormalizerMatches +- Breaking: Top-level function `normalize` +- Breaking: Properties `chaos_secondary_pass`, `coherence_non_latin` and `w_counter` from CharsetMatch +- Support for the backport `unicodedata2` + +## [3.0.0rc1](https://github.com/Ousret/charset_normalizer/compare/3.0.0b2...3.0.0rc1) (2022-10-18) + +### Added +- Extend the capability of explain=True when cp_isolation contains at most two entries (min one), will log in details of the Mess-detector results +- Support for alternative language frequency set in charset_normalizer.assets.FREQUENCIES +- Add parameter `language_threshold` in `from_bytes`, `from_path` and `from_fp` to adjust the minimum expected coherence ratio + +### Changed +- Build with static metadata using 'build' frontend +- Make the language detection stricter + +### Fixed +- CLI with opt --normalize fail when using full path for files +- TooManyAccentuatedPlugin induce false positive on the mess detection when too few alpha character have been fed to it + +### Removed +- Coherence detector no longer return 'Simple English' instead return 'English' +- Coherence detector no longer return 'Classical Chinese' instead return 'Chinese' + +## [3.0.0b2](https://github.com/Ousret/charset_normalizer/compare/3.0.0b1...3.0.0b2) (2022-08-21) + +### Added +- `normalizer --version` now specify if current version provide extra speedup (meaning mypyc compilation whl) + +### Removed +- Breaking: Method `first()` and `best()` from CharsetMatch +- UTF-7 will no longer appear as "detected" without a recognized SIG/mark (is unreliable/conflict with ASCII) + +### Fixed +- Sphinx warnings when generating the documentation + +## [3.0.0b1](https://github.com/Ousret/charset_normalizer/compare/2.1.0...3.0.0b1) (2022-08-15) + +### Changed +- Optional: Module `md.py` can be compiled using Mypyc to provide an extra speedup up to 4x faster than v2.1 + +### Removed +- Breaking: Class aliases CharsetDetector, CharsetDoctor, CharsetNormalizerMatch and CharsetNormalizerMatches +- Breaking: Top-level function `normalize` +- Breaking: Properties `chaos_secondary_pass`, `coherence_non_latin` and `w_counter` from CharsetMatch +- Support for the backport `unicodedata2` + +## [2.1.1](https://github.com/Ousret/charset_normalizer/compare/2.1.0...2.1.1) (2022-08-19) + +### Deprecated +- Function `normalize` scheduled for removal in 3.0 + +### Changed +- Removed useless call to decode in fn is_unprintable (#206) + +### Fixed +- Third-party library (i18n xgettext) crashing not recognizing utf_8 (PEP 263) with underscore from [@aleksandernovikov](https://github.com/aleksandernovikov) (#204) + +## [2.1.0](https://github.com/Ousret/charset_normalizer/compare/2.0.12...2.1.0) (2022-06-19) + +### Added +- Output the Unicode table version when running the CLI with `--version` (PR #194) + +### Changed +- Re-use decoded buffer for single byte character sets from [@nijel](https://github.com/nijel) (PR #175) +- Fixing some performance bottlenecks from [@deedy5](https://github.com/deedy5) (PR #183) + +### Fixed +- Workaround potential bug in cpython with Zero Width No-Break Space located in Arabic Presentation Forms-B, Unicode 1.1 not acknowledged as space (PR #175) +- CLI default threshold aligned with the API threshold from [@oleksandr-kuzmenko](https://github.com/oleksandr-kuzmenko) (PR #181) + +### Removed +- Support for Python 3.5 (PR #192) + +### Deprecated +- Use of backport unicodedata from `unicodedata2` as Python is quickly catching up, scheduled for removal in 3.0 (PR #194) + +## [2.0.12](https://github.com/Ousret/charset_normalizer/compare/2.0.11...2.0.12) (2022-02-12) + +### Fixed +- ASCII miss-detection on rare cases (PR #170) + +## [2.0.11](https://github.com/Ousret/charset_normalizer/compare/2.0.10...2.0.11) (2022-01-30) + +### Added +- Explicit support for Python 3.11 (PR #164) + +### Changed +- The logging behavior have been completely reviewed, now using only TRACE and DEBUG levels (PR #163 #165) + +## [2.0.10](https://github.com/Ousret/charset_normalizer/compare/2.0.9...2.0.10) (2022-01-04) + +### Fixed +- Fallback match entries might lead to UnicodeDecodeError for large bytes sequence (PR #154) + +### Changed +- Skipping the language-detection (CD) on ASCII (PR #155) + +## [2.0.9](https://github.com/Ousret/charset_normalizer/compare/2.0.8...2.0.9) (2021-12-03) + +### Changed +- Moderating the logging impact (since 2.0.8) for specific environments (PR #147) + +### Fixed +- Wrong logging level applied when setting kwarg `explain` to True (PR #146) + +## [2.0.8](https://github.com/Ousret/charset_normalizer/compare/2.0.7...2.0.8) (2021-11-24) +### Changed +- Improvement over Vietnamese detection (PR #126) +- MD improvement on trailing data and long foreign (non-pure latin) data (PR #124) +- Efficiency improvements in cd/alphabet_languages from [@adbar](https://github.com/adbar) (PR #122) +- call sum() without an intermediary list following PEP 289 recommendations from [@adbar](https://github.com/adbar) (PR #129) +- Code style as refactored by Sourcery-AI (PR #131) +- Minor adjustment on the MD around european words (PR #133) +- Remove and replace SRTs from assets / tests (PR #139) +- Initialize the library logger with a `NullHandler` by default from [@nmaynes](https://github.com/nmaynes) (PR #135) +- Setting kwarg `explain` to True will add provisionally (bounded to function lifespan) a specific stream handler (PR #135) + +### Fixed +- Fix large (misleading) sequence giving UnicodeDecodeError (PR #137) +- Avoid using too insignificant chunk (PR #137) + +### Added +- Add and expose function `set_logging_handler` to configure a specific StreamHandler from [@nmaynes](https://github.com/nmaynes) (PR #135) +- Add `CHANGELOG.md` entries, format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/) (PR #141) + +## [2.0.7](https://github.com/Ousret/charset_normalizer/compare/2.0.6...2.0.7) (2021-10-11) +### Added +- Add support for Kazakh (Cyrillic) language detection (PR #109) + +### Changed +- Further, improve inferring the language from a given single-byte code page (PR #112) +- Vainly trying to leverage PEP263 when PEP3120 is not supported (PR #116) +- Refactoring for potential performance improvements in loops from [@adbar](https://github.com/adbar) (PR #113) +- Various detection improvement (MD+CD) (PR #117) + +### Removed +- Remove redundant logging entry about detected language(s) (PR #115) + +### Fixed +- Fix a minor inconsistency between Python 3.5 and other versions regarding language detection (PR #117 #102) + +## [2.0.6](https://github.com/Ousret/charset_normalizer/compare/2.0.5...2.0.6) (2021-09-18) +### Fixed +- Unforeseen regression with the loss of the backward-compatibility with some older minor of Python 3.5.x (PR #100) +- Fix CLI crash when using --minimal output in certain cases (PR #103) + +### Changed +- Minor improvement to the detection efficiency (less than 1%) (PR #106 #101) + +## [2.0.5](https://github.com/Ousret/charset_normalizer/compare/2.0.4...2.0.5) (2021-09-14) +### Changed +- The project now comply with: flake8, mypy, isort and black to ensure a better overall quality (PR #81) +- The BC-support with v1.x was improved, the old staticmethods are restored (PR #82) +- The Unicode detection is slightly improved (PR #93) +- Add syntax sugar \_\_bool\_\_ for results CharsetMatches list-container (PR #91) + +### Removed +- The project no longer raise warning on tiny content given for detection, will be simply logged as warning instead (PR #92) + +### Fixed +- In some rare case, the chunks extractor could cut in the middle of a multi-byte character and could mislead the mess detection (PR #95) +- Some rare 'space' characters could trip up the UnprintablePlugin/Mess detection (PR #96) +- The MANIFEST.in was not exhaustive (PR #78) + +## [2.0.4](https://github.com/Ousret/charset_normalizer/compare/2.0.3...2.0.4) (2021-07-30) +### Fixed +- The CLI no longer raise an unexpected exception when no encoding has been found (PR #70) +- Fix accessing the 'alphabets' property when the payload contains surrogate characters (PR #68) +- The logger could mislead (explain=True) on detected languages and the impact of one MBCS match (PR #72) +- Submatch factoring could be wrong in rare edge cases (PR #72) +- Multiple files given to the CLI were ignored when publishing results to STDOUT. (After the first path) (PR #72) +- Fix line endings from CRLF to LF for certain project files (PR #67) + +### Changed +- Adjust the MD to lower the sensitivity, thus improving the global detection reliability (PR #69 #76) +- Allow fallback on specified encoding if any (PR #71) + +## [2.0.3](https://github.com/Ousret/charset_normalizer/compare/2.0.2...2.0.3) (2021-07-16) +### Changed +- Part of the detection mechanism has been improved to be less sensitive, resulting in more accurate detection results. Especially ASCII. (PR #63) +- According to the community wishes, the detection will fall back on ASCII or UTF-8 in a last-resort case. (PR #64) + +## [2.0.2](https://github.com/Ousret/charset_normalizer/compare/2.0.1...2.0.2) (2021-07-15) +### Fixed +- Empty/Too small JSON payload miss-detection fixed. Report from [@tseaver](https://github.com/tseaver) (PR #59) + +### Changed +- Don't inject unicodedata2 into sys.modules from [@akx](https://github.com/akx) (PR #57) + +## [2.0.1](https://github.com/Ousret/charset_normalizer/compare/2.0.0...2.0.1) (2021-07-13) +### Fixed +- Make it work where there isn't a filesystem available, dropping assets frequencies.json. Report from [@sethmlarson](https://github.com/sethmlarson). (PR #55) +- Using explain=False permanently disable the verbose output in the current runtime (PR #47) +- One log entry (language target preemptive) was not show in logs when using explain=True (PR #47) +- Fix undesired exception (ValueError) on getitem of instance CharsetMatches (PR #52) + +### Changed +- Public function normalize default args values were not aligned with from_bytes (PR #53) + +### Added +- You may now use charset aliases in cp_isolation and cp_exclusion arguments (PR #47) + +## [2.0.0](https://github.com/Ousret/charset_normalizer/compare/1.4.1...2.0.0) (2021-07-02) +### Changed +- 4x to 5 times faster than the previous 1.4.0 release. At least 2x faster than Chardet. +- Accent has been made on UTF-8 detection, should perform rather instantaneous. +- The backward compatibility with Chardet has been greatly improved. The legacy detect function returns an identical charset name whenever possible. +- The detection mechanism has been slightly improved, now Turkish content is detected correctly (most of the time) +- The program has been rewritten to ease the readability and maintainability. (+Using static typing)+ +- utf_7 detection has been reinstated. + +### Removed +- This package no longer require anything when used with Python 3.5 (Dropped cached_property) +- Removed support for these languages: Catalan, Esperanto, Kazakh, Baque, Volapük, Azeri, Galician, Nynorsk, Macedonian, and Serbocroatian. +- The exception hook on UnicodeDecodeError has been removed. + +### Deprecated +- Methods coherence_non_latin, w_counter, chaos_secondary_pass of the class CharsetMatch are now deprecated and scheduled for removal in v3.0 + +### Fixed +- The CLI output used the relative path of the file(s). Should be absolute. + +## [1.4.1](https://github.com/Ousret/charset_normalizer/compare/1.4.0...1.4.1) (2021-05-28) +### Fixed +- Logger configuration/usage no longer conflict with others (PR #44) + +## [1.4.0](https://github.com/Ousret/charset_normalizer/compare/1.3.9...1.4.0) (2021-05-21) +### Removed +- Using standard logging instead of using the package loguru. +- Dropping nose test framework in favor of the maintained pytest. +- Choose to not use dragonmapper package to help with gibberish Chinese/CJK text. +- Require cached_property only for Python 3.5 due to constraint. Dropping for every other interpreter version. +- Stop support for UTF-7 that does not contain a SIG. +- Dropping PrettyTable, replaced with pure JSON output in CLI. + +### Fixed +- BOM marker in a CharsetNormalizerMatch instance could be False in rare cases even if obviously present. Due to the sub-match factoring process. +- Not searching properly for the BOM when trying utf32/16 parent codec. + +### Changed +- Improving the package final size by compressing frequencies.json. +- Huge improvement over the larges payload. + +### Added +- CLI now produces JSON consumable output. +- Return ASCII if given sequences fit. Given reasonable confidence. + +## [1.3.9](https://github.com/Ousret/charset_normalizer/compare/1.3.8...1.3.9) (2021-05-13) + +### Fixed +- In some very rare cases, you may end up getting encode/decode errors due to a bad bytes payload (PR #40) + +## [1.3.8](https://github.com/Ousret/charset_normalizer/compare/1.3.7...1.3.8) (2021-05-12) + +### Fixed +- Empty given payload for detection may cause an exception if trying to access the `alphabets` property. (PR #39) + +## [1.3.7](https://github.com/Ousret/charset_normalizer/compare/1.3.6...1.3.7) (2021-05-12) + +### Fixed +- The legacy detect function should return UTF-8-SIG if sig is present in the payload. (PR #38) + +## [1.3.6](https://github.com/Ousret/charset_normalizer/compare/1.3.5...1.3.6) (2021-02-09) + +### Changed +- Amend the previous release to allow prettytable 2.0 (PR #35) + +## [1.3.5](https://github.com/Ousret/charset_normalizer/compare/1.3.4...1.3.5) (2021-02-08) + +### Fixed +- Fix error while using the package with a python pre-release interpreter (PR #33) + +### Changed +- Dependencies refactoring, constraints revised. + +### Added +- Add python 3.9 and 3.10 to the supported interpreters + +MIT License + +Copyright (c) 2019 TAHRI Ahmed R. + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/psets/9/finance/env/lib/python3.12/site-packages/charset_normalizer-3.4.0.dist-info/RECORD b/psets/9/finance/env/lib/python3.12/site-packages/charset_normalizer-3.4.0.dist-info/RECORD new file mode 100644 index 0000000..a10aeb5 --- /dev/null +++ b/psets/9/finance/env/lib/python3.12/site-packages/charset_normalizer-3.4.0.dist-info/RECORD @@ -0,0 +1,35 @@ +../../../bin/normalizer,sha256=ekqe9JUa_XbpXPLd67-amVvulPU1zuc_gOtEx26P31w,270 +charset_normalizer-3.4.0.dist-info/INSTALLER,sha256=zuuue4knoyJ-UwPPXg8fezS7VCrXJQrAP7zeNuwvFQg,4 +charset_normalizer-3.4.0.dist-info/LICENSE,sha256=6zGgxaT7Cbik4yBV0lweX5w1iidS_vPNcgIT0cz-4kE,1070 +charset_normalizer-3.4.0.dist-info/METADATA,sha256=WGbEW9ehh2spNJxo1M6sEGGZWmsQ-oj2DsMjV29zoms,34159 +charset_normalizer-3.4.0.dist-info/RECORD,, +charset_normalizer-3.4.0.dist-info/WHEEL,sha256=7B4nnId14TToQHuAKpxbDLCJbNciqBsV-mvXE2hVLJc,151 +charset_normalizer-3.4.0.dist-info/entry_points.txt,sha256=ADSTKrkXZ3hhdOVFi6DcUEHQRS0xfxDIE_pEz4wLIXA,65 +charset_normalizer-3.4.0.dist-info/top_level.txt,sha256=7ASyzePr8_xuZWJsnqJjIBtyV8vhEo0wBCv1MPRRi3Q,19 +charset_normalizer/__init__.py,sha256=UzI3xC8PhmcLRMzSgPb6minTmRq0kWznnCBJ8ZCc2XI,1577 +charset_normalizer/__main__.py,sha256=JxY8bleaENOFlLRb9HfoeZCzAMnn2A1oGR5Xm2eyqg0,73 +charset_normalizer/__pycache__/__init__.cpython-312.pyc,, +charset_normalizer/__pycache__/__main__.cpython-312.pyc,, +charset_normalizer/__pycache__/api.cpython-312.pyc,, +charset_normalizer/__pycache__/cd.cpython-312.pyc,, +charset_normalizer/__pycache__/constant.cpython-312.pyc,, +charset_normalizer/__pycache__/legacy.cpython-312.pyc,, +charset_normalizer/__pycache__/md.cpython-312.pyc,, +charset_normalizer/__pycache__/models.cpython-312.pyc,, +charset_normalizer/__pycache__/utils.cpython-312.pyc,, +charset_normalizer/__pycache__/version.cpython-312.pyc,, +charset_normalizer/api.py,sha256=kMyNUqrfBZU22PP0pYKrSldtYUGA24wsGlXGLAKra7c,22559 +charset_normalizer/cd.py,sha256=xwZliZcTQFA3jU0c00PRiu9MNxXTFxQkFLWmMW24ZzI,12560 +charset_normalizer/cli/__init__.py,sha256=D5ERp8P62llm2FuoMzydZ7d9rs8cvvLXqE-1_6oViPc,100 +charset_normalizer/cli/__main__.py,sha256=zX9sV_ApU1d96Wb0cS04vulstdB4F0Eh7kLn-gevfw4,10411 +charset_normalizer/cli/__pycache__/__init__.cpython-312.pyc,, +charset_normalizer/cli/__pycache__/__main__.cpython-312.pyc,, +charset_normalizer/constant.py,sha256=uwoW87NicWZDTLviX7le0wdoYBbhBQDA4n1JtJo77ts,40499 +charset_normalizer/legacy.py,sha256=XJjkT0hejMH8qfAKz1ts8OUiBT18t2FJP3tJgLwUWwc,2327 +charset_normalizer/md.cpython-312-x86_64-linux-gnu.so,sha256=W654QTU3QZI6eWJ0fanScAr0_O6sL0I61fyRSdC-39Y,16064 +charset_normalizer/md.py,sha256=SIIZcENrslI7h3v4GigbFN61fRyE_wiCN1z9Ii3fBRo,20138 +charset_normalizer/md__mypyc.cpython-312-x86_64-linux-gnu.so,sha256=aHbqbG6rcHNRf7bwpi57D1X8ZKAmyoVnTldPUDzCKMo,276848 +charset_normalizer/models.py,sha256=oAMAcBSEY7CngbUXJp34Wc4Rl9NKJJjGmUwW3EPtk6g,12425 +charset_normalizer/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0 +charset_normalizer/utils.py,sha256=teiosMqzKjXyAHXnGdjSBOgnBZwx-SkBbCLrx0UXy8M,11894 +charset_normalizer/version.py,sha256=AX66S4ytQFdd6F5jbVU2OPMqYwFS5M3BkMvyX-3BKF8,79 diff --git a/psets/9/finance/env/lib/python3.12/site-packages/charset_normalizer-3.4.0.dist-info/WHEEL b/psets/9/finance/env/lib/python3.12/site-packages/charset_normalizer-3.4.0.dist-info/WHEEL new file mode 100644 index 0000000..3e81182 --- /dev/null +++ b/psets/9/finance/env/lib/python3.12/site-packages/charset_normalizer-3.4.0.dist-info/WHEEL @@ -0,0 +1,6 @@ +Wheel-Version: 1.0 +Generator: setuptools (75.1.0) +Root-Is-Purelib: false +Tag: cp312-cp312-manylinux_2_17_x86_64 +Tag: cp312-cp312-manylinux2014_x86_64 + diff --git a/psets/9/finance/env/lib/python3.12/site-packages/charset_normalizer-3.4.0.dist-info/entry_points.txt b/psets/9/finance/env/lib/python3.12/site-packages/charset_normalizer-3.4.0.dist-info/entry_points.txt new file mode 100644 index 0000000..65619e7 --- /dev/null +++ b/psets/9/finance/env/lib/python3.12/site-packages/charset_normalizer-3.4.0.dist-info/entry_points.txt @@ -0,0 +1,2 @@ +[console_scripts] +normalizer = charset_normalizer.cli:cli_detect diff --git a/psets/9/finance/env/lib/python3.12/site-packages/charset_normalizer-3.4.0.dist-info/top_level.txt b/psets/9/finance/env/lib/python3.12/site-packages/charset_normalizer-3.4.0.dist-info/top_level.txt new file mode 100644 index 0000000..66958f0 --- /dev/null +++ b/psets/9/finance/env/lib/python3.12/site-packages/charset_normalizer-3.4.0.dist-info/top_level.txt @@ -0,0 +1 @@ +charset_normalizer diff --git a/psets/9/finance/env/lib/python3.12/site-packages/charset_normalizer/__init__.py b/psets/9/finance/env/lib/python3.12/site-packages/charset_normalizer/__init__.py new file mode 100644 index 0000000..55991fc --- /dev/null +++ b/psets/9/finance/env/lib/python3.12/site-packages/charset_normalizer/__init__.py @@ -0,0 +1,46 @@ +# -*- coding: utf-8 -*- +""" +Charset-Normalizer +~~~~~~~~~~~~~~ +The Real First Universal Charset Detector. +A library that helps you read text from an unknown charset encoding. +Motivated by chardet, This package is trying to resolve the issue by taking a new approach. +All IANA character set names for which the Python core library provides codecs are supported. + +Basic usage: + >>> from charset_normalizer import from_bytes + >>> results = from_bytes('Bсеки човек има право на образование. Oбразованието!'.encode('utf_8')) + >>> best_guess = results.best() + >>> str(best_guess) + 'Bсеки човек има право на образование. Oбразованието!' + +Others methods and usages are available - see the full documentation +at . +:copyright: (c) 2021 by Ahmed TAHRI +:license: MIT, see LICENSE for more details. +""" +import logging + +from .api import from_bytes, from_fp, from_path, is_binary +from .legacy import detect +from .models import CharsetMatch, CharsetMatches +from .utils import set_logging_handler +from .version import VERSION, __version__ + +__all__ = ( + "from_fp", + "from_path", + "from_bytes", + "is_binary", + "detect", + "CharsetMatch", + "CharsetMatches", + "__version__", + "VERSION", + "set_logging_handler", +) + +# Attach a NullHandler to the top level logger by default +# https://docs.python.org/3.3/howto/logging.html#configuring-logging-for-a-library + +logging.getLogger("charset_normalizer").addHandler(logging.NullHandler()) diff --git a/psets/9/finance/env/lib/python3.12/site-packages/charset_normalizer/__main__.py b/psets/9/finance/env/lib/python3.12/site-packages/charset_normalizer/__main__.py new file mode 100644 index 0000000..beae2ef --- /dev/null +++ b/psets/9/finance/env/lib/python3.12/site-packages/charset_normalizer/__main__.py @@ -0,0 +1,4 @@ +from .cli import cli_detect + +if __name__ == "__main__": + cli_detect() diff --git a/psets/9/finance/env/lib/python3.12/site-packages/charset_normalizer/__pycache__/__init__.cpython-312.pyc b/psets/9/finance/env/lib/python3.12/site-packages/charset_normalizer/__pycache__/__init__.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..de664498cc36d503c7940c02dfa8daba8d2ed99e GIT binary patch literal 1734 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 Yq$7(Z9a${t$YKeQb?r1liCEJA263Z(>;M1& literal 0 HcmV?d00001 diff --git a/psets/9/finance/env/lib/python3.12/site-packages/charset_normalizer/__pycache__/cd.cpython-312.pyc b/psets/9/finance/env/lib/python3.12/site-packages/charset_normalizer/__pycache__/cd.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..5f1bd9e01791ea5a51ba69fa531118df2ab6dcc7 GIT binary patch literal 13443 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%0Af*fC__7 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 Raax27OTT{{T^#O-=v+ literal 0 HcmV?d00001 diff --git a/psets/9/finance/env/lib/python3.12/site-packages/charset_normalizer/__pycache__/legacy.cpython-312.pyc b/psets/9/finance/env/lib/python3.12/site-packages/charset_normalizer/__pycache__/legacy.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..eb7fee66c3fb77f4be9e1f4ab1a99a1d0c8e2771 GIT binary patch literal 2848 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 literal 0 HcmV?d00001 diff --git a/psets/9/finance/env/lib/python3.12/site-packages/charset_normalizer/__pycache__/version.cpython-312.pyc b/psets/9/finance/env/lib/python3.12/site-packages/charset_normalizer/__pycache__/version.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..087c2100c9e63b46540284938d1d39c7fb02460e GIT binary patch literal 331 zcmX@j%ge<81dppD)BQm-hyw%6P{wCHAY(d13PTh_3S$&wDq|KaObLQcVOq@y;YBf5 zGHbF_32?bq6yz7DDwL%b6=&w>aaFMz>zU{o++x)8(`32D9v`2QpBx{5i#t9ZsshMi zEiTB(EV;!V<{A|2>F>9a;WNn0U#a@Jc_sQTi6yCd`pNkznR)5@$;GAy`US CharsetMatches: + """ + Given a raw bytes sequence, return the best possibles charset usable to render str objects. + If there is no results, it is a strong indicator that the source is binary/not text. + By default, the process will extract 5 blocks of 512o each to assess the mess and coherence of a given sequence. + And will give up a particular code page after 20% of measured mess. Those criteria are customizable at will. + + The preemptive behavior DOES NOT replace the traditional detection workflow, it prioritize a particular code page + but never take it for granted. Can improve the performance. + + You may want to focus your attention to some code page or/and not others, use cp_isolation and cp_exclusion for that + purpose. + + This function will strip the SIG in the payload/sequence every time except on UTF-16, UTF-32. + By default the library does not setup any handler other than the NullHandler, if you choose to set the 'explain' + toggle to True it will alter the logger configuration to add a StreamHandler that is suitable for debugging. + Custom logging format and handler can be set manually. + """ + + if not isinstance(sequences, (bytearray, bytes)): + raise TypeError( + "Expected object of type bytes or bytearray, got: {0}".format( + type(sequences) + ) + ) + + if explain: + previous_logger_level: int = logger.level + logger.addHandler(explain_handler) + logger.setLevel(TRACE) + + length: int = len(sequences) + + if length == 0: + logger.debug("Encoding detection on empty bytes, assuming utf_8 intention.") + if explain: + logger.removeHandler(explain_handler) + logger.setLevel(previous_logger_level or logging.WARNING) + return CharsetMatches([CharsetMatch(sequences, "utf_8", 0.0, False, [], "")]) + + if cp_isolation is not None: + logger.log( + TRACE, + "cp_isolation is set. use this flag for debugging purpose. " + "limited list of encoding allowed : %s.", + ", ".join(cp_isolation), + ) + cp_isolation = [iana_name(cp, False) for cp in cp_isolation] + else: + cp_isolation = [] + + if cp_exclusion is not None: + logger.log( + TRACE, + "cp_exclusion is set. use this flag for debugging purpose. " + "limited list of encoding excluded : %s.", + ", ".join(cp_exclusion), + ) + cp_exclusion = [iana_name(cp, False) for cp in cp_exclusion] + else: + cp_exclusion = [] + + if length <= (chunk_size * steps): + logger.log( + TRACE, + "override steps (%i) and chunk_size (%i) as content does not fit (%i byte(s) given) parameters.", + steps, + chunk_size, + length, + ) + steps = 1 + chunk_size = length + + if steps > 1 and length / steps < chunk_size: + chunk_size = int(length / steps) + + is_too_small_sequence: bool = len(sequences) < TOO_SMALL_SEQUENCE + is_too_large_sequence: bool = len(sequences) >= TOO_BIG_SEQUENCE + + if is_too_small_sequence: + logger.log( + TRACE, + "Trying to detect encoding from a tiny portion of ({}) byte(s).".format( + length + ), + ) + elif is_too_large_sequence: + logger.log( + TRACE, + "Using lazy str decoding because the payload is quite large, ({}) byte(s).".format( + length + ), + ) + + prioritized_encodings: List[str] = [] + + specified_encoding: Optional[str] = ( + any_specified_encoding(sequences) if preemptive_behaviour else None + ) + + if specified_encoding is not None: + prioritized_encodings.append(specified_encoding) + logger.log( + TRACE, + "Detected declarative mark in sequence. Priority +1 given for %s.", + specified_encoding, + ) + + tested: Set[str] = set() + tested_but_hard_failure: List[str] = [] + tested_but_soft_failure: List[str] = [] + + fallback_ascii: Optional[CharsetMatch] = None + fallback_u8: Optional[CharsetMatch] = None + fallback_specified: Optional[CharsetMatch] = None + + results: CharsetMatches = CharsetMatches() + + early_stop_results: CharsetMatches = CharsetMatches() + + sig_encoding, sig_payload = identify_sig_or_bom(sequences) + + if sig_encoding is not None: + prioritized_encodings.append(sig_encoding) + logger.log( + TRACE, + "Detected a SIG or BOM mark on first %i byte(s). Priority +1 given for %s.", + len(sig_payload), + sig_encoding, + ) + + prioritized_encodings.append("ascii") + + if "utf_8" not in prioritized_encodings: + prioritized_encodings.append("utf_8") + + for encoding_iana in prioritized_encodings + IANA_SUPPORTED: + if cp_isolation and encoding_iana not in cp_isolation: + continue + + if cp_exclusion and encoding_iana in cp_exclusion: + continue + + if encoding_iana in tested: + continue + + tested.add(encoding_iana) + + decoded_payload: Optional[str] = None + bom_or_sig_available: bool = sig_encoding == encoding_iana + strip_sig_or_bom: bool = bom_or_sig_available and should_strip_sig_or_bom( + encoding_iana + ) + + if encoding_iana in {"utf_16", "utf_32"} and not bom_or_sig_available: + logger.log( + TRACE, + "Encoding %s won't be tested as-is because it require a BOM. Will try some sub-encoder LE/BE.", + encoding_iana, + ) + continue + if encoding_iana in {"utf_7"} and not bom_or_sig_available: + logger.log( + TRACE, + "Encoding %s won't be tested as-is because detection is unreliable without BOM/SIG.", + encoding_iana, + ) + continue + + try: + is_multi_byte_decoder: bool = is_multi_byte_encoding(encoding_iana) + except (ModuleNotFoundError, ImportError): + logger.log( + TRACE, + "Encoding %s does not provide an IncrementalDecoder", + encoding_iana, + ) + continue + + try: + if is_too_large_sequence and is_multi_byte_decoder is False: + str( + ( + sequences[: int(50e4)] + if strip_sig_or_bom is False + else sequences[len(sig_payload) : int(50e4)] + ), + encoding=encoding_iana, + ) + else: + decoded_payload = str( + ( + sequences + if strip_sig_or_bom is False + else sequences[len(sig_payload) :] + ), + encoding=encoding_iana, + ) + except (UnicodeDecodeError, LookupError) as e: + if not isinstance(e, LookupError): + logger.log( + TRACE, + "Code page %s does not fit given bytes sequence at ALL. %s", + encoding_iana, + str(e), + ) + tested_but_hard_failure.append(encoding_iana) + continue + + similar_soft_failure_test: bool = False + + for encoding_soft_failed in tested_but_soft_failure: + if is_cp_similar(encoding_iana, encoding_soft_failed): + similar_soft_failure_test = True + break + + if similar_soft_failure_test: + logger.log( + TRACE, + "%s is deemed too similar to code page %s and was consider unsuited already. Continuing!", + encoding_iana, + encoding_soft_failed, + ) + continue + + r_ = range( + 0 if not bom_or_sig_available else len(sig_payload), + length, + int(length / steps), + ) + + multi_byte_bonus: bool = ( + is_multi_byte_decoder + and decoded_payload is not None + and len(decoded_payload) < length + ) + + if multi_byte_bonus: + logger.log( + TRACE, + "Code page %s is a multi byte encoding table and it appear that at least one character " + "was encoded using n-bytes.", + encoding_iana, + ) + + max_chunk_gave_up: int = int(len(r_) / 4) + + max_chunk_gave_up = max(max_chunk_gave_up, 2) + early_stop_count: int = 0 + lazy_str_hard_failure = False + + md_chunks: List[str] = [] + md_ratios = [] + + try: + for chunk in cut_sequence_chunks( + sequences, + encoding_iana, + r_, + chunk_size, + bom_or_sig_available, + strip_sig_or_bom, + sig_payload, + is_multi_byte_decoder, + decoded_payload, + ): + md_chunks.append(chunk) + + md_ratios.append( + mess_ratio( + chunk, + threshold, + explain is True and 1 <= len(cp_isolation) <= 2, + ) + ) + + if md_ratios[-1] >= threshold: + early_stop_count += 1 + + if (early_stop_count >= max_chunk_gave_up) or ( + bom_or_sig_available and strip_sig_or_bom is False + ): + break + except ( + UnicodeDecodeError + ) as e: # Lazy str loading may have missed something there + logger.log( + TRACE, + "LazyStr Loading: After MD chunk decode, code page %s does not fit given bytes sequence at ALL. %s", + encoding_iana, + str(e), + ) + early_stop_count = max_chunk_gave_up + lazy_str_hard_failure = True + + # We might want to check the sequence again with the whole content + # Only if initial MD tests passes + if ( + not lazy_str_hard_failure + and is_too_large_sequence + and not is_multi_byte_decoder + ): + try: + sequences[int(50e3) :].decode(encoding_iana, errors="strict") + except UnicodeDecodeError as e: + logger.log( + TRACE, + "LazyStr Loading: After final lookup, code page %s does not fit given bytes sequence at ALL. %s", + encoding_iana, + str(e), + ) + tested_but_hard_failure.append(encoding_iana) + continue + + mean_mess_ratio: float = sum(md_ratios) / len(md_ratios) if md_ratios else 0.0 + if mean_mess_ratio >= threshold or early_stop_count >= max_chunk_gave_up: + tested_but_soft_failure.append(encoding_iana) + logger.log( + TRACE, + "%s was excluded because of initial chaos probing. Gave up %i time(s). " + "Computed mean chaos is %f %%.", + encoding_iana, + early_stop_count, + round(mean_mess_ratio * 100, ndigits=3), + ) + # Preparing those fallbacks in case we got nothing. + if ( + enable_fallback + and encoding_iana in ["ascii", "utf_8", specified_encoding] + and not lazy_str_hard_failure + ): + fallback_entry = CharsetMatch( + sequences, + encoding_iana, + threshold, + False, + [], + decoded_payload, + preemptive_declaration=specified_encoding, + ) + if encoding_iana == specified_encoding: + fallback_specified = fallback_entry + elif encoding_iana == "ascii": + fallback_ascii = fallback_entry + else: + fallback_u8 = fallback_entry + continue + + logger.log( + TRACE, + "%s passed initial chaos probing. Mean measured chaos is %f %%", + encoding_iana, + round(mean_mess_ratio * 100, ndigits=3), + ) + + if not is_multi_byte_decoder: + target_languages: List[str] = encoding_languages(encoding_iana) + else: + target_languages = mb_encoding_languages(encoding_iana) + + if target_languages: + logger.log( + TRACE, + "{} should target any language(s) of {}".format( + encoding_iana, str(target_languages) + ), + ) + + cd_ratios = [] + + # We shall skip the CD when its about ASCII + # Most of the time its not relevant to run "language-detection" on it. + if encoding_iana != "ascii": + for chunk in md_chunks: + chunk_languages = coherence_ratio( + chunk, + language_threshold, + ",".join(target_languages) if target_languages else None, + ) + + cd_ratios.append(chunk_languages) + + cd_ratios_merged = merge_coherence_ratios(cd_ratios) + + if cd_ratios_merged: + logger.log( + TRACE, + "We detected language {} using {}".format( + cd_ratios_merged, encoding_iana + ), + ) + + current_match = CharsetMatch( + sequences, + encoding_iana, + mean_mess_ratio, + bom_or_sig_available, + cd_ratios_merged, + ( + decoded_payload + if ( + is_too_large_sequence is False + or encoding_iana in [specified_encoding, "ascii", "utf_8"] + ) + else None + ), + preemptive_declaration=specified_encoding, + ) + + results.append(current_match) + + if ( + encoding_iana in [specified_encoding, "ascii", "utf_8"] + and mean_mess_ratio < 0.1 + ): + # If md says nothing to worry about, then... stop immediately! + if mean_mess_ratio == 0.0: + logger.debug( + "Encoding detection: %s is most likely the one.", + current_match.encoding, + ) + if explain: + logger.removeHandler(explain_handler) + logger.setLevel(previous_logger_level) + return CharsetMatches([current_match]) + + early_stop_results.append(current_match) + + if ( + len(early_stop_results) + and (specified_encoding is None or specified_encoding in tested) + and "ascii" in tested + and "utf_8" in tested + ): + probable_result: CharsetMatch = early_stop_results.best() # type: ignore[assignment] + logger.debug( + "Encoding detection: %s is most likely the one.", + probable_result.encoding, + ) + if explain: + logger.removeHandler(explain_handler) + logger.setLevel(previous_logger_level) + + return CharsetMatches([probable_result]) + + if encoding_iana == sig_encoding: + logger.debug( + "Encoding detection: %s is most likely the one as we detected a BOM or SIG within " + "the beginning of the sequence.", + encoding_iana, + ) + if explain: + logger.removeHandler(explain_handler) + logger.setLevel(previous_logger_level) + return CharsetMatches([results[encoding_iana]]) + + if len(results) == 0: + if fallback_u8 or fallback_ascii or fallback_specified: + logger.log( + TRACE, + "Nothing got out of the detection process. Using ASCII/UTF-8/Specified fallback.", + ) + + if fallback_specified: + logger.debug( + "Encoding detection: %s will be used as a fallback match", + fallback_specified.encoding, + ) + results.append(fallback_specified) + elif ( + (fallback_u8 and fallback_ascii is None) + or ( + fallback_u8 + and fallback_ascii + and fallback_u8.fingerprint != fallback_ascii.fingerprint + ) + or (fallback_u8 is not None) + ): + logger.debug("Encoding detection: utf_8 will be used as a fallback match") + results.append(fallback_u8) + elif fallback_ascii: + logger.debug("Encoding detection: ascii will be used as a fallback match") + results.append(fallback_ascii) + + if results: + logger.debug( + "Encoding detection: Found %s as plausible (best-candidate) for content. With %i alternatives.", + results.best().encoding, # type: ignore + len(results) - 1, + ) + else: + logger.debug("Encoding detection: Unable to determine any suitable charset.") + + if explain: + logger.removeHandler(explain_handler) + logger.setLevel(previous_logger_level) + + return results + + +def from_fp( + fp: BinaryIO, + steps: int = 5, + chunk_size: int = 512, + threshold: float = 0.20, + cp_isolation: Optional[List[str]] = None, + cp_exclusion: Optional[List[str]] = None, + preemptive_behaviour: bool = True, + explain: bool = False, + language_threshold: float = 0.1, + enable_fallback: bool = True, +) -> CharsetMatches: + """ + Same thing than the function from_bytes but using a file pointer that is already ready. + Will not close the file pointer. + """ + return from_bytes( + fp.read(), + steps, + chunk_size, + threshold, + cp_isolation, + cp_exclusion, + preemptive_behaviour, + explain, + language_threshold, + enable_fallback, + ) + + +def from_path( + path: Union[str, bytes, PathLike], # type: ignore[type-arg] + steps: int = 5, + chunk_size: int = 512, + threshold: float = 0.20, + cp_isolation: Optional[List[str]] = None, + cp_exclusion: Optional[List[str]] = None, + preemptive_behaviour: bool = True, + explain: bool = False, + language_threshold: float = 0.1, + enable_fallback: bool = True, +) -> CharsetMatches: + """ + Same thing than the function from_bytes but with one extra step. Opening and reading given file path in binary mode. + Can raise IOError. + """ + with open(path, "rb") as fp: + return from_fp( + fp, + steps, + chunk_size, + threshold, + cp_isolation, + cp_exclusion, + preemptive_behaviour, + explain, + language_threshold, + enable_fallback, + ) + + +def is_binary( + fp_or_path_or_payload: Union[PathLike, str, BinaryIO, bytes], # type: ignore[type-arg] + steps: int = 5, + chunk_size: int = 512, + threshold: float = 0.20, + cp_isolation: Optional[List[str]] = None, + cp_exclusion: Optional[List[str]] = None, + preemptive_behaviour: bool = True, + explain: bool = False, + language_threshold: float = 0.1, + enable_fallback: bool = False, +) -> bool: + """ + Detect if the given input (file, bytes, or path) points to a binary file. aka. not a string. + Based on the same main heuristic algorithms and default kwargs at the sole exception that fallbacks match + are disabled to be stricter around ASCII-compatible but unlikely to be a string. + """ + if isinstance(fp_or_path_or_payload, (str, PathLike)): + guesses = from_path( + fp_or_path_or_payload, + steps=steps, + chunk_size=chunk_size, + threshold=threshold, + cp_isolation=cp_isolation, + cp_exclusion=cp_exclusion, + preemptive_behaviour=preemptive_behaviour, + explain=explain, + language_threshold=language_threshold, + enable_fallback=enable_fallback, + ) + elif isinstance( + fp_or_path_or_payload, + ( + bytes, + bytearray, + ), + ): + guesses = from_bytes( + fp_or_path_or_payload, + steps=steps, + chunk_size=chunk_size, + threshold=threshold, + cp_isolation=cp_isolation, + cp_exclusion=cp_exclusion, + preemptive_behaviour=preemptive_behaviour, + explain=explain, + language_threshold=language_threshold, + enable_fallback=enable_fallback, + ) + else: + guesses = from_fp( + fp_or_path_or_payload, + steps=steps, + chunk_size=chunk_size, + threshold=threshold, + cp_isolation=cp_isolation, + cp_exclusion=cp_exclusion, + preemptive_behaviour=preemptive_behaviour, + explain=explain, + language_threshold=language_threshold, + enable_fallback=enable_fallback, + ) + + return not guesses diff --git a/psets/9/finance/env/lib/python3.12/site-packages/charset_normalizer/cd.py b/psets/9/finance/env/lib/python3.12/site-packages/charset_normalizer/cd.py new file mode 100644 index 0000000..4ea6760 --- /dev/null +++ b/psets/9/finance/env/lib/python3.12/site-packages/charset_normalizer/cd.py @@ -0,0 +1,395 @@ +import importlib +from codecs import IncrementalDecoder +from collections import Counter +from functools import lru_cache +from typing import Counter as TypeCounter, Dict, List, Optional, Tuple + +from .constant import ( + FREQUENCIES, + KO_NAMES, + LANGUAGE_SUPPORTED_COUNT, + TOO_SMALL_SEQUENCE, + ZH_NAMES, +) +from .md import is_suspiciously_successive_range +from .models import CoherenceMatches +from .utils import ( + is_accentuated, + is_latin, + is_multi_byte_encoding, + is_unicode_range_secondary, + unicode_range, +) + + +def encoding_unicode_range(iana_name: str) -> List[str]: + """ + Return associated unicode ranges in a single byte code page. + """ + if is_multi_byte_encoding(iana_name): + raise IOError("Function not supported on multi-byte code page") + + decoder = importlib.import_module( + "encodings.{}".format(iana_name) + ).IncrementalDecoder + + p: IncrementalDecoder = decoder(errors="ignore") + seen_ranges: Dict[str, int] = {} + character_count: int = 0 + + for i in range(0x40, 0xFF): + chunk: str = p.decode(bytes([i])) + + if chunk: + character_range: Optional[str] = unicode_range(chunk) + + if character_range is None: + continue + + if is_unicode_range_secondary(character_range) is False: + if character_range not in seen_ranges: + seen_ranges[character_range] = 0 + seen_ranges[character_range] += 1 + character_count += 1 + + return sorted( + [ + character_range + for character_range in seen_ranges + if seen_ranges[character_range] / character_count >= 0.15 + ] + ) + + +def unicode_range_languages(primary_range: str) -> List[str]: + """ + Return inferred languages used with a unicode range. + """ + languages: List[str] = [] + + for language, characters in FREQUENCIES.items(): + for character in characters: + if unicode_range(character) == primary_range: + languages.append(language) + break + + return languages + + +@lru_cache() +def encoding_languages(iana_name: str) -> List[str]: + """ + Single-byte encoding language association. Some code page are heavily linked to particular language(s). + This function does the correspondence. + """ + unicode_ranges: List[str] = encoding_unicode_range(iana_name) + primary_range: Optional[str] = None + + for specified_range in unicode_ranges: + if "Latin" not in specified_range: + primary_range = specified_range + break + + if primary_range is None: + return ["Latin Based"] + + return unicode_range_languages(primary_range) + + +@lru_cache() +def mb_encoding_languages(iana_name: str) -> List[str]: + """ + Multi-byte encoding language association. Some code page are heavily linked to particular language(s). + This function does the correspondence. + """ + if ( + iana_name.startswith("shift_") + or iana_name.startswith("iso2022_jp") + or iana_name.startswith("euc_j") + or iana_name == "cp932" + ): + return ["Japanese"] + if iana_name.startswith("gb") or iana_name in ZH_NAMES: + return ["Chinese"] + if iana_name.startswith("iso2022_kr") or iana_name in KO_NAMES: + return ["Korean"] + + return [] + + +@lru_cache(maxsize=LANGUAGE_SUPPORTED_COUNT) +def get_target_features(language: str) -> Tuple[bool, bool]: + """ + Determine main aspects from a supported language if it contains accents and if is pure Latin. + """ + target_have_accents: bool = False + target_pure_latin: bool = True + + for character in FREQUENCIES[language]: + if not target_have_accents and is_accentuated(character): + target_have_accents = True + if target_pure_latin and is_latin(character) is False: + target_pure_latin = False + + return target_have_accents, target_pure_latin + + +def alphabet_languages( + characters: List[str], ignore_non_latin: bool = False +) -> List[str]: + """ + Return associated languages associated to given characters. + """ + languages: List[Tuple[str, float]] = [] + + source_have_accents = any(is_accentuated(character) for character in characters) + + for language, language_characters in FREQUENCIES.items(): + target_have_accents, target_pure_latin = get_target_features(language) + + if ignore_non_latin and target_pure_latin is False: + continue + + if target_have_accents is False and source_have_accents: + continue + + character_count: int = len(language_characters) + + character_match_count: int = len( + [c for c in language_characters if c in characters] + ) + + ratio: float = character_match_count / character_count + + if ratio >= 0.2: + languages.append((language, ratio)) + + languages = sorted(languages, key=lambda x: x[1], reverse=True) + + return [compatible_language[0] for compatible_language in languages] + + +def characters_popularity_compare( + language: str, ordered_characters: List[str] +) -> float: + """ + Determine if a ordered characters list (by occurrence from most appearance to rarest) match a particular language. + The result is a ratio between 0. (absolutely no correspondence) and 1. (near perfect fit). + Beware that is function is not strict on the match in order to ease the detection. (Meaning close match is 1.) + """ + if language not in FREQUENCIES: + raise ValueError("{} not available".format(language)) + + character_approved_count: int = 0 + FREQUENCIES_language_set = set(FREQUENCIES[language]) + + ordered_characters_count: int = len(ordered_characters) + target_language_characters_count: int = len(FREQUENCIES[language]) + + large_alphabet: bool = target_language_characters_count > 26 + + for character, character_rank in zip( + ordered_characters, range(0, ordered_characters_count) + ): + if character not in FREQUENCIES_language_set: + continue + + character_rank_in_language: int = FREQUENCIES[language].index(character) + expected_projection_ratio: float = ( + target_language_characters_count / ordered_characters_count + ) + character_rank_projection: int = int(character_rank * expected_projection_ratio) + + if ( + large_alphabet is False + and abs(character_rank_projection - character_rank_in_language) > 4 + ): + continue + + if ( + large_alphabet is True + and abs(character_rank_projection - character_rank_in_language) + < target_language_characters_count / 3 + ): + character_approved_count += 1 + continue + + characters_before_source: List[str] = FREQUENCIES[language][ + 0:character_rank_in_language + ] + characters_after_source: List[str] = FREQUENCIES[language][ + character_rank_in_language: + ] + characters_before: List[str] = ordered_characters[0:character_rank] + characters_after: List[str] = ordered_characters[character_rank:] + + before_match_count: int = len( + set(characters_before) & set(characters_before_source) + ) + + after_match_count: int = len( + set(characters_after) & set(characters_after_source) + ) + + if len(characters_before_source) == 0 and before_match_count <= 4: + character_approved_count += 1 + continue + + if len(characters_after_source) == 0 and after_match_count <= 4: + character_approved_count += 1 + continue + + if ( + before_match_count / len(characters_before_source) >= 0.4 + or after_match_count / len(characters_after_source) >= 0.4 + ): + character_approved_count += 1 + continue + + return character_approved_count / len(ordered_characters) + + +def alpha_unicode_split(decoded_sequence: str) -> List[str]: + """ + Given a decoded text sequence, return a list of str. Unicode range / alphabet separation. + Ex. a text containing English/Latin with a bit a Hebrew will return two items in the resulting list; + One containing the latin letters and the other hebrew. + """ + layers: Dict[str, str] = {} + + for character in decoded_sequence: + if character.isalpha() is False: + continue + + character_range: Optional[str] = unicode_range(character) + + if character_range is None: + continue + + layer_target_range: Optional[str] = None + + for discovered_range in layers: + if ( + is_suspiciously_successive_range(discovered_range, character_range) + is False + ): + layer_target_range = discovered_range + break + + if layer_target_range is None: + layer_target_range = character_range + + if layer_target_range not in layers: + layers[layer_target_range] = character.lower() + continue + + layers[layer_target_range] += character.lower() + + return list(layers.values()) + + +def merge_coherence_ratios(results: List[CoherenceMatches]) -> CoherenceMatches: + """ + This function merge results previously given by the function coherence_ratio. + The return type is the same as coherence_ratio. + """ + per_language_ratios: Dict[str, List[float]] = {} + for result in results: + for sub_result in result: + language, ratio = sub_result + if language not in per_language_ratios: + per_language_ratios[language] = [ratio] + continue + per_language_ratios[language].append(ratio) + + merge = [ + ( + language, + round( + sum(per_language_ratios[language]) / len(per_language_ratios[language]), + 4, + ), + ) + for language in per_language_ratios + ] + + return sorted(merge, key=lambda x: x[1], reverse=True) + + +def filter_alt_coherence_matches(results: CoherenceMatches) -> CoherenceMatches: + """ + We shall NOT return "English—" in CoherenceMatches because it is an alternative + of "English". This function only keeps the best match and remove the em-dash in it. + """ + index_results: Dict[str, List[float]] = dict() + + for result in results: + language, ratio = result + no_em_name: str = language.replace("—", "") + + if no_em_name not in index_results: + index_results[no_em_name] = [] + + index_results[no_em_name].append(ratio) + + if any(len(index_results[e]) > 1 for e in index_results): + filtered_results: CoherenceMatches = [] + + for language in index_results: + filtered_results.append((language, max(index_results[language]))) + + return filtered_results + + return results + + +@lru_cache(maxsize=2048) +def coherence_ratio( + decoded_sequence: str, threshold: float = 0.1, lg_inclusion: Optional[str] = None +) -> CoherenceMatches: + """ + Detect ANY language that can be identified in given sequence. The sequence will be analysed by layers. + A layer = Character extraction by alphabets/ranges. + """ + + results: List[Tuple[str, float]] = [] + ignore_non_latin: bool = False + + sufficient_match_count: int = 0 + + lg_inclusion_list = lg_inclusion.split(",") if lg_inclusion is not None else [] + if "Latin Based" in lg_inclusion_list: + ignore_non_latin = True + lg_inclusion_list.remove("Latin Based") + + for layer in alpha_unicode_split(decoded_sequence): + sequence_frequencies: TypeCounter[str] = Counter(layer) + most_common = sequence_frequencies.most_common() + + character_count: int = sum(o for c, o in most_common) + + if character_count <= TOO_SMALL_SEQUENCE: + continue + + popular_character_ordered: List[str] = [c for c, o in most_common] + + for language in lg_inclusion_list or alphabet_languages( + popular_character_ordered, ignore_non_latin + ): + ratio: float = characters_popularity_compare( + language, popular_character_ordered + ) + + if ratio < threshold: + continue + elif ratio >= 0.8: + sufficient_match_count += 1 + + results.append((language, round(ratio, 4))) + + if sufficient_match_count >= 3: + break + + return sorted( + filter_alt_coherence_matches(results), key=lambda x: x[1], reverse=True + ) diff --git a/psets/9/finance/env/lib/python3.12/site-packages/charset_normalizer/cli/__init__.py b/psets/9/finance/env/lib/python3.12/site-packages/charset_normalizer/cli/__init__.py new file mode 100644 index 0000000..d95fedf --- /dev/null +++ b/psets/9/finance/env/lib/python3.12/site-packages/charset_normalizer/cli/__init__.py @@ -0,0 +1,6 @@ +from .__main__ import cli_detect, query_yes_no + +__all__ = ( + "cli_detect", + "query_yes_no", +) diff --git a/psets/9/finance/env/lib/python3.12/site-packages/charset_normalizer/cli/__main__.py b/psets/9/finance/env/lib/python3.12/site-packages/charset_normalizer/cli/__main__.py new file mode 100644 index 0000000..e7edd0f --- /dev/null +++ b/psets/9/finance/env/lib/python3.12/site-packages/charset_normalizer/cli/__main__.py @@ -0,0 +1,320 @@ +import argparse +import sys +from json import dumps +from os.path import abspath, basename, dirname, join, realpath +from platform import python_version +from typing import List, Optional +from unicodedata import unidata_version + +import charset_normalizer.md as md_module +from charset_normalizer import from_fp +from charset_normalizer.models import CliDetectionResult +from charset_normalizer.version import __version__ + + +def query_yes_no(question: str, default: str = "yes") -> bool: + """Ask a yes/no question via input() and return their answer. + + "question" is a string that is presented to the user. + "default" is the presumed answer if the user just hits . + It must be "yes" (the default), "no" or None (meaning + an answer is required of the user). + + The "answer" return value is True for "yes" or False for "no". + + Credit goes to (c) https://stackoverflow.com/questions/3041986/apt-command-line-interface-like-yes-no-input + """ + valid = {"yes": True, "y": True, "ye": True, "no": False, "n": False} + if default is None: + prompt = " [y/n] " + elif default == "yes": + prompt = " [Y/n] " + elif default == "no": + prompt = " [y/N] " + else: + raise ValueError("invalid default answer: '%s'" % default) + + while True: + sys.stdout.write(question + prompt) + choice = input().lower() + if default is not None and choice == "": + return valid[default] + elif choice in valid: + return valid[choice] + else: + sys.stdout.write("Please respond with 'yes' or 'no' " "(or 'y' or 'n').\n") + + +def cli_detect(argv: Optional[List[str]] = None) -> int: + """ + CLI assistant using ARGV and ArgumentParser + :param argv: + :return: 0 if everything is fine, anything else equal trouble + """ + parser = argparse.ArgumentParser( + description="The Real First Universal Charset Detector. " + "Discover originating encoding used on text file. " + "Normalize text to unicode." + ) + + parser.add_argument( + "files", type=argparse.FileType("rb"), nargs="+", help="File(s) to be analysed" + ) + parser.add_argument( + "-v", + "--verbose", + action="store_true", + default=False, + dest="verbose", + help="Display complementary information about file if any. " + "Stdout will contain logs about the detection process.", + ) + parser.add_argument( + "-a", + "--with-alternative", + action="store_true", + default=False, + dest="alternatives", + help="Output complementary possibilities if any. Top-level JSON WILL be a list.", + ) + parser.add_argument( + "-n", + "--normalize", + action="store_true", + default=False, + dest="normalize", + help="Permit to normalize input file. If not set, program does not write anything.", + ) + parser.add_argument( + "-m", + "--minimal", + action="store_true", + default=False, + dest="minimal", + help="Only output the charset detected to STDOUT. Disabling JSON output.", + ) + parser.add_argument( + "-r", + "--replace", + action="store_true", + default=False, + dest="replace", + help="Replace file when trying to normalize it instead of creating a new one.", + ) + parser.add_argument( + "-f", + "--force", + action="store_true", + default=False, + dest="force", + help="Replace file without asking if you are sure, use this flag with caution.", + ) + parser.add_argument( + "-i", + "--no-preemptive", + action="store_true", + default=False, + dest="no_preemptive", + help="Disable looking at a charset declaration to hint the detector.", + ) + parser.add_argument( + "-t", + "--threshold", + action="store", + default=0.2, + type=float, + dest="threshold", + help="Define a custom maximum amount of chaos allowed in decoded content. 0. <= chaos <= 1.", + ) + parser.add_argument( + "--version", + action="version", + version="Charset-Normalizer {} - Python {} - Unicode {} - SpeedUp {}".format( + __version__, + python_version(), + unidata_version, + "OFF" if md_module.__file__.lower().endswith(".py") else "ON", + ), + help="Show version information and exit.", + ) + + args = parser.parse_args(argv) + + if args.replace is True and args.normalize is False: + if args.files: + for my_file in args.files: + my_file.close() + print("Use --replace in addition of --normalize only.", file=sys.stderr) + return 1 + + if args.force is True and args.replace is False: + if args.files: + for my_file in args.files: + my_file.close() + print("Use --force in addition of --replace only.", file=sys.stderr) + return 1 + + if args.threshold < 0.0 or args.threshold > 1.0: + if args.files: + for my_file in args.files: + my_file.close() + print("--threshold VALUE should be between 0. AND 1.", file=sys.stderr) + return 1 + + x_ = [] + + for my_file in args.files: + matches = from_fp( + my_file, + threshold=args.threshold, + explain=args.verbose, + preemptive_behaviour=args.no_preemptive is False, + ) + + best_guess = matches.best() + + if best_guess is None: + print( + 'Unable to identify originating encoding for "{}". {}'.format( + my_file.name, + ( + "Maybe try increasing maximum amount of chaos." + if args.threshold < 1.0 + else "" + ), + ), + file=sys.stderr, + ) + x_.append( + CliDetectionResult( + abspath(my_file.name), + None, + [], + [], + "Unknown", + [], + False, + 1.0, + 0.0, + None, + True, + ) + ) + else: + x_.append( + CliDetectionResult( + abspath(my_file.name), + best_guess.encoding, + best_guess.encoding_aliases, + [ + cp + for cp in best_guess.could_be_from_charset + if cp != best_guess.encoding + ], + best_guess.language, + best_guess.alphabets, + best_guess.bom, + best_guess.percent_chaos, + best_guess.percent_coherence, + None, + True, + ) + ) + + if len(matches) > 1 and args.alternatives: + for el in matches: + if el != best_guess: + x_.append( + CliDetectionResult( + abspath(my_file.name), + el.encoding, + el.encoding_aliases, + [ + cp + for cp in el.could_be_from_charset + if cp != el.encoding + ], + el.language, + el.alphabets, + el.bom, + el.percent_chaos, + el.percent_coherence, + None, + False, + ) + ) + + if args.normalize is True: + if best_guess.encoding.startswith("utf") is True: + print( + '"{}" file does not need to be normalized, as it already came from unicode.'.format( + my_file.name + ), + file=sys.stderr, + ) + if my_file.closed is False: + my_file.close() + continue + + dir_path = dirname(realpath(my_file.name)) + file_name = basename(realpath(my_file.name)) + + o_: List[str] = file_name.split(".") + + if args.replace is False: + o_.insert(-1, best_guess.encoding) + if my_file.closed is False: + my_file.close() + elif ( + args.force is False + and query_yes_no( + 'Are you sure to normalize "{}" by replacing it ?'.format( + my_file.name + ), + "no", + ) + is False + ): + if my_file.closed is False: + my_file.close() + continue + + try: + x_[0].unicode_path = join(dir_path, ".".join(o_)) + + with open(x_[0].unicode_path, "wb") as fp: + fp.write(best_guess.output()) + except IOError as e: + print(str(e), file=sys.stderr) + if my_file.closed is False: + my_file.close() + return 2 + + if my_file.closed is False: + my_file.close() + + if args.minimal is False: + print( + dumps( + [el.__dict__ for el in x_] if len(x_) > 1 else x_[0].__dict__, + ensure_ascii=True, + indent=4, + ) + ) + else: + for my_file in args.files: + print( + ", ".join( + [ + el.encoding or "undefined" + for el in x_ + if el.path == abspath(my_file.name) + ] + ) + ) + + return 0 + + +if __name__ == "__main__": + cli_detect() diff --git a/psets/9/finance/env/lib/python3.12/site-packages/charset_normalizer/cli/__pycache__/__init__.cpython-312.pyc b/psets/9/finance/env/lib/python3.12/site-packages/charset_normalizer/cli/__pycache__/__init__.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..041af64020c171d53d6dbd1ed88389e1428061b1 GIT binary patch literal 292 zcmXv}J5Izf5Vf61yINS$a)lIR_=o}tQBl*AX5_Vptig7I?L`VyoPslO7H*J+f{JdX z?Wk}hnBvWQ^U=)vSS}YV$JfhktEW7P{}6vDM+<)9q7;vD7zPqW)agOMu@ra?w)1k~T&Jd-wi0^EdCHuJt=M!AZL>^S9 zjc-B4^JC~Er3e>rXT0=^fcz6!vx0s|>&~CmC#MiiqN84_2iZ~twU#08vgN0&$gwQTkt#o8%W!UOzd>A-2&~o zcQ~YM(;Ed?>`3C=$GPX8_dPsU|7N#a2zdVU?bpX|ZG$)JsE?`8c=R98m?s#5(Qw3w z^45%Kps(e$aovbcgT{26K5iH>#Em1yxM{=`Cr8M*dBlw8^qeJb9kJrJfwRT!Blfss z#DV)pt|IOnapJaytBhBTxNzIVx#QI%)woS^HSyY!THH2sp160!3++nA!qzcX__ML~ zV@AgQr-qRRriyW}4%W`rd4X#52eXZ1dZq$qo7iT?ISG6Uq?TZtZWS2R5Yw7zjoYwmyWCN3mCq=(OHqoPEl9nc9a+DTXo{qD!iHQohp^qh^yi5u#%^?t2=15LU6A3{ZLetWb$NEfJT!Sc#1w_|vSI z;v^WghE?crSSG)lVns9!l(1toK*&acl~Mv9(H8hYFC+Zv;P26X4OX6pK|fmf(Y0c`S#Q?))HOU5`G)~0GK^2PEs^A&59vDL8;=WE<|Z6$|qCOHa|u445cW6k|x-w z00ZI_D+DbT3Lc-j#z#d(z$8jSlphC3T0#R!fd$)=ScZ}kXgQS<(Nes!pkllbO(ED+ z96*%~sOVU61rVM8(nUC`O_KPscmtV=7B&=0a{J-#qC63^Si0202CxjTl)))4g*r3LYYsM#|4^8v53uK0p4S< zi9!K1`e{xq48i^d97h0mRHDWctcc{XE#jvpBq=F&g+ii4Ms4be#{05fsWNPvs-Y#@q6F-AvN=uWZ$;6A`7U=$RG8655hKi9#qteKXz z)2yuJ6S9U+o2WOYL;RbR;0EJDz1MNCw$Pgnop_Tc{l9NCzJkdlPR5Sd6sBdlnEIiyMIe`29H zFNOMOiRD9)1OsXgMZ`TFp`^%4V(36<-YtJW&djv0_+6E0u@Q+}7SIte(+iG%=)@FtnGc+XQqy(}1BHnWjxZH-iHrE?XGiCZM-4tr)tE*}4hnc4iynXSPeEstV=> zX2NFLY|BtsY-3dPyl-BiJ>s`)T82vp|kI) zhuNvxji6YmO z>e)G=rTlmw@h0#;qs!=GTb^B|a;hP&x%Gt9rb00Lq^)W@23g+I&+YxU3VsP0-vQWp z`_mAREvlT9M7Znk@}4-Sn#j$U5;Hr$L8km8lKmOf%u z|E3Swg%ncx&FISW2csP-Oz91yyGlK^#eiOK_o!YlW5^g{d(^qoTeZ3wW5#&-dmF6o zrE*>lmb#`JCxqiLA5QtsJ6;erN##4&^R$p zFh}6e%5*aanM2IpTUKSQ3Zo%rb^M_})Q%ZrtVgA-^oG%wN*U)d(3Yrx7w%UL)3Lt^3-K^#n-1+&Km(!>mU5q`ZB_&XjbdwwS)6 zPSL3{ydh>B-F(bYaeRw-po>G-S6jb7a;P-Un58$= z72kTTC1Z)bsje=)nf@YnD`@6<=kmdfH5M+dQd`Wi^7>MvEaW`Tm)6)fNsB)V6qU;& zkgShMbdidezrDVh0hLCqIqLV&`OR9@UHdyI)c<_l2I1xs0UR273PnOm1Mml#F=)CX* zD%{y@#(+z3&P>_(eo-T8L3gKs=e-KgDj(__^7rrPiRr-zz@Za)3O?1=7GfuyYg5pF zozTF~wclOTy-rMNwh$7h(%VW1$7k#tbd^wNGIn*3KTgzq9c*;Qe#s8sD~6QTlxB)h zC@%0s7P*6#|CRI=3#!K)85*EyQG_Zn%}Y@DLv_K!r;oh~g(QYLEQ~{~kC#rNN{fKu zyOOj($0<~a=u!rhvSSz3fog#)6vv=BN-0Svgdo)y6(gtu2j#2iIFyPcv=z%Ml_XTS zgt{P4N$f=lcIVh2R1^#4A!QIMdQboda5jhv+YBp4geb0#%LcSSl(oXBta%|_(+|CE zq94@&p=wD(^?Vwz`*pHjnodFqj0YKrvVMZ)l4)(=LfRY%09~UAk(Di?ln~gk1O>-_ z*;E)!$AI=EM^95w9!zp95-crDLkSmZl5t=J=%z=Z$c70=!UVwusWZ6n28BD0gN3jp z%2Qlo9Ll&DRw<(v3ieQ)O+c|t4Epu5k;XNAr7EWfJ|!Ut)(NE2>8d~g6#@e^2c=0Q z!walz+t3ly11D1w6eyn}HJJcQ8I5vLDGJ3=mBQgfGQff2Ico6C$rIGMfuSKRF^U7L z3c`kb+8ThGXF(6Lx!6n(onnPJ6k9>Y#X+T}UC`dZ7)(eM)cJNG=EjljF{m<&MsY2& zXkKWiIMPBq%15ChD4Pn6bni)?o2Edrh$AGhLg^5Srbuu~-TTaN-^sJX*udyfDBO-K z+$gIMZUNyISkPbuE@29d^s&>*h@!Nq2^Ne`m`2N=#Yya6W7Kpa1)j)KVoCr%1LFtoklS(exKinj z&?#hB2zxYLfs_z{0zM0sS)_71p9q(_=^n68V4Vf?O5h#fc7Wa>s|W|KkIfWV0~c3h zsmKsq6ZVjhqNNEaHcuotMmAtK82{@<^!)1~*<74TpY3B&a6tIsS|Aap;`GI6JOzOz zo=5>^sO^K25@6*VsxdPlJFvs5Y%0$#Ef}b>u$VCw8u>%%zy?iGuO1#cdz1pLr8oxp?kFow zv0%y|;ln5TkYsg27wjpU*o)u*aP8eyD>x4Dft&*$L(egZpn%dr*>sklB_=|O}`@xfwv z;6YV|=v@ph3>-%gxxlbF*oJ{v3|FcYy8kR53$iBo#s9&R?l=stgU@<=#o?G8#dr=X2| zf$?|CB%CR5z`_yYc=GIp@XRn_n8oL@OrpbS7#~A$6-C263&<1B5CIi*1$3P$*x*Ap z$C+?E!K64=Cc|N5I^nR;jAlrdXGC-e$QHaI!YvA@VkAIXMhJccWQcI+I5Q;Sx=<2O zVHRHmv4SALw|)YfgkVQ4RO%A;BLMv<95u2Y-%uOrWD@ofAR#3LBnh;wa#YJswH1cT z8@QqphX_@3`emn(NKC&4ux+iF`O;Og3CgQR^$wIK?r7#W^a%Hib zm|z7!&&oQE<%LePF&xRXASoOhFnzL*00tC?wq-I=v-b$7(9;&t-+W#Zh*AqNLQ|+KIg2?*=zDz zjpHRv-i{$jfUJ5FvO$Hc&)HuqfSCZy`6O7i3g*e#-*`S)Y2TdvmCb>@`h2iTbyIiF ze(w2TUKOk%XFvXYFkqo3=X9;xt8#YWg2`8ul?kxm$vKa&Ift{(;dNW>x~*>2*064? zU$1Ujt8UL$x35(Pvekjr>d;#C{%rOByVdur4_!U_@$e(Fq0$06bL`5yFlr0P(L>m( z)~pR#Ys13us?~S7@1e>1=b3jhvr^Vnzoh@bano_9ElcgoSu3u0{h%vX-+ZI%y{=hP z&RIKepR@m{0+iga^>fmG&(ZU*sZ!)O|`070_II=hA|1#Z5gutc{6BU{MnJ84}LQEDR~m1FCL%o@h^;f9@W|^tNvT(fc4b#);F!W+q3TWoEsXUtUClWZ3(RTdRKhCj|}?inqT{R z7kYE`jZ1ZFExWTVyI1OWe`O%N^*LYfmuNn3A*!1<;MkURZv$lWC+1FIoIA4a9k|hv zb$4KLJ&&55z@M(l?s&Y7aJpvq{Y7ShUa4qa>RW5wv(mcfmvt?(y}4TN!pLfEd(KmL z!@Ou-ZwRha?aQW*Y#-WIsXaN$_ks1M6<%vpXO`*&szW>1g8eJOexSO=_v>K)vNqT5 zUq1cO8y~*0(!L*PZfnm4`+?>bAJE*grLg`3+f5t7X1r;{*gCRQ2X5@nQoD0hYmRCI zdK;U*)>V1y@&=;bm)}7+-PbQ&y|mEe_*AkwF`ScIdSB_z?b%o=!gJ2)t z`Wx0o>xyUB(%V_juAHwGd&wi6v9juG9SNSOBRoEEXPf=EU!Bu|1O4`^AeiKDVj5r+ z{`cc|pVu~hMd(3(Ztr_r7U;j(`o8!<`eyo5_pUP9d#~a_eZ%kaW`O_SuRKKM3%~uU z3UG=8a0LH*kLP@&d&T5A@2mMmW%v0`t!$^xw;SXD3GH>Q>n)q@LCt};DjlD-8_su_ zKigq~@y|NVZz`Gk+Ko09gyG(76gFq;$&+f9YX&_sHBe+dmHp<>-CxVc#LZJxfjB;I>`NDTBCDn~1^!m|6g2VZmtV4+^ z%5jiPP<|8+e@F", + "=", + ":", + "/", + "&", + ";", + "{", + "}", + "[", + "]", + ",", + "|", + '"', + "-", + "(", + ")", +} + + +KO_NAMES: Set[str] = {"johab", "cp949", "euc_kr"} +ZH_NAMES: Set[str] = {"big5", "cp950", "big5hkscs", "hz"} + +# Logging LEVEL below DEBUG +TRACE: int = 5 + + +# Language label that contain the em dash "—" +# character are to be considered alternative seq to origin +FREQUENCIES: Dict[str, List[str]] = { + "English": [ + "e", + "a", + "t", + "i", + "o", + "n", + "s", + "r", + "h", + "l", + "d", + "c", + "u", + "m", + "f", + "p", + "g", + "w", + "y", + "b", + "v", + "k", + "x", + "j", + "z", + "q", + ], + "English—": [ + "e", + "a", + "t", + "i", + "o", + "n", + "s", + "r", + "h", + "l", + "d", + "c", + "m", + "u", + "f", + "p", + "g", + "w", + "b", + "y", + "v", + "k", + "j", + "x", + "z", + "q", + ], + "German": [ + "e", + "n", + "i", + "r", + "s", + "t", + "a", + "d", + "h", + "u", + "l", + "g", + "o", + "c", + "m", + "b", + "f", + "k", + "w", + "z", + "p", + "v", + "ü", + "ä", + "ö", + "j", + ], + "French": [ + "e", + "a", + "s", + "n", + "i", + "t", + "r", + "l", + "u", + "o", + "d", + "c", + "p", + "m", + "é", + "v", + "g", + "f", + "b", + "h", + "q", + "à", + "x", + "è", + "y", + "j", + ], + "Dutch": [ + "e", + "n", + "a", + "i", + "r", + "t", + "o", + "d", + "s", + "l", + "g", + "h", + "v", + "m", + "u", + "k", + "c", + "p", + "b", + "w", + "j", + "z", + "f", + "y", + "x", + "ë", + ], + "Italian": [ + "e", + "i", + "a", + "o", + "n", + "l", + "t", + "r", + "s", + "c", + "d", + "u", + "p", + "m", + "g", + "v", + "f", + "b", + "z", + "h", + "q", + "è", + "à", + "k", + "y", + "ò", + ], + "Polish": [ + "a", + "i", + "o", + "e", + "n", + "r", + "z", + "w", + "s", + "c", + "t", + "k", + "y", + "d", + "p", + "m", + "u", + "l", + "j", + "ł", + "g", + "b", + "h", + "ą", + "ę", + "ó", + ], + "Spanish": [ + "e", + "a", + "o", + "n", + "s", + "r", + "i", + "l", + "d", + "t", + "c", + "u", + "m", + "p", + "b", + "g", + "v", + "f", + "y", + "ó", + "h", + "q", + "í", + "j", + "z", + "á", + ], + "Russian": [ + "о", + "а", + "е", + "и", + "н", + "с", + "т", + "р", + "в", + "л", + "к", + "м", + "д", + "п", + "у", + "г", + "я", + "ы", + "з", + "б", + "й", + "ь", + "ч", + "х", + "ж", + "ц", + ], + # Jap-Kanji + "Japanese": [ + "人", + "一", + "大", + "亅", + "丁", + "丨", + "竹", + "笑", + "口", + "日", + "今", + "二", + "彳", + "行", + "十", + "土", + "丶", + "寸", + "寺", + "時", + "乙", + "丿", + "乂", + "气", + "気", + "冂", + "巾", + "亠", + "市", + "目", + "儿", + "見", + "八", + "小", + "凵", + "県", + "月", + "彐", + "門", + "間", + "木", + "東", + "山", + "出", + "本", + "中", + "刀", + "分", + "耳", + "又", + "取", + "最", + "言", + "田", + "心", + "思", + "刂", + "前", + "京", + "尹", + "事", + "生", + "厶", + "云", + "会", + "未", + "来", + "白", + "冫", + "楽", + "灬", + "馬", + "尸", + "尺", + "駅", + "明", + "耂", + "者", + "了", + "阝", + "都", + "高", + "卜", + "占", + "厂", + "广", + "店", + "子", + "申", + "奄", + "亻", + "俺", + "上", + "方", + "冖", + "学", + "衣", + "艮", + "食", + "自", + ], + # Jap-Katakana + "Japanese—": [ + "ー", + "ン", + "ス", + "・", + "ル", + "ト", + "リ", + "イ", + "ア", + "ラ", + "ッ", + "ク", + "ド", + "シ", + "レ", + "ジ", + "タ", + "フ", + "ロ", + "カ", + "テ", + "マ", + "ィ", + "グ", + "バ", + "ム", + "プ", + "オ", + "コ", + "デ", + "ニ", + "ウ", + "メ", + "サ", + "ビ", + "ナ", + "ブ", + "ャ", + "エ", + "ュ", + "チ", + "キ", + "ズ", + "ダ", + "パ", + "ミ", + "ェ", + "ョ", + "ハ", + "セ", + "ベ", + "ガ", + "モ", + "ツ", + "ネ", + "ボ", + "ソ", + "ノ", + "ァ", + "ヴ", + "ワ", + "ポ", + "ペ", + "ピ", + "ケ", + "ゴ", + "ギ", + "ザ", + "ホ", + "ゲ", + "ォ", + "ヤ", + "ヒ", + "ユ", + "ヨ", + "ヘ", + "ゼ", + "ヌ", + "ゥ", + "ゾ", + "ヶ", + "ヂ", + "ヲ", + "ヅ", + "ヵ", + "ヱ", + "ヰ", + "ヮ", + "ヽ", + "゠", + "ヾ", + "ヷ", + "ヿ", + "ヸ", + "ヹ", + "ヺ", + ], + # Jap-Hiragana + "Japanese——": [ + "の", + "に", + "る", + "た", + "と", + "は", + "し", + "い", + "を", + "で", + "て", + "が", + "な", + "れ", + "か", + "ら", + "さ", + "っ", + "り", + "す", + "あ", + "も", + "こ", + "ま", + "う", + "く", + "よ", + "き", + "ん", + "め", + "お", + "け", + "そ", + "つ", + "だ", + "や", + "え", + "ど", + "わ", + "ち", + "み", + "せ", + "じ", + "ば", + "へ", + "び", + "ず", + "ろ", + "ほ", + "げ", + "む", + "べ", + "ひ", + "ょ", + "ゆ", + "ぶ", + "ご", + "ゃ", + "ね", + "ふ", + "ぐ", + "ぎ", + "ぼ", + "ゅ", + "づ", + "ざ", + "ぞ", + "ぬ", + "ぜ", + "ぱ", + "ぽ", + "ぷ", + "ぴ", + "ぃ", + "ぁ", + "ぇ", + "ぺ", + "ゞ", + "ぢ", + "ぉ", + "ぅ", + "ゐ", + "ゝ", + "ゑ", + "゛", + "゜", + "ゎ", + "ゔ", + "゚", + "ゟ", + "゙", + "ゕ", + "ゖ", + ], + "Portuguese": [ + "a", + "e", + "o", + "s", + "i", + "r", + "d", + "n", + "t", + "m", + "u", + "c", + "l", + "p", + "g", + "v", + "b", + "f", + "h", + "ã", + "q", + "é", + "ç", + "á", + "z", + "í", + ], + "Swedish": [ + "e", + "a", + "n", + "r", + "t", + "s", + "i", + "l", + "d", + "o", + "m", + "k", + "g", + "v", + "h", + "f", + "u", + "p", + "ä", + "c", + "b", + "ö", + "å", + "y", + "j", + "x", + ], + "Chinese": [ + "的", + "一", + "是", + "不", + "了", + "在", + "人", + "有", + "我", + "他", + "这", + "个", + "们", + "中", + "来", + "上", + "大", + "为", + "和", + "国", + "地", + "到", + "以", + "说", + "时", + "要", + "就", + "出", + "会", + "可", + "也", + "你", + "对", + "生", + "能", + "而", + "子", + "那", + "得", + "于", + "着", + "下", + "自", + "之", + "年", + "过", + "发", + "后", + "作", + "里", + "用", + "道", + "行", + "所", + "然", + "家", + "种", + "事", + "成", + "方", + "多", + "经", + "么", + "去", + "法", + "学", + "如", + "都", + "同", + "现", + "当", + "没", + "动", + "面", + "起", + "看", + "定", + "天", + "分", + "还", + "进", + "好", + "小", + "部", + "其", + "些", + "主", + "样", + "理", + "心", + "她", + "本", + "前", + "开", + "但", + "因", + "只", + "从", + "想", + "实", + ], + "Ukrainian": [ + "о", + "а", + "н", + "і", + "и", + "р", + "в", + "т", + "е", + "с", + "к", + "л", + "у", + "д", + "м", + "п", + "з", + "я", + "ь", + "б", + "г", + "й", + "ч", + "х", + "ц", + "ї", + ], + "Norwegian": [ + "e", + "r", + "n", + "t", + "a", + "s", + "i", + "o", + "l", + "d", + "g", + "k", + "m", + "v", + "f", + "p", + "u", + "b", + "h", + "å", + "y", + "j", + "ø", + "c", + "æ", + "w", + ], + "Finnish": [ + "a", + "i", + "n", + "t", + "e", + "s", + "l", + "o", + "u", + "k", + "ä", + "m", + "r", + "v", + "j", + "h", + "p", + "y", + "d", + "ö", + "g", + "c", + "b", + "f", + "w", + "z", + ], + "Vietnamese": [ + "n", + "h", + "t", + "i", + "c", + "g", + "a", + "o", + "u", + "m", + "l", + "r", + "à", + "đ", + "s", + "e", + "v", + "p", + "b", + "y", + "ư", + "d", + "á", + "k", + "ộ", + "ế", + ], + "Czech": [ + "o", + "e", + "a", + "n", + "t", + "s", + "i", + "l", + "v", + "r", + "k", + "d", + "u", + "m", + "p", + "í", + "c", + "h", + "z", + "á", + "y", + "j", + "b", + "ě", + "é", + "ř", + ], + "Hungarian": [ + "e", + "a", + "t", + "l", + "s", + "n", + "k", + "r", + "i", + "o", + "z", + "á", + "é", + "g", + "m", + "b", + "y", + "v", + "d", + "h", + "u", + "p", + "j", + "ö", + "f", + "c", + ], + "Korean": [ + "이", + "다", + "에", + "의", + "는", + "로", + "하", + "을", + "가", + "고", + "지", + "서", + "한", + "은", + "기", + "으", + "년", + "대", + "사", + "시", + "를", + "리", + "도", + "인", + "스", + "일", + ], + "Indonesian": [ + "a", + "n", + "e", + "i", + "r", + "t", + "u", + "s", + "d", + "k", + "m", + "l", + "g", + "p", + "b", + "o", + "h", + "y", + "j", + "c", + "w", + "f", + "v", + "z", + "x", + "q", + ], + "Turkish": [ + "a", + "e", + "i", + "n", + "r", + "l", + "ı", + "k", + "d", + "t", + "s", + "m", + "y", + "u", + "o", + "b", + "ü", + "ş", + "v", + "g", + "z", + "h", + "c", + "p", + "ç", + "ğ", + ], + "Romanian": [ + "e", + "i", + "a", + "r", + "n", + "t", + "u", + "l", + "o", + "c", + "s", + "d", + "p", + "m", + "ă", + "f", + "v", + "î", + "g", + "b", + "ș", + "ț", + "z", + "h", + "â", + "j", + ], + "Farsi": [ + "ا", + "ی", + "ر", + "د", + "ن", + "ه", + "و", + "م", + "ت", + "ب", + "س", + "ل", + "ک", + "ش", + "ز", + "ف", + "گ", + "ع", + "خ", + "ق", + "ج", + "آ", + "پ", + "ح", + "ط", + "ص", + ], + "Arabic": [ + "ا", + "ل", + "ي", + "م", + "و", + "ن", + "ر", + "ت", + "ب", + "ة", + "ع", + "د", + "س", + "ف", + "ه", + "ك", + "ق", + "أ", + "ح", + "ج", + "ش", + "ط", + "ص", + "ى", + "خ", + "إ", + ], + "Danish": [ + "e", + "r", + "n", + "t", + "a", + "i", + "s", + "d", + "l", + "o", + "g", + "m", + "k", + "f", + "v", + "u", + "b", + "h", + "p", + "å", + "y", + "ø", + "æ", + "c", + "j", + "w", + ], + "Serbian": [ + "а", + "и", + "о", + "е", + "н", + "р", + "с", + "у", + "т", + "к", + "ј", + "в", + "д", + "м", + "п", + "л", + "г", + "з", + "б", + "a", + "i", + "e", + "o", + "n", + "ц", + "ш", + ], + "Lithuanian": [ + "i", + "a", + "s", + "o", + "r", + "e", + "t", + "n", + "u", + "k", + "m", + "l", + "p", + "v", + "d", + "j", + "g", + "ė", + "b", + "y", + "ų", + "š", + "ž", + "c", + "ą", + "į", + ], + "Slovene": [ + "e", + "a", + "i", + "o", + "n", + "r", + "s", + "l", + "t", + "j", + "v", + "k", + "d", + "p", + "m", + "u", + "z", + "b", + "g", + "h", + "č", + "c", + "š", + "ž", + "f", + "y", + ], + "Slovak": [ + "o", + "a", + "e", + "n", + "i", + "r", + "v", + "t", + "s", + "l", + "k", + "d", + "m", + "p", + "u", + "c", + "h", + "j", + "b", + "z", + "á", + "y", + "ý", + "í", + "č", + "é", + ], + "Hebrew": [ + "י", + "ו", + "ה", + "ל", + "ר", + "ב", + "ת", + "מ", + "א", + "ש", + "נ", + "ע", + "ם", + "ד", + "ק", + "ח", + "פ", + "ס", + "כ", + "ג", + "ט", + "צ", + "ן", + "ז", + "ך", + ], + "Bulgarian": [ + "а", + "и", + "о", + "е", + "н", + "т", + "р", + "с", + "в", + "л", + "к", + "д", + "п", + "м", + "з", + "г", + "я", + "ъ", + "у", + "б", + "ч", + "ц", + "й", + "ж", + "щ", + "х", + ], + "Croatian": [ + "a", + "i", + "o", + "e", + "n", + "r", + "j", + "s", + "t", + "u", + "k", + "l", + "v", + "d", + "m", + "p", + "g", + "z", + "b", + "c", + "č", + "h", + "š", + "ž", + "ć", + "f", + ], + "Hindi": [ + "क", + "र", + "स", + "न", + "त", + "म", + "ह", + "प", + "य", + "ल", + "व", + "ज", + "द", + "ग", + "ब", + "श", + "ट", + "अ", + "ए", + "थ", + "भ", + "ड", + "च", + "ध", + "ष", + "इ", + ], + "Estonian": [ + "a", + "i", + "e", + "s", + "t", + "l", + "u", + "n", + "o", + "k", + "r", + "d", + "m", + "v", + "g", + "p", + "j", + "h", + "ä", + "b", + "õ", + "ü", + "f", + "c", + "ö", + "y", + ], + "Thai": [ + "า", + "น", + "ร", + "อ", + "ก", + "เ", + "ง", + "ม", + "ย", + "ล", + "ว", + "ด", + "ท", + "ส", + "ต", + "ะ", + "ป", + "บ", + "ค", + "ห", + "แ", + "จ", + "พ", + "ช", + "ข", + "ใ", + ], + "Greek": [ + "α", + "τ", + "ο", + "ι", + "ε", + "ν", + "ρ", + "σ", + "κ", + "η", + "π", + "ς", + "υ", + "μ", + "λ", + "ί", + "ό", + "ά", + "γ", + "έ", + "δ", + "ή", + "ω", + "χ", + "θ", + "ύ", + ], + "Tamil": [ + "க", + "த", + "ப", + "ட", + "ர", + "ம", + "ல", + "ன", + "வ", + "ற", + "ய", + "ள", + "ச", + "ந", + "இ", + "ண", + "அ", + "ஆ", + "ழ", + "ங", + "எ", + "உ", + "ஒ", + "ஸ", + ], + "Kazakh": [ + "а", + "ы", + "е", + "н", + "т", + "р", + "л", + "і", + "д", + "с", + "м", + "қ", + "к", + "о", + "б", + "и", + "у", + "ғ", + "ж", + "ң", + "з", + "ш", + "й", + "п", + "г", + "ө", + ], +} + +LANGUAGE_SUPPORTED_COUNT: int = len(FREQUENCIES) diff --git a/psets/9/finance/env/lib/python3.12/site-packages/charset_normalizer/legacy.py b/psets/9/finance/env/lib/python3.12/site-packages/charset_normalizer/legacy.py new file mode 100644 index 0000000..3f6d490 --- /dev/null +++ b/psets/9/finance/env/lib/python3.12/site-packages/charset_normalizer/legacy.py @@ -0,0 +1,65 @@ +from __future__ import annotations + +from typing import TYPE_CHECKING, Any, Optional +from warnings import warn + +from .api import from_bytes +from .constant import CHARDET_CORRESPONDENCE + +# TODO: remove this check when dropping Python 3.7 support +if TYPE_CHECKING: + from typing_extensions import TypedDict + + class ResultDict(TypedDict): + encoding: Optional[str] + language: str + confidence: Optional[float] + + +def detect( + byte_str: bytes, should_rename_legacy: bool = False, **kwargs: Any +) -> ResultDict: + """ + chardet legacy method + Detect the encoding of the given byte string. It should be mostly backward-compatible. + Encoding name will match Chardet own writing whenever possible. (Not on encoding name unsupported by it) + This function is deprecated and should be used to migrate your project easily, consult the documentation for + further information. Not planned for removal. + + :param byte_str: The byte sequence to examine. + :param should_rename_legacy: Should we rename legacy encodings + to their more modern equivalents? + """ + if len(kwargs): + warn( + f"charset-normalizer disregard arguments '{','.join(list(kwargs.keys()))}' in legacy function detect()" + ) + + if not isinstance(byte_str, (bytearray, bytes)): + raise TypeError( # pragma: nocover + "Expected object of type bytes or bytearray, got: " + "{0}".format(type(byte_str)) + ) + + if isinstance(byte_str, bytearray): + byte_str = bytes(byte_str) + + r = from_bytes(byte_str).best() + + encoding = r.encoding if r is not None else None + language = r.language if r is not None and r.language != "Unknown" else "" + confidence = 1.0 - r.chaos if r is not None else None + + # Note: CharsetNormalizer does not return 'UTF-8-SIG' as the sig get stripped in the detection/normalization process + # but chardet does return 'utf-8-sig' and it is a valid codec name. + if r is not None and encoding == "utf_8" and r.bom: + encoding += "_sig" + + if should_rename_legacy is False and encoding in CHARDET_CORRESPONDENCE: + encoding = CHARDET_CORRESPONDENCE[encoding] + + return { + "encoding": encoding, + "language": language, + "confidence": confidence, + } diff --git a/psets/9/finance/env/lib/python3.12/site-packages/charset_normalizer/md.cpython-312-x86_64-linux-gnu.so b/psets/9/finance/env/lib/python3.12/site-packages/charset_normalizer/md.cpython-312-x86_64-linux-gnu.so new file mode 100644 index 0000000000000000000000000000000000000000..3d0b46ae77baa966a03418d61fbd1da9d141366e GIT binary patch literal 16064 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 literal 0 HcmV?d00001 diff --git a/psets/9/finance/env/lib/python3.12/site-packages/charset_normalizer/md.py b/psets/9/finance/env/lib/python3.12/site-packages/charset_normalizer/md.py new file mode 100644 index 0000000..d834db0 --- /dev/null +++ b/psets/9/finance/env/lib/python3.12/site-packages/charset_normalizer/md.py @@ -0,0 +1,628 @@ +from functools import lru_cache +from logging import getLogger +from typing import List, Optional + +from .constant import ( + COMMON_SAFE_ASCII_CHARACTERS, + TRACE, + UNICODE_SECONDARY_RANGE_KEYWORD, +) +from .utils import ( + is_accentuated, + is_arabic, + is_arabic_isolated_form, + is_case_variable, + is_cjk, + is_emoticon, + is_hangul, + is_hiragana, + is_katakana, + is_latin, + is_punctuation, + is_separator, + is_symbol, + is_thai, + is_unprintable, + remove_accent, + unicode_range, +) + + +class MessDetectorPlugin: + """ + Base abstract class used for mess detection plugins. + All detectors MUST extend and implement given methods. + """ + + def eligible(self, character: str) -> bool: + """ + Determine if given character should be fed in. + """ + raise NotImplementedError # pragma: nocover + + def feed(self, character: str) -> None: + """ + The main routine to be executed upon character. + Insert the logic in witch the text would be considered chaotic. + """ + raise NotImplementedError # pragma: nocover + + def reset(self) -> None: # pragma: no cover + """ + Permit to reset the plugin to the initial state. + """ + raise NotImplementedError + + @property + def ratio(self) -> float: + """ + Compute the chaos ratio based on what your feed() has seen. + Must NOT be lower than 0.; No restriction gt 0. + """ + raise NotImplementedError # pragma: nocover + + +class TooManySymbolOrPunctuationPlugin(MessDetectorPlugin): + def __init__(self) -> None: + self._punctuation_count: int = 0 + self._symbol_count: int = 0 + self._character_count: int = 0 + + self._last_printable_char: Optional[str] = None + self._frenzy_symbol_in_word: bool = False + + def eligible(self, character: str) -> bool: + return character.isprintable() + + def feed(self, character: str) -> None: + self._character_count += 1 + + if ( + character != self._last_printable_char + and character not in COMMON_SAFE_ASCII_CHARACTERS + ): + if is_punctuation(character): + self._punctuation_count += 1 + elif ( + character.isdigit() is False + and is_symbol(character) + and is_emoticon(character) is False + ): + self._symbol_count += 2 + + self._last_printable_char = character + + def reset(self) -> None: # pragma: no cover + self._punctuation_count = 0 + self._character_count = 0 + self._symbol_count = 0 + + @property + def ratio(self) -> float: + if self._character_count == 0: + return 0.0 + + ratio_of_punctuation: float = ( + self._punctuation_count + self._symbol_count + ) / self._character_count + + return ratio_of_punctuation if ratio_of_punctuation >= 0.3 else 0.0 + + +class TooManyAccentuatedPlugin(MessDetectorPlugin): + def __init__(self) -> None: + self._character_count: int = 0 + self._accentuated_count: int = 0 + + def eligible(self, character: str) -> bool: + return character.isalpha() + + def feed(self, character: str) -> None: + self._character_count += 1 + + if is_accentuated(character): + self._accentuated_count += 1 + + def reset(self) -> None: # pragma: no cover + self._character_count = 0 + self._accentuated_count = 0 + + @property + def ratio(self) -> float: + if self._character_count < 8: + return 0.0 + + ratio_of_accentuation: float = self._accentuated_count / self._character_count + return ratio_of_accentuation if ratio_of_accentuation >= 0.35 else 0.0 + + +class UnprintablePlugin(MessDetectorPlugin): + def __init__(self) -> None: + self._unprintable_count: int = 0 + self._character_count: int = 0 + + def eligible(self, character: str) -> bool: + return True + + def feed(self, character: str) -> None: + if is_unprintable(character): + self._unprintable_count += 1 + self._character_count += 1 + + def reset(self) -> None: # pragma: no cover + self._unprintable_count = 0 + + @property + def ratio(self) -> float: + if self._character_count == 0: + return 0.0 + + return (self._unprintable_count * 8) / self._character_count + + +class SuspiciousDuplicateAccentPlugin(MessDetectorPlugin): + def __init__(self) -> None: + self._successive_count: int = 0 + self._character_count: int = 0 + + self._last_latin_character: Optional[str] = None + + def eligible(self, character: str) -> bool: + return character.isalpha() and is_latin(character) + + def feed(self, character: str) -> None: + self._character_count += 1 + if ( + self._last_latin_character is not None + and is_accentuated(character) + and is_accentuated(self._last_latin_character) + ): + if character.isupper() and self._last_latin_character.isupper(): + self._successive_count += 1 + # Worse if its the same char duplicated with different accent. + if remove_accent(character) == remove_accent(self._last_latin_character): + self._successive_count += 1 + self._last_latin_character = character + + def reset(self) -> None: # pragma: no cover + self._successive_count = 0 + self._character_count = 0 + self._last_latin_character = None + + @property + def ratio(self) -> float: + if self._character_count == 0: + return 0.0 + + return (self._successive_count * 2) / self._character_count + + +class SuspiciousRange(MessDetectorPlugin): + def __init__(self) -> None: + self._suspicious_successive_range_count: int = 0 + self._character_count: int = 0 + self._last_printable_seen: Optional[str] = None + + def eligible(self, character: str) -> bool: + return character.isprintable() + + def feed(self, character: str) -> None: + self._character_count += 1 + + if ( + character.isspace() + or is_punctuation(character) + or character in COMMON_SAFE_ASCII_CHARACTERS + ): + self._last_printable_seen = None + return + + if self._last_printable_seen is None: + self._last_printable_seen = character + return + + unicode_range_a: Optional[str] = unicode_range(self._last_printable_seen) + unicode_range_b: Optional[str] = unicode_range(character) + + if is_suspiciously_successive_range(unicode_range_a, unicode_range_b): + self._suspicious_successive_range_count += 1 + + self._last_printable_seen = character + + def reset(self) -> None: # pragma: no cover + self._character_count = 0 + self._suspicious_successive_range_count = 0 + self._last_printable_seen = None + + @property + def ratio(self) -> float: + if self._character_count <= 13: + return 0.0 + + ratio_of_suspicious_range_usage: float = ( + self._suspicious_successive_range_count * 2 + ) / self._character_count + + return ratio_of_suspicious_range_usage + + +class SuperWeirdWordPlugin(MessDetectorPlugin): + def __init__(self) -> None: + self._word_count: int = 0 + self._bad_word_count: int = 0 + self._foreign_long_count: int = 0 + + self._is_current_word_bad: bool = False + self._foreign_long_watch: bool = False + + self._character_count: int = 0 + self._bad_character_count: int = 0 + + self._buffer: str = "" + self._buffer_accent_count: int = 0 + self._buffer_glyph_count: int = 0 + + def eligible(self, character: str) -> bool: + return True + + def feed(self, character: str) -> None: + if character.isalpha(): + self._buffer += character + if is_accentuated(character): + self._buffer_accent_count += 1 + if ( + self._foreign_long_watch is False + and (is_latin(character) is False or is_accentuated(character)) + and is_cjk(character) is False + and is_hangul(character) is False + and is_katakana(character) is False + and is_hiragana(character) is False + and is_thai(character) is False + ): + self._foreign_long_watch = True + if ( + is_cjk(character) + or is_hangul(character) + or is_katakana(character) + or is_hiragana(character) + or is_thai(character) + ): + self._buffer_glyph_count += 1 + return + if not self._buffer: + return + if ( + character.isspace() or is_punctuation(character) or is_separator(character) + ) and self._buffer: + self._word_count += 1 + buffer_length: int = len(self._buffer) + + self._character_count += buffer_length + + if buffer_length >= 4: + if self._buffer_accent_count / buffer_length >= 0.5: + self._is_current_word_bad = True + # Word/Buffer ending with an upper case accentuated letter are so rare, + # that we will consider them all as suspicious. Same weight as foreign_long suspicious. + elif ( + is_accentuated(self._buffer[-1]) + and self._buffer[-1].isupper() + and all(_.isupper() for _ in self._buffer) is False + ): + self._foreign_long_count += 1 + self._is_current_word_bad = True + elif self._buffer_glyph_count == 1: + self._is_current_word_bad = True + self._foreign_long_count += 1 + if buffer_length >= 24 and self._foreign_long_watch: + camel_case_dst = [ + i + for c, i in zip(self._buffer, range(0, buffer_length)) + if c.isupper() + ] + probable_camel_cased: bool = False + + if camel_case_dst and (len(camel_case_dst) / buffer_length <= 0.3): + probable_camel_cased = True + + if not probable_camel_cased: + self._foreign_long_count += 1 + self._is_current_word_bad = True + + if self._is_current_word_bad: + self._bad_word_count += 1 + self._bad_character_count += len(self._buffer) + self._is_current_word_bad = False + + self._foreign_long_watch = False + self._buffer = "" + self._buffer_accent_count = 0 + self._buffer_glyph_count = 0 + elif ( + character not in {"<", ">", "-", "=", "~", "|", "_"} + and character.isdigit() is False + and is_symbol(character) + ): + self._is_current_word_bad = True + self._buffer += character + + def reset(self) -> None: # pragma: no cover + self._buffer = "" + self._is_current_word_bad = False + self._foreign_long_watch = False + self._bad_word_count = 0 + self._word_count = 0 + self._character_count = 0 + self._bad_character_count = 0 + self._foreign_long_count = 0 + + @property + def ratio(self) -> float: + if self._word_count <= 10 and self._foreign_long_count == 0: + return 0.0 + + return self._bad_character_count / self._character_count + + +class CjkInvalidStopPlugin(MessDetectorPlugin): + """ + GB(Chinese) based encoding often render the stop incorrectly when the content does not fit and + can be easily detected. Searching for the overuse of '丅' and '丄'. + """ + + def __init__(self) -> None: + self._wrong_stop_count: int = 0 + self._cjk_character_count: int = 0 + + def eligible(self, character: str) -> bool: + return True + + def feed(self, character: str) -> None: + if character in {"丅", "丄"}: + self._wrong_stop_count += 1 + return + if is_cjk(character): + self._cjk_character_count += 1 + + def reset(self) -> None: # pragma: no cover + self._wrong_stop_count = 0 + self._cjk_character_count = 0 + + @property + def ratio(self) -> float: + if self._cjk_character_count < 16: + return 0.0 + return self._wrong_stop_count / self._cjk_character_count + + +class ArchaicUpperLowerPlugin(MessDetectorPlugin): + def __init__(self) -> None: + self._buf: bool = False + + self._character_count_since_last_sep: int = 0 + + self._successive_upper_lower_count: int = 0 + self._successive_upper_lower_count_final: int = 0 + + self._character_count: int = 0 + + self._last_alpha_seen: Optional[str] = None + self._current_ascii_only: bool = True + + def eligible(self, character: str) -> bool: + return True + + def feed(self, character: str) -> None: + is_concerned = character.isalpha() and is_case_variable(character) + chunk_sep = is_concerned is False + + if chunk_sep and self._character_count_since_last_sep > 0: + if ( + self._character_count_since_last_sep <= 64 + and character.isdigit() is False + and self._current_ascii_only is False + ): + self._successive_upper_lower_count_final += ( + self._successive_upper_lower_count + ) + + self._successive_upper_lower_count = 0 + self._character_count_since_last_sep = 0 + self._last_alpha_seen = None + self._buf = False + self._character_count += 1 + self._current_ascii_only = True + + return + + if self._current_ascii_only is True and character.isascii() is False: + self._current_ascii_only = False + + if self._last_alpha_seen is not None: + if (character.isupper() and self._last_alpha_seen.islower()) or ( + character.islower() and self._last_alpha_seen.isupper() + ): + if self._buf is True: + self._successive_upper_lower_count += 2 + self._buf = False + else: + self._buf = True + else: + self._buf = False + + self._character_count += 1 + self._character_count_since_last_sep += 1 + self._last_alpha_seen = character + + def reset(self) -> None: # pragma: no cover + self._character_count = 0 + self._character_count_since_last_sep = 0 + self._successive_upper_lower_count = 0 + self._successive_upper_lower_count_final = 0 + self._last_alpha_seen = None + self._buf = False + self._current_ascii_only = True + + @property + def ratio(self) -> float: + if self._character_count == 0: + return 0.0 + + return self._successive_upper_lower_count_final / self._character_count + + +class ArabicIsolatedFormPlugin(MessDetectorPlugin): + def __init__(self) -> None: + self._character_count: int = 0 + self._isolated_form_count: int = 0 + + def reset(self) -> None: # pragma: no cover + self._character_count = 0 + self._isolated_form_count = 0 + + def eligible(self, character: str) -> bool: + return is_arabic(character) + + def feed(self, character: str) -> None: + self._character_count += 1 + + if is_arabic_isolated_form(character): + self._isolated_form_count += 1 + + @property + def ratio(self) -> float: + if self._character_count < 8: + return 0.0 + + isolated_form_usage: float = self._isolated_form_count / self._character_count + + return isolated_form_usage + + +@lru_cache(maxsize=1024) +def is_suspiciously_successive_range( + unicode_range_a: Optional[str], unicode_range_b: Optional[str] +) -> bool: + """ + Determine if two Unicode range seen next to each other can be considered as suspicious. + """ + if unicode_range_a is None or unicode_range_b is None: + return True + + if unicode_range_a == unicode_range_b: + return False + + if "Latin" in unicode_range_a and "Latin" in unicode_range_b: + return False + + if "Emoticons" in unicode_range_a or "Emoticons" in unicode_range_b: + return False + + # Latin characters can be accompanied with a combining diacritical mark + # eg. Vietnamese. + if ("Latin" in unicode_range_a or "Latin" in unicode_range_b) and ( + "Combining" in unicode_range_a or "Combining" in unicode_range_b + ): + return False + + keywords_range_a, keywords_range_b = unicode_range_a.split( + " " + ), unicode_range_b.split(" ") + + for el in keywords_range_a: + if el in UNICODE_SECONDARY_RANGE_KEYWORD: + continue + if el in keywords_range_b: + return False + + # Japanese Exception + range_a_jp_chars, range_b_jp_chars = ( + unicode_range_a + in ( + "Hiragana", + "Katakana", + ), + unicode_range_b in ("Hiragana", "Katakana"), + ) + if (range_a_jp_chars or range_b_jp_chars) and ( + "CJK" in unicode_range_a or "CJK" in unicode_range_b + ): + return False + if range_a_jp_chars and range_b_jp_chars: + return False + + if "Hangul" in unicode_range_a or "Hangul" in unicode_range_b: + if "CJK" in unicode_range_a or "CJK" in unicode_range_b: + return False + if unicode_range_a == "Basic Latin" or unicode_range_b == "Basic Latin": + return False + + # Chinese/Japanese use dedicated range for punctuation and/or separators. + if ("CJK" in unicode_range_a or "CJK" in unicode_range_b) or ( + unicode_range_a in ["Katakana", "Hiragana"] + and unicode_range_b in ["Katakana", "Hiragana"] + ): + if "Punctuation" in unicode_range_a or "Punctuation" in unicode_range_b: + return False + if "Forms" in unicode_range_a or "Forms" in unicode_range_b: + return False + if unicode_range_a == "Basic Latin" or unicode_range_b == "Basic Latin": + return False + + return True + + +@lru_cache(maxsize=2048) +def mess_ratio( + decoded_sequence: str, maximum_threshold: float = 0.2, debug: bool = False +) -> float: + """ + Compute a mess ratio given a decoded bytes sequence. The maximum threshold does stop the computation earlier. + """ + + detectors: List[MessDetectorPlugin] = [ + md_class() for md_class in MessDetectorPlugin.__subclasses__() + ] + + length: int = len(decoded_sequence) + 1 + + mean_mess_ratio: float = 0.0 + + if length < 512: + intermediary_mean_mess_ratio_calc: int = 32 + elif length <= 1024: + intermediary_mean_mess_ratio_calc = 64 + else: + intermediary_mean_mess_ratio_calc = 128 + + for character, index in zip(decoded_sequence + "\n", range(length)): + for detector in detectors: + if detector.eligible(character): + detector.feed(character) + + if ( + index > 0 and index % intermediary_mean_mess_ratio_calc == 0 + ) or index == length - 1: + mean_mess_ratio = sum(dt.ratio for dt in detectors) + + if mean_mess_ratio >= maximum_threshold: + break + + if debug: + logger = getLogger("charset_normalizer") + + logger.log( + TRACE, + "Mess-detector extended-analysis start. " + f"intermediary_mean_mess_ratio_calc={intermediary_mean_mess_ratio_calc} mean_mess_ratio={mean_mess_ratio} " + f"maximum_threshold={maximum_threshold}", + ) + + if len(decoded_sequence) > 16: + logger.log(TRACE, f"Starting with: {decoded_sequence[:16]}") + logger.log(TRACE, f"Ending with: {decoded_sequence[-16::]}") + + for dt in detectors: # pragma: nocover + logger.log(TRACE, f"{dt.__class__}: {dt.ratio}") + + return round(mean_mess_ratio, 3) diff --git a/psets/9/finance/env/lib/python3.12/site-packages/charset_normalizer/md__mypyc.cpython-312-x86_64-linux-gnu.so b/psets/9/finance/env/lib/python3.12/site-packages/charset_normalizer/md__mypyc.cpython-312-x86_64-linux-gnu.so new file mode 100644 index 0000000000000000000000000000000000000000..27ce76b9d2234b32a2c4e3baa9d52c9080f12c57 GIT binary patch literal 276848 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�J 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 z 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 bool: + if not isinstance(other, CharsetMatch): + if isinstance(other, str): + return iana_name(other) == self.encoding + return False + return self.encoding == other.encoding and self.fingerprint == other.fingerprint + + def __lt__(self, other: object) -> bool: + """ + Implemented to make sorted available upon CharsetMatches items. + """ + if not isinstance(other, CharsetMatch): + raise ValueError + + chaos_difference: float = abs(self.chaos - other.chaos) + coherence_difference: float = abs(self.coherence - other.coherence) + + # Below 1% difference --> Use Coherence + if chaos_difference < 0.01 and coherence_difference > 0.02: + return self.coherence > other.coherence + elif chaos_difference < 0.01 and coherence_difference <= 0.02: + # When having a difficult decision, use the result that decoded as many multi-byte as possible. + # preserve RAM usage! + if len(self._payload) >= TOO_BIG_SEQUENCE: + return self.chaos < other.chaos + return self.multi_byte_usage > other.multi_byte_usage + + return self.chaos < other.chaos + + @property + def multi_byte_usage(self) -> float: + return 1.0 - (len(str(self)) / len(self.raw)) + + def __str__(self) -> str: + # Lazy Str Loading + if self._string is None: + self._string = str(self._payload, self._encoding, "strict") + return self._string + + def __repr__(self) -> str: + return "".format(self.encoding, self.fingerprint) + + def add_submatch(self, other: "CharsetMatch") -> None: + if not isinstance(other, CharsetMatch) or other == self: + raise ValueError( + "Unable to add instance <{}> as a submatch of a CharsetMatch".format( + other.__class__ + ) + ) + + other._string = None # Unload RAM usage; dirty trick. + self._leaves.append(other) + + @property + def encoding(self) -> str: + return self._encoding + + @property + def encoding_aliases(self) -> List[str]: + """ + Encoding name are known by many name, using this could help when searching for IBM855 when it's listed as CP855. + """ + also_known_as: List[str] = [] + for u, p in aliases.items(): + if self.encoding == u: + also_known_as.append(p) + elif self.encoding == p: + also_known_as.append(u) + return also_known_as + + @property + def bom(self) -> bool: + return self._has_sig_or_bom + + @property + def byte_order_mark(self) -> bool: + return self._has_sig_or_bom + + @property + def languages(self) -> List[str]: + """ + Return the complete list of possible languages found in decoded sequence. + Usually not really useful. Returned list may be empty even if 'language' property return something != 'Unknown'. + """ + return [e[0] for e in self._languages] + + @property + def language(self) -> str: + """ + Most probable language found in decoded sequence. If none were detected or inferred, the property will return + "Unknown". + """ + if not self._languages: + # Trying to infer the language based on the given encoding + # Its either English or we should not pronounce ourselves in certain cases. + if "ascii" in self.could_be_from_charset: + return "English" + + # doing it there to avoid circular import + from charset_normalizer.cd import encoding_languages, mb_encoding_languages + + languages = ( + mb_encoding_languages(self.encoding) + if is_multi_byte_encoding(self.encoding) + else encoding_languages(self.encoding) + ) + + if len(languages) == 0 or "Latin Based" in languages: + return "Unknown" + + return languages[0] + + return self._languages[0][0] + + @property + def chaos(self) -> float: + return self._mean_mess_ratio + + @property + def coherence(self) -> float: + if not self._languages: + return 0.0 + return self._languages[0][1] + + @property + def percent_chaos(self) -> float: + return round(self.chaos * 100, ndigits=3) + + @property + def percent_coherence(self) -> float: + return round(self.coherence * 100, ndigits=3) + + @property + def raw(self) -> bytes: + """ + Original untouched bytes. + """ + return self._payload + + @property + def submatch(self) -> List["CharsetMatch"]: + return self._leaves + + @property + def has_submatch(self) -> bool: + return len(self._leaves) > 0 + + @property + def alphabets(self) -> List[str]: + if self._unicode_ranges is not None: + return self._unicode_ranges + # list detected ranges + detected_ranges: List[Optional[str]] = [ + unicode_range(char) for char in str(self) + ] + # filter and sort + self._unicode_ranges = sorted(list({r for r in detected_ranges if r})) + return self._unicode_ranges + + @property + def could_be_from_charset(self) -> List[str]: + """ + The complete list of encoding that output the exact SAME str result and therefore could be the originating + encoding. + This list does include the encoding available in property 'encoding'. + """ + return [self._encoding] + [m.encoding for m in self._leaves] + + def output(self, encoding: str = "utf_8") -> bytes: + """ + Method to get re-encoded bytes payload using given target encoding. Default to UTF-8. + Any errors will be simply ignored by the encoder NOT replaced. + """ + if self._output_encoding is None or self._output_encoding != encoding: + self._output_encoding = encoding + decoded_string = str(self) + if ( + self._preemptive_declaration is not None + and self._preemptive_declaration.lower() + not in ["utf-8", "utf8", "utf_8"] + ): + patched_header = sub( + RE_POSSIBLE_ENCODING_INDICATION, + lambda m: m.string[m.span()[0] : m.span()[1]].replace( + m.groups()[0], iana_name(self._output_encoding) # type: ignore[arg-type] + ), + decoded_string[:8192], + 1, + ) + + decoded_string = patched_header + decoded_string[8192:] + + self._output_payload = decoded_string.encode(encoding, "replace") + + return self._output_payload # type: ignore + + @property + def fingerprint(self) -> str: + """ + Retrieve the unique SHA256 computed using the transformed (re-encoded) payload. Not the original one. + """ + return sha256(self.output()).hexdigest() + + +class CharsetMatches: + """ + Container with every CharsetMatch items ordered by default from most probable to the less one. + Act like a list(iterable) but does not implements all related methods. + """ + + def __init__(self, results: Optional[List[CharsetMatch]] = None): + self._results: List[CharsetMatch] = sorted(results) if results else [] + + def __iter__(self) -> Iterator[CharsetMatch]: + yield from self._results + + def __getitem__(self, item: Union[int, str]) -> CharsetMatch: + """ + Retrieve a single item either by its position or encoding name (alias may be used here). + Raise KeyError upon invalid index or encoding not present in results. + """ + if isinstance(item, int): + return self._results[item] + if isinstance(item, str): + item = iana_name(item, False) + for result in self._results: + if item in result.could_be_from_charset: + return result + raise KeyError + + def __len__(self) -> int: + return len(self._results) + + def __bool__(self) -> bool: + return len(self._results) > 0 + + def append(self, item: CharsetMatch) -> None: + """ + Insert a single match. Will be inserted accordingly to preserve sort. + Can be inserted as a submatch. + """ + if not isinstance(item, CharsetMatch): + raise ValueError( + "Cannot append instance '{}' to CharsetMatches".format( + str(item.__class__) + ) + ) + # We should disable the submatch factoring when the input file is too heavy (conserve RAM usage) + if len(item.raw) < TOO_BIG_SEQUENCE: + for match in self._results: + if match.fingerprint == item.fingerprint and match.chaos == item.chaos: + match.add_submatch(item) + return + self._results.append(item) + self._results = sorted(self._results) + + def best(self) -> Optional["CharsetMatch"]: + """ + Simply return the first match. Strict equivalent to matches[0]. + """ + if not self._results: + return None + return self._results[0] + + def first(self) -> Optional["CharsetMatch"]: + """ + Redundant method, call the method best(). Kept for BC reasons. + """ + return self.best() + + +CoherenceMatch = Tuple[str, float] +CoherenceMatches = List[CoherenceMatch] + + +class CliDetectionResult: + def __init__( + self, + path: str, + encoding: Optional[str], + encoding_aliases: List[str], + alternative_encodings: List[str], + language: str, + alphabets: List[str], + has_sig_or_bom: bool, + chaos: float, + coherence: float, + unicode_path: Optional[str], + is_preferred: bool, + ): + self.path: str = path + self.unicode_path: Optional[str] = unicode_path + self.encoding: Optional[str] = encoding + self.encoding_aliases: List[str] = encoding_aliases + self.alternative_encodings: List[str] = alternative_encodings + self.language: str = language + self.alphabets: List[str] = alphabets + self.has_sig_or_bom: bool = has_sig_or_bom + self.chaos: float = chaos + self.coherence: float = coherence + self.is_preferred: bool = is_preferred + + @property + def __dict__(self) -> Dict[str, Any]: # type: ignore + return { + "path": self.path, + "encoding": self.encoding, + "encoding_aliases": self.encoding_aliases, + "alternative_encodings": self.alternative_encodings, + "language": self.language, + "alphabets": self.alphabets, + "has_sig_or_bom": self.has_sig_or_bom, + "chaos": self.chaos, + "coherence": self.coherence, + "unicode_path": self.unicode_path, + "is_preferred": self.is_preferred, + } + + def to_json(self) -> str: + return dumps(self.__dict__, ensure_ascii=True, indent=4) diff --git a/psets/9/finance/env/lib/python3.12/site-packages/charset_normalizer/py.typed b/psets/9/finance/env/lib/python3.12/site-packages/charset_normalizer/py.typed new file mode 100644 index 0000000..e69de29 diff --git a/psets/9/finance/env/lib/python3.12/site-packages/charset_normalizer/utils.py b/psets/9/finance/env/lib/python3.12/site-packages/charset_normalizer/utils.py new file mode 100644 index 0000000..e5cbbf4 --- /dev/null +++ b/psets/9/finance/env/lib/python3.12/site-packages/charset_normalizer/utils.py @@ -0,0 +1,421 @@ +import importlib +import logging +import unicodedata +from codecs import IncrementalDecoder +from encodings.aliases import aliases +from functools import lru_cache +from re import findall +from typing import Generator, List, Optional, Set, Tuple, Union + +from _multibytecodec import MultibyteIncrementalDecoder + +from .constant import ( + ENCODING_MARKS, + IANA_SUPPORTED_SIMILAR, + RE_POSSIBLE_ENCODING_INDICATION, + UNICODE_RANGES_COMBINED, + UNICODE_SECONDARY_RANGE_KEYWORD, + UTF8_MAXIMAL_ALLOCATION, +) + + +@lru_cache(maxsize=UTF8_MAXIMAL_ALLOCATION) +def is_accentuated(character: str) -> bool: + try: + description: str = unicodedata.name(character) + except ValueError: + return False + return ( + "WITH GRAVE" in description + or "WITH ACUTE" in description + or "WITH CEDILLA" in description + or "WITH DIAERESIS" in description + or "WITH CIRCUMFLEX" in description + or "WITH TILDE" in description + or "WITH MACRON" in description + or "WITH RING ABOVE" in description + ) + + +@lru_cache(maxsize=UTF8_MAXIMAL_ALLOCATION) +def remove_accent(character: str) -> str: + decomposed: str = unicodedata.decomposition(character) + if not decomposed: + return character + + codes: List[str] = decomposed.split(" ") + + return chr(int(codes[0], 16)) + + +@lru_cache(maxsize=UTF8_MAXIMAL_ALLOCATION) +def unicode_range(character: str) -> Optional[str]: + """ + Retrieve the Unicode range official name from a single character. + """ + character_ord: int = ord(character) + + for range_name, ord_range in UNICODE_RANGES_COMBINED.items(): + if character_ord in ord_range: + return range_name + + return None + + +@lru_cache(maxsize=UTF8_MAXIMAL_ALLOCATION) +def is_latin(character: str) -> bool: + try: + description: str = unicodedata.name(character) + except ValueError: + return False + return "LATIN" in description + + +@lru_cache(maxsize=UTF8_MAXIMAL_ALLOCATION) +def is_punctuation(character: str) -> bool: + character_category: str = unicodedata.category(character) + + if "P" in character_category: + return True + + character_range: Optional[str] = unicode_range(character) + + if character_range is None: + return False + + return "Punctuation" in character_range + + +@lru_cache(maxsize=UTF8_MAXIMAL_ALLOCATION) +def is_symbol(character: str) -> bool: + character_category: str = unicodedata.category(character) + + if "S" in character_category or "N" in character_category: + return True + + character_range: Optional[str] = unicode_range(character) + + if character_range is None: + return False + + return "Forms" in character_range and character_category != "Lo" + + +@lru_cache(maxsize=UTF8_MAXIMAL_ALLOCATION) +def is_emoticon(character: str) -> bool: + character_range: Optional[str] = unicode_range(character) + + if character_range is None: + return False + + return "Emoticons" in character_range or "Pictographs" in character_range + + +@lru_cache(maxsize=UTF8_MAXIMAL_ALLOCATION) +def is_separator(character: str) -> bool: + if character.isspace() or character in {"|", "+", "<", ">"}: + return True + + character_category: str = unicodedata.category(character) + + return "Z" in character_category or character_category in {"Po", "Pd", "Pc"} + + +@lru_cache(maxsize=UTF8_MAXIMAL_ALLOCATION) +def is_case_variable(character: str) -> bool: + return character.islower() != character.isupper() + + +@lru_cache(maxsize=UTF8_MAXIMAL_ALLOCATION) +def is_cjk(character: str) -> bool: + try: + character_name = unicodedata.name(character) + except ValueError: + return False + + return "CJK" in character_name + + +@lru_cache(maxsize=UTF8_MAXIMAL_ALLOCATION) +def is_hiragana(character: str) -> bool: + try: + character_name = unicodedata.name(character) + except ValueError: + return False + + return "HIRAGANA" in character_name + + +@lru_cache(maxsize=UTF8_MAXIMAL_ALLOCATION) +def is_katakana(character: str) -> bool: + try: + character_name = unicodedata.name(character) + except ValueError: + return False + + return "KATAKANA" in character_name + + +@lru_cache(maxsize=UTF8_MAXIMAL_ALLOCATION) +def is_hangul(character: str) -> bool: + try: + character_name = unicodedata.name(character) + except ValueError: + return False + + return "HANGUL" in character_name + + +@lru_cache(maxsize=UTF8_MAXIMAL_ALLOCATION) +def is_thai(character: str) -> bool: + try: + character_name = unicodedata.name(character) + except ValueError: + return False + + return "THAI" in character_name + + +@lru_cache(maxsize=UTF8_MAXIMAL_ALLOCATION) +def is_arabic(character: str) -> bool: + try: + character_name = unicodedata.name(character) + except ValueError: + return False + + return "ARABIC" in character_name + + +@lru_cache(maxsize=UTF8_MAXIMAL_ALLOCATION) +def is_arabic_isolated_form(character: str) -> bool: + try: + character_name = unicodedata.name(character) + except ValueError: + return False + + return "ARABIC" in character_name and "ISOLATED FORM" in character_name + + +@lru_cache(maxsize=len(UNICODE_RANGES_COMBINED)) +def is_unicode_range_secondary(range_name: str) -> bool: + return any(keyword in range_name for keyword in UNICODE_SECONDARY_RANGE_KEYWORD) + + +@lru_cache(maxsize=UTF8_MAXIMAL_ALLOCATION) +def is_unprintable(character: str) -> bool: + return ( + character.isspace() is False # includes \n \t \r \v + and character.isprintable() is False + and character != "\x1A" # Why? Its the ASCII substitute character. + and character != "\ufeff" # bug discovered in Python, + # Zero Width No-Break Space located in Arabic Presentation Forms-B, Unicode 1.1 not acknowledged as space. + ) + + +def any_specified_encoding(sequence: bytes, search_zone: int = 8192) -> Optional[str]: + """ + Extract using ASCII-only decoder any specified encoding in the first n-bytes. + """ + if not isinstance(sequence, bytes): + raise TypeError + + seq_len: int = len(sequence) + + results: List[str] = findall( + RE_POSSIBLE_ENCODING_INDICATION, + sequence[: min(seq_len, search_zone)].decode("ascii", errors="ignore"), + ) + + if len(results) == 0: + return None + + for specified_encoding in results: + specified_encoding = specified_encoding.lower().replace("-", "_") + + encoding_alias: str + encoding_iana: str + + for encoding_alias, encoding_iana in aliases.items(): + if encoding_alias == specified_encoding: + return encoding_iana + if encoding_iana == specified_encoding: + return encoding_iana + + return None + + +@lru_cache(maxsize=128) +def is_multi_byte_encoding(name: str) -> bool: + """ + Verify is a specific encoding is a multi byte one based on it IANA name + """ + return name in { + "utf_8", + "utf_8_sig", + "utf_16", + "utf_16_be", + "utf_16_le", + "utf_32", + "utf_32_le", + "utf_32_be", + "utf_7", + } or issubclass( + importlib.import_module("encodings.{}".format(name)).IncrementalDecoder, + MultibyteIncrementalDecoder, + ) + + +def identify_sig_or_bom(sequence: bytes) -> Tuple[Optional[str], bytes]: + """ + Identify and extract SIG/BOM in given sequence. + """ + + for iana_encoding in ENCODING_MARKS: + marks: Union[bytes, List[bytes]] = ENCODING_MARKS[iana_encoding] + + if isinstance(marks, bytes): + marks = [marks] + + for mark in marks: + if sequence.startswith(mark): + return iana_encoding, mark + + return None, b"" + + +def should_strip_sig_or_bom(iana_encoding: str) -> bool: + return iana_encoding not in {"utf_16", "utf_32"} + + +def iana_name(cp_name: str, strict: bool = True) -> str: + cp_name = cp_name.lower().replace("-", "_") + + encoding_alias: str + encoding_iana: str + + for encoding_alias, encoding_iana in aliases.items(): + if cp_name in [encoding_alias, encoding_iana]: + return encoding_iana + + if strict: + raise ValueError("Unable to retrieve IANA for '{}'".format(cp_name)) + + return cp_name + + +def range_scan(decoded_sequence: str) -> List[str]: + ranges: Set[str] = set() + + for character in decoded_sequence: + character_range: Optional[str] = unicode_range(character) + + if character_range is None: + continue + + ranges.add(character_range) + + return list(ranges) + + +def cp_similarity(iana_name_a: str, iana_name_b: str) -> float: + if is_multi_byte_encoding(iana_name_a) or is_multi_byte_encoding(iana_name_b): + return 0.0 + + decoder_a = importlib.import_module( + "encodings.{}".format(iana_name_a) + ).IncrementalDecoder + decoder_b = importlib.import_module( + "encodings.{}".format(iana_name_b) + ).IncrementalDecoder + + id_a: IncrementalDecoder = decoder_a(errors="ignore") + id_b: IncrementalDecoder = decoder_b(errors="ignore") + + character_match_count: int = 0 + + for i in range(255): + to_be_decoded: bytes = bytes([i]) + if id_a.decode(to_be_decoded) == id_b.decode(to_be_decoded): + character_match_count += 1 + + return character_match_count / 254 + + +def is_cp_similar(iana_name_a: str, iana_name_b: str) -> bool: + """ + Determine if two code page are at least 80% similar. IANA_SUPPORTED_SIMILAR dict was generated using + the function cp_similarity. + """ + return ( + iana_name_a in IANA_SUPPORTED_SIMILAR + and iana_name_b in IANA_SUPPORTED_SIMILAR[iana_name_a] + ) + + +def set_logging_handler( + name: str = "charset_normalizer", + level: int = logging.INFO, + format_string: str = "%(asctime)s | %(levelname)s | %(message)s", +) -> None: + logger = logging.getLogger(name) + logger.setLevel(level) + + handler = logging.StreamHandler() + handler.setFormatter(logging.Formatter(format_string)) + logger.addHandler(handler) + + +def cut_sequence_chunks( + sequences: bytes, + encoding_iana: str, + offsets: range, + chunk_size: int, + bom_or_sig_available: bool, + strip_sig_or_bom: bool, + sig_payload: bytes, + is_multi_byte_decoder: bool, + decoded_payload: Optional[str] = None, +) -> Generator[str, None, None]: + if decoded_payload and is_multi_byte_decoder is False: + for i in offsets: + chunk = decoded_payload[i : i + chunk_size] + if not chunk: + break + yield chunk + else: + for i in offsets: + chunk_end = i + chunk_size + if chunk_end > len(sequences) + 8: + continue + + cut_sequence = sequences[i : i + chunk_size] + + if bom_or_sig_available and strip_sig_or_bom is False: + cut_sequence = sig_payload + cut_sequence + + chunk = cut_sequence.decode( + encoding_iana, + errors="ignore" if is_multi_byte_decoder else "strict", + ) + + # multi-byte bad cutting detector and adjustment + # not the cleanest way to perform that fix but clever enough for now. + if is_multi_byte_decoder and i > 0: + chunk_partial_size_chk: int = min(chunk_size, 16) + + if ( + decoded_payload + and chunk[:chunk_partial_size_chk] not in decoded_payload + ): + for j in range(i, i - 4, -1): + cut_sequence = sequences[j:chunk_end] + + if bom_or_sig_available and strip_sig_or_bom is False: + cut_sequence = sig_payload + cut_sequence + + chunk = cut_sequence.decode(encoding_iana, errors="ignore") + + if chunk[:chunk_partial_size_chk] in decoded_payload: + break + + yield chunk diff --git a/psets/9/finance/env/lib/python3.12/site-packages/charset_normalizer/version.py b/psets/9/finance/env/lib/python3.12/site-packages/charset_normalizer/version.py new file mode 100644 index 0000000..699990e --- /dev/null +++ b/psets/9/finance/env/lib/python3.12/site-packages/charset_normalizer/version.py @@ -0,0 +1,6 @@ +""" +Expose version +""" + +__version__ = "3.4.0" +VERSION = __version__.split(".") diff --git a/psets/9/finance/env/lib/python3.12/site-packages/click-8.1.7.dist-info/INSTALLER b/psets/9/finance/env/lib/python3.12/site-packages/click-8.1.7.dist-info/INSTALLER new file mode 100644 index 0000000..a1b589e --- /dev/null +++ b/psets/9/finance/env/lib/python3.12/site-packages/click-8.1.7.dist-info/INSTALLER @@ -0,0 +1 @@ +pip diff --git a/psets/9/finance/env/lib/python3.12/site-packages/click-8.1.7.dist-info/LICENSE.rst b/psets/9/finance/env/lib/python3.12/site-packages/click-8.1.7.dist-info/LICENSE.rst new file mode 100644 index 0000000..d12a849 --- /dev/null +++ b/psets/9/finance/env/lib/python3.12/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/psets/9/finance/env/lib/python3.12/site-packages/click-8.1.7.dist-info/METADATA b/psets/9/finance/env/lib/python3.12/site-packages/click-8.1.7.dist-info/METADATA new file mode 100644 index 0000000..7a6bbb2 --- /dev/null +++ b/psets/9/finance/env/lib/python3.12/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/psets/9/finance/env/lib/python3.12/site-packages/click-8.1.7.dist-info/RECORD b/psets/9/finance/env/lib/python3.12/site-packages/click-8.1.7.dist-info/RECORD new file mode 100644 index 0000000..95ff8c6 --- /dev/null +++ b/psets/9/finance/env/lib/python3.12/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-312.pyc,, +click/__pycache__/_compat.cpython-312.pyc,, +click/__pycache__/_termui_impl.cpython-312.pyc,, +click/__pycache__/_textwrap.cpython-312.pyc,, +click/__pycache__/_winconsole.cpython-312.pyc,, +click/__pycache__/core.cpython-312.pyc,, +click/__pycache__/decorators.cpython-312.pyc,, +click/__pycache__/exceptions.cpython-312.pyc,, +click/__pycache__/formatting.cpython-312.pyc,, +click/__pycache__/globals.cpython-312.pyc,, +click/__pycache__/parser.cpython-312.pyc,, +click/__pycache__/shell_completion.cpython-312.pyc,, +click/__pycache__/termui.cpython-312.pyc,, +click/__pycache__/testing.cpython-312.pyc,, +click/__pycache__/types.cpython-312.pyc,, +click/__pycache__/utils.cpython-312.pyc,, +click/_compat.py,sha256=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/psets/9/finance/env/lib/python3.12/site-packages/click-8.1.7.dist-info/WHEEL b/psets/9/finance/env/lib/python3.12/site-packages/click-8.1.7.dist-info/WHEEL new file mode 100644 index 0000000..2c08da0 --- /dev/null +++ b/psets/9/finance/env/lib/python3.12/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/psets/9/finance/env/lib/python3.12/site-packages/click-8.1.7.dist-info/top_level.txt b/psets/9/finance/env/lib/python3.12/site-packages/click-8.1.7.dist-info/top_level.txt new file mode 100644 index 0000000..dca9a90 --- /dev/null +++ b/psets/9/finance/env/lib/python3.12/site-packages/click-8.1.7.dist-info/top_level.txt @@ -0,0 +1 @@ +click diff --git a/psets/9/finance/env/lib/python3.12/site-packages/click/__init__.py b/psets/9/finance/env/lib/python3.12/site-packages/click/__init__.py new file mode 100644 index 0000000..9a1dab0 --- /dev/null +++ b/psets/9/finance/env/lib/python3.12/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/psets/9/finance/env/lib/python3.12/site-packages/click/__pycache__/__init__.cpython-312.pyc b/psets/9/finance/env/lib/python3.12/site-packages/click/__pycache__/__init__.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..a94c4098a1b0920ca7168d2e5b32e9e6bd993c75 GIT binary patch literal 2705 zcmY+_NmCo!83y1MXhIT`F*Y7BZLp2Spk|(o!AJ(18(*MoSlqMeYPAkh$34|KE&FmS zoBWFWhWwFivdv0Ws!CN>*(G%=o2>GFpBQdfygcXYGjtyvssB1SSTOMSmp}Z}td$}FU6a9wqC!=8qqmgR#`Kh2!^rguCaKGqhr{T0nvoml;WY}3aE3)hyoD(^A z9?pwAdjK8~1MC7^5CwM8F9s!1Vwd1SF~}Z-hr|$j2p$&0>|uCBjIc-GQ8CIMh3|=b z?0fK-7-NsY_r-noeRy1qv&Z2F;sN`C|1g*k6YPiZBk_nm0Y4Ux*^l5S;tBgP{8T(; zKY=I3B>O4+Ogv*x!c$_3{R}pR$)56`2h(DjZNf8RhW*@s5xf*H+0*{3U{=hsXZ+Ve zS(Mo?;5jkJehJTudG;%KK`gLm;YG2?ehpVdg3R_(&YF_u&uX1N$BP zQG8?{z{ld4U4?%TKfpEdyQ}x*!(Tdun(w(^O;4MSsl6cfrFnLhw4%@qqDC7nFVwN8 zWW%gqnMq5UI%)V`-HhTSc9fQ85}ASXRTjQ0FY&^r=|(}|gbma8LUeYO7bn`hY=;%| zBJ{nl(u^>Rx}IGxm|ilg&AOvyqu{8hjghxEa&UHxC7r}5BgLCzp=n0ys*@|9y5`#94b#=r(@!X6Ypuw0>0Ga?nC>;5blYDkU-uC|E6DsD9!`o8tY@J`lJp9Z_=pM6Q&OaZYe4vTW+xX@J z#fy`(&!@G+FJBJdqnWo^uJ8NHJ{SarBM$nczacnm{+Obh;*1gbCSGG=+ zbOIEIsYoBeU1=bSWytgVlG&;(S2j<|pE^0)ZbYtachWekQsLEWs5C`}B1@5@$WshZ z&>LJ85uL*A0oMv|b3+YM3{ebIj8KeH+@lzyxKA-o@c_{&$eVMh)kCUIP&}e|O!0)` zDa9nkGm0rhr_kFL`u$QSRi9He*Yu;h<7+idt!&JvOU-ZtXESJf>IHRvN%4wemf|%< znPQG&o??Mwk)lFjAv&1^pQctzR9L21p;)C@qgbcdpxC6?qS&U`p?E{FOYs)b$+Qy> zce+P~eTsJ!2NYF`8lqFQ?VInv{b%D>l#KuWWCdYj(b)_wH)>!9ELX2DS+SOhwzjQH z9EH%8mJGjH_}#Z+emSgGmRBt8C2}!#+^_gPY0IVeh-KSe=q0vYiLW~O-QFu?PkqKp z^lPmDhWJ;1DwX|~g!)DF&OrNfBy6T|M|~dr5DY)(}BhR z=;XL*?nzGMM81#fR-b$~&)#+2I`-6e>)F%LZD3Dhw+T;OpSfS?7I;oF^p6TMxZCy_N*OYx>>}UokW9VHv>LNd#MWisv=CxFS~&YW%NLLD(bXUm{Ux_( z+=Zu(lk~my*^*jFG-di!X5lQH*eRM(=Nc_N`xFJl7wc~YwIf;{m}-?OMH~M1`}Ef? zI$kh#SD}pxh*_(Rw)>V`Yy?tiX7df5AE`QHSSq^n##VY^I9N zD?tqqs{+JU{4=#xjkZ>@wmd4dbN%%E*C5ZT`{r2!JXw05QL6YzSR{zcP)q%NYxyD= zt=3grVjo2Y`FSG+Fy>=iqnbD)CZ~ZtPYT3^g{Ifa_VGM>9gUV+Ws%15+&ja ztcXTXsiWe`e^zKy&+bRNtl}#4YBlRs{Xc839z;>CVgq`$hV{A#HSf`hjlkWe2c)k? z`q~GiuR(etBod*Z&IZZ$|ws;yPf&mviZx8V3DZFKy`2 zGoICgw=Y5q2!@|&)%RG%R?J=-Q7%Tkj)@z@Ht~!0V`F-ih(*Tx8GESFq#nDt32@xR zIP_+4=!Y^KdNVixNejg9w_r36eJ<`rvc^`F-oh|}WS`=c>odWZ&FZ%M)K!_5Q%FkK zjM`f<7FjCek6tjZrC zOFp~{MF6Se_vNX-Xw*gJSU_SoAmJEzJUxm%GzxJqdS0ZDUwEw)pWz}cG1*8E+tHit z;y#9L8-OqS@&54V#a3DC~lZO$g9<_8H&$;r8|2&nl)+SeAVKiXaX6gJNLdtYVU6IVgt|C(8OI zFH%L{nLbH-za$63?A;_w;X!%8Z=`Oeoq#9pp%y#fO>+@`)D}+fi#aaBX*Yi9o{>UfZ)P;r-p=5_{=Q%cdAp>`;loFt23#&ka+6UuQ&H-&Y#}dG zQ;3G-A@|A2*8YKT>j7U_8faDF)9MdBw4wDvND7Bqx3~5L27Cj4sZ|=d*xDC3(|Tbj zd@eY!sikdWYbX$w)?e`X&->0wp;muiz<<8g>ksx{@P%703@L7Jzwf-{4Wmz9bq?e* zH0#1Y^f0_pF6HEel9;(_p{#!9sYKbjF(GMojQ(2Ey=2U^U|W?GoJpaC{HmqNss{Y- zI?Q%ciZdHci>QF}XCRLk1O9AgdJvcf#m>%4Z+eG|gpAA1RWFq+a3X&mtLg-|iVLUb ziR0=ySp3PW@#^#Yr;VbSy$jfTT%(}c3 z@%8wJHo*fV4SHk6f~#U;WPBugGT~~xOB(rG5--KK=q5>zH zMWM$z#`W-`LL6;F#&&I4$KC})K0%}qxvIc+5q z_&^skG&MsPIgKvL^~erxWfHL<{pS?R!OMQ>0&()|yv&wY4skPky`t3T^$vR;011|3 zKWYsTSV8Y}dW$=0FPS(pe&p+qf4tzT26?l%KeU&Cyjk37@>WvDebcgB{~dmLK6#_A zGxD|t0Wfi{7tcc1OF0Uh27(h@dWdopaww)i2y|yiZo^9s-IhsVJG}h9!%|B@zt4q8 z;XcaUc9l&;#v`{}E90(}30HkgsAscvUDwe8vc(o!lY@|uxQ5rOSiRoygBU zvscAeMh(cLafL?Uef$EKvU8q>Ok0(rlZbu*p7HtI_yBWWXRc6B15|1e8;d1y1?xQq)VPa&=VL4 zOL7mSKtxDl$kQK`B~OnW>`${nVvW85?Zrxz1oT%7FcG=0Z^#qqztAW3O9SB+kEcE4 z2@U$stwR~eAw7Z1>jy7*NcbSJWI*yup%4fj+GO>Fg8h=mACUcn{h=_)d!ZI9OQ7zN zm<-|46YTM5va-iFAbK=G+0)bKI}2F{y#?=ve@62A21AmE)fxuAg;-q|2E(2+J`o*- zgy=sfiJst@UdbO0d4d?#P{^|;IDkUvHJa*?21H3_mHH()>ad$1+P~Z zyo&qjM)r;deM%9WTD zo7bC`xIn$D3&xR2IYY%r@E_$CT$PjI>Bv+B0+nlROjyf?07e=Zmh!q!!UXI7?;(&Y zJ{0dhWKvEO3r2Ji-4#zbvuEqg6--bYxo}46($TDEq|q!8inr675iQhu$j_FB#H8y~ zjI>1BnoM#Aekv_)L|(;s1{fPs43wuyuY&a;CGb5V8gB+Q9>L3SX&y*fy%OR>`{4nY z_Oi(X(~nI(HnVzebHcu1jK6KOk3GBqqPt~k%c~8u?wQTstxA+N#q3QP#^Q;)JTv9k zAH;-42K?e;|3_%yetZ!kJD(N#0Vu+?0w?0|IWr-Aguk*pE5#KPdBYiT7Zbv3TsAu$ zOe87NPOqb&VZ3G!sv)TG5L9qXuDXn%V$cMYCSzxpB4|WSrZv#fB*=U5EH;1gPD&t# zEpLFAUKk30Id@sek0EI|e_3lS^dl*B4&Er2w7G8CmVaPdo-C`%PUYG;F=5{{#wT;9 zvVNBTu0By#AG6n!+*3nx&tv0{-Llul?X^+gyxjv{TT=eK?u$=~kxEDmqvXd4K?n^s9`OXi1<0f|FhqI31@H4ClgUz> zL8iL6y)G)x+gF0&5Hi^qG8rtjz&S^4vZQ?4K4rgEvNB$>a%R(yOIBxauDljF=crYx zmI3D+wV$NSDD+8aEqa#0ynRdc@2+3E&#HURYS~w1e6Ng0%zKqQg{uq*7stp?P{(H^ z|0=cl^yL43)F#aj(SeLBO8$%T(_(ZfL)FqE2B?$1D0RxJm!KFFLXvczw2>WMK%^o( zh0!G1i%RDeLl~m_eGsV&!ze%`t?Dr(g#z$$naby&MB=r+t9`fXTH|%CiMqCV`^F54 z+(VXV7x71%+FQ7HTP*E6^zUxx;djck)opUiv@Mgjl1C;i3hfYsey=yXsZj}WGv(Mp z9x0IJ1C&<}AzD5}uf#$bEtY8w$u$1!>XKBYuQe1)UMK#c=i$A;-O-tiLaI8wqp=9a zmduU@VGIX*6f=bcgcd11Rn8lmXY?s3*P7?}?-{Qf7b%!BnT)HWt5O^uGYyOMNR?QP z<8MkRIjy_OlZyzgnOr0ykgwweBc_xBCuU@uut7`8 zveg3ZrjZBp_3KVS@2Qcr>$*9*Dt@=OU!N+n}X$ClxsQUhDj4Vj70u2Rf|0nby&+f`8WdVTBWn{`@&6S4zdq$3u5F>x^q$YRnu zH1+9vPHIGNH#KrN8ulS~Wr+Q}^ z6RxJ1(DaejJ=qvtGjkweZ5rJVVkFo`zdFBk-Q0;A_47-&=9gKeO8d8Mt_KMG|9{M$ z><4@?YqXe(&6+GB;Q`Z?UW>iR^>3+)bL5r7%UcpO@r+2T+QlqVW*5Od$0#}&Gh_^G z*>T9GcJ1&3`kMYg$R8Z&37j32p*6u-Qvga6?NoylI_)R+A3mHu5Rog<0T38cAE?O4 zGi1!sOe)oBy*3f(yvk+TqWn4jA(AzKi+0Xl`|8usGI!rBPt@-Ip!V=Ps}r_IV}?iB z$Q1)SaWP)>^$kk?Tn>~W$GcHcK4pmTpbhD~BYJ3BbadK=(5y*tH#6X%_5x=H!%UH-o;C&`AE{6wSV*J>^@M|@jA9xgQ3?eJZmf@<0};Z$#eT z9NT&{W_UtHz@m^R*(e|KBE(}2@_?}er*|1vM-(-ZIoku&^}~L4x~U#+s^eOngLk9@ zRFBfL;9_b(2D6;0xfBSWyBFwCF+$(r$(~OGrUVHnMi@*5gxR@uo@zu{k_95od*1nS z7)Aaw{-Gv#D)O!bmz=al58-&kZu%*wv+w-K>Y1sWtG=-%Vcn53>Wu1%h+@k*s8%c) z!9}s<5NtnnOmmraz7imuhPgSZ40D)XLl(5fbZ*pF)fHojS*AB)9_akkH5E~I<h-&t?c1=2ujftG&VyvZbXO(qbxomjF_3BgARrc4sARUGdpoJMochs zATj_)G_A8kCS43j6RCStlLm7E9ac=L4TDVJVZ?|T4K!KgL5j%WgnW@+FOiq2OmXDN zno8w`U?{|JBriThG6Z2Bb8IsJq*4{S{-7*FBb|p-5oG@d{6oJBZauh@RGd45I5?XtR& z4r21ov}wd$B-bW|3e7lzSw`4QWEo*HnpCo^Vl(NTBsot7P7owwvA7vtK5?K~%Zg&z z4MRl#CZA)jqU*#d9swN-m0+U^L1!t#AdgT)c9tkx0TC<;YPF;CD6&^$H7%|}KwZC$ zNuf*~=z>tQAdn$Q)(RwdtSWQOoUu~2PczoE6!9C#j_n2~ zU!iKs;ra2;IGQ6iPqa_Sou}*!6{8z(phj{dIMsw{Qifh-cRkPJ(1TcN=kS)N!Pdx} zg7gc-FmYTf$^EcC@~8_&lR&UG=zOLn6o&m&3r0?pEt3%)&c!KCu^%5C2nYJ5v;~U- z(<#EdT#=&$Cjy$>%L>Uap@MDbZ-{i`&^>*LOP~eklGxG{31?SK z=t|n$qmTa|fz#H{0jJ<#m;gnXq5=wLXd)uzF~nTw6_bhuxd2jayVTusI`afF?*W7s zb0M^3c1gmqE*C;w3FnhB;mQBIAOy+bUI-zQK}h~OM*aZcP(D&4bO1Oq?e|s0NbmUY z&T+&F*#a6y;L|T4veMJoB0EchOoV-BW+6Rz`B7<+e^d8{fx5uhp1!k7{wjh{p)95I zGA|4m#o#3p1P4Mv2r#N(#jr$v5g8d3yspooEFQ$>3qek*C@rvH{mIkF@i;A|EeL>c znmB92YbRbmHGArYaI-OCX&>E}G+V$wT<$T;g00~-|LcL-z>VsgTVlt-lAewkp8gjL z!RrLU7cefYCsKE-kb0RyL__7@f|m~+S1xpD(fu~EJVom$A3WW&-2{S!W#7Hv>7DJp zvF2t+?8MXawv#c#$$zonk*{KKd7$|QLFLnchE~zHk(o}t<=>%F#D)|@PoPg4E(wNO zp74dwJr+1GJp&wlRx!ZVM9O2ZnKiZ-<)$J0M)-?3jn0azY&E4xeN6zGC}{9Qiy4(8XkgY)+AFyyea;c^l((Slhj6($sHiDl3`UArzF<3?=C>{@#*?P)V513z&;= z{)Mox~E*%U2AIYumib$P@RZqQ=0 zWki?g)R^0FIpxK8v}{~2Nf`yMm(ah!{elwB1=;bMg^E}bG54;&H;3rfU@n&aj^W!n z4SPncc@S^8w`9Z`vCw{0EF0h>f;PGl8*B!IE0sBGhV)Pc4rK+cC8$EOSZ2$|vJpqP zT`L-KM6AC60{gYR*=H64nI1aB2etIx4lR^@h7V}r-a}d_`^-swG#jgh$W$ld)JCSR z5u8^n)6#KXVS>gH_;`w&)vn-5)%k4qxImI5$;v%CpF?@aywb$3*rw;m_p#Z}CSs9$YoTJqw z?jrYF{4~#VFIx>bjre{2C0?#ae)$wUTpiK1Y*6@q#^=%!k!otJSazM22Bgaupx@UQ+TD^#f1Y?=C93=Qzmmam%(-#4HF|99xyb`B56!mz6Jwgc?sVhs zgTh}@c%MwirycU|!tav*0RHe_wBz>40Nu2qJtYhlrOSa(m|lr3GV??1IblzIAt;9> zab3n-5Y~-h&!ymCA5`1}7lVBlp@yZ>s4aw>6`s@n;Dw>n>(PJNM>dbFdQVvDM@3}I zNY%G^jv_l#Hma=+V23OBLm_EEsbLqa09CPIJ!__qu!5Wc=Sds3T@L&k zOp&4+2sbq@k_ZJ8 zepwy}V!IBxE7%V+0$iX_%(z}ekW$P?PpH{UN4>`nJbfGy-u=f9ws$FrICygZV@wCG z7+CX$-XIhKW-%bMD=ikP692Q3{9W`!F^6-f+nMe~}+V}52ctSA-LdY-wD;DST zlToT-c-njPh+_1gLlQ_Bps`lzj}&QQ@EKFUu2n_R4x0ufLC*Q{n$M3jGs z7x^Z|7=S|kijmo^D)w+cu92lBHbvJXD!e2UQB`!lo)F0ylh7QfqB(} z&6%K825;WB@k3X|Le-i?)!Mm(v8uLMN!vo%%DF?(81|_R;HFzg9`j0=;?qTzX={v)Ac@=UaTMwn|%2yLV73zqW9V^RBS zXI?)$d-hi2mU!cq8GQQ=N71Q-o^{+fPJvcQu)f|-*wv{snVzxCg z!72lG17O zlsUTj8?Iz|#q=Xnk3nZN=)ZwV_TJP1~ zH&=dd_4U>B5#FhO#U+zW~4#>3xpI0w48kz z(viLhWyoogcD_Wt7fDw5EcWKuNpoI}?vvetu9I#L>byO;rjbXloMc&(?F23u;wq>l zV#~V@ZDu!X3onBa@})rh9+pZB)4P4Q~sPfMJGt?ri^+^CMK*@ z_uRN^)CW$SXAwkG!MgH?2;8qLuxF+lKr~eat{407LZ_iEb_=vmXRcRUG+G3nsL`79 znhqk?es8QMH9{iKyO1zMTKcXgv-}g3k(2Pi7HM|nA5a8ALjI6Ef+0@T*o6NT!nr04 zGM$GGyK`a5>WC9CN$h3TqZ2z{+6il+q+p*gkDDhPV zcf?okm=|^?E0<*Eo-y>|P;Wu)xr*1~P=>lS4SNkKbWE&Z1D5v}4(9+3rz&?iIkym! zG$_&mXm<_3PG$@VS3^utuM6c#+ZjwXv5wNQNLHFI#7Vl!hnqE$jJpmM`OT-Je?pBD zQUIc^vN3gO;M)0Rzc)N|K~i|{Jz%2Ti!^NvIjKJd4%%eM6*zuNr_tRzAO%j!X`b<* z*~QruoBF>+SpEoJzBUxs#UO#>&f;*vQdeXD6Lq@+rO<6mKW03-X0ATAq-D(dW1;ol z^-T+kEh@F&*-cdO>D79knOwU4a6wjQm-tn#mLFZE#CyA{#{M;RwS;w*so{u6er+U{ zz6x`l*DlF1It_A7+TN@ksVX)8h~kJGtCpjrtWbmtGHohwgO3Q0YFtWyWhSNa-%w~f z{Nqx@ee`R~a)MP501rQ|VYLEfKIw@LWKZ8@F6xGcKjTK(1f=yTTw zuMS>qPH~93ae_VGFJq6`u_qTP7V?_D^@M)wTL?=qj72U0K_)q(z&ih zdZe7Zu~9WeZOodYHZGbVhNR$am~p?3v!l88?{!@7xbbj&U3+}RJ~CY0@IL<+#y>N% zAdUmbfOP{EsEw|=i*T(vCK^fJ@-ZNSAwqhc<5hLV4N;*1$*gmruzU=eaYs~OUvI#) z<9g!Y8DMk}@wqr*h3YhLf#s6#Anor6n&~xeE1TFgzALJW9)uhgGpMW}uaiW=SttJl zfqY_=J;}))b@yZxPx30@GZBUYHX2Psq)NZ0z(ycL^R{%Jl91hWDQ|?1-E>LU8h$el3&Z}1F#X$*f z=*f4H_3sJBk0Ag$YAv69>easabq8X#2j{IFNq5zB-BjI}>8_r$Rb-QXZ0*3#!d`mI zwlr>Addt=rw>93fwZ(01H`XO=dt!z?DxWs`gMGL=m&WelOjl|Y?L-uj?odE!jA1;sHmPkHFavNW1$ST&EMP|bFKKmb!2|+{&zYO zYmdYlkHmx{Nmu#U_LxC6`X-1IJ^vOSe*80zhRzUpEdq2F06jE2-7mJvH0cDy_Djf4 zSFo9aM^eghBz8fT@JSI^!fEFzXzvqb%SDV*c0}ou&tA-aYvO+(4@`i#P&uBX+)spx z+pdaRuC;O3+JtLeOjxJRY=yd#0U&&Cg&n4VriSunIzuw(WaUNkivqJ@r|Ow2Hl*zQ zWlv*a`OEj|NA%gFh}?6g5ko{@{Hg}~?n)Y$UJ|kfOT8pY6}YfnizxOTg>j*mXncXw z2;7Jr z=o}~Wxg0i3Hbn9;%u=2k*A+tt4a0fv`OE;B(1wNk-%wVu$P(;0y}rIa(ojM>228~D zD#cD83Cdt4ttiiES~+U-hI~Dens0dZy`L7!YDsf4E~5oOO7M@#8sFfk{ICjl@xD0} zEAf21Q09T9p`$Wcvg}q#W4xqszGO|Zqyol=C$#14MlY~#MRv{Bz=lm936T94() zE(0in23ncOi(+d>x4VLvnN1tBYA<;RX)2*2kit4HL$t5~#3vUdQ8r_V$^VP;dB_9e zu}2xHG_5@>|R8Lipnf}pWv{XWER=#{p_p$)Z60R?-YnivB=D58H zEtZsySw6nIHGRc#NwT8mr4G8}xa8+|H>4x!ix9WT!Xag5AAwkfF}zT*uZ(+7u-Zmr zZf$)czV(U3*5fhZxGK_-k~7a{8}BN!p%pugy+(FFgiQuz&pAG4Ye>7NNPLSiuQuw1 zx(fnBEJO^uLNyva%Woy}8M6Qv%ws+8;**%0F=j%)w1Pi0Ob6J=`Mr>Zn-~y&^ zrT(~)1yHd$UmlLG_}WOqRvR;@Vr^chXw)>S#eMMZe}gDHcg5}i4P{Pw9x8lrKMmsOUvfxF1E`DpHdI?7N561PJ)FPNoTc{r0n0}0dErDLtynU(jnkVK$7=&RB>SU@8k;mVeOU*cDvlCrjn=jB0U& z2UEqNS(=$5wP3!8nc`p#%+#YX%Yqy#Get=)UE?)4K2>jTX8_lvnW~9yNw`;z?IYpaNr@F>hd*@GeC^9)I=U?GPA;n(J2=@m{y42hMncQd)Djg` zytI!Y5JBydy^IB2?0pZ2H>2bWOT2jcF9gItBo`)K&IwfqG3Yy!9G0H4@+ zaP(lx;5L>*3y%-Ws3z9&(#D^0h)Xr%2HfZoM%nUk40WlidL;tDc=)O-rt`~?m@FMG zAh?RKtIyYeM)d8LYf$x4G`9(|u=QEmH=^>17M z$ok7|`x_5x`!w2?mjVE+O>l=7DL3mbl~bH)n|oDi4B?b5`yId#yXY(b1M)!=&d=*q$OdS*|Z2r7N==r zQ`LZyqy<&(bUr@FzIFMyD(y3lsd6P+f=U@a&BZ>%mt$+Hl;0Bx%|Ve^Y&GRts>Q6; zUPtJXuO-83!Z|O#V6|J`j8y!%&_VrzHDm+y&}?@e%zByAOA8z***?}$~lCTtr<1qhBn z^tRT>SCFC(k2wQ$cYH;v#K=2wv?pE_XWCwWX!fD2=PB7a=ci=n-I6N4Au8Wm-Wp%t zdY8k?&o=Ml`SLp)^B>h2_^QIvh`Is&ARg~PKZwVjQY&9lmQa@cXOY`l|X4V_Yh73`GPU=M|2LL*s{1 zdJ211yl$Pf&TX1?sqfo&yuIYDCGYHiYdL$rZL};JkuS9}J+H22%qzY|Rz6ie>6@0O zq^YGTJ>v4_7w-l0OEK7rxF?3khof!RHecNgP#I^9S9i`CVoTP~g=0%L#a)|I7RqR) z51B2QS`s~Wt?OzR4ssi28?HVReH?hW4C6mn9C zdWoCeY20zso5*7XcPx$~-A7zr_wioPeTq@hlR{RlVjI1!`4!dcG4Q3(c(1*>mawoi z<)rtvYdfy)DE?l;wetu0J9-m;l27KWHZ`K9^?SY7dvBIq52jeeZKH{;DDd}uU=_$af zr$9mdEGoYN7G>oe?i8y+rAkjoz70yn%A$G_5YP&8=0T1pV2RJc-*ma`}r6Kzsgve#McUiDIvwe_^c)!jvR=uXk!t#E!K(Z@#?!qWK01N z#uGd>MbDH8W-s_c)5Ny%Z7Ds4mwOn0S#|ZR>if3sZ(HB8zO(5qP$Q&MT}#H7fEPji z5x3OBY6V9!cAl@Bq%Vi?by2FB$GtxTUoqJ>y?JVLl)q-YYMk0hz^s_rOt7p-IcxY5 zZAp}Zs&rrN#zBv8U5MAV#cJB(&W$NOvfKvQq3ay8jXEd!Y0H!)x+=|aSI+rpz0S47mv4_P*&Z)pi(Z#1<($i4(}N$% z8FeWmz92N_n+S{tk_Pjbn?dW?boW&EjDE@s^rG7sWwXIp`Iejf+rnEytbA|W(jGIk Q-_h$_y1QTsIwptyZ>mZfTL1t6 literal 0 HcmV?d00001 diff --git a/psets/9/finance/env/lib/python3.12/site-packages/click/__pycache__/_termui_impl.cpython-312.pyc b/psets/9/finance/env/lib/python3.12/site-packages/click/__pycache__/_termui_impl.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..acfb694eb375ddc1112918b41b0e626b721736c5 GIT binary patch literal 30528 zcmd7532<9yo+tJm?vprqU*IWHqDWoVY02iH(>7&G^2HvThWJ1U6fZx3l87d4$?Mt% zZFPxkdxzk*9Z@yjH9hSq)5&HmC$q8JJ>9L@Y!X7CLl~wj>|M{!I-9D%L#4Xo-b(WO ze-G~gq#ot&nWQRD;(OnHfB*aY@Za0*77ov^#-2T=f1cz1J$dBEoN=t)(sJB1CvaVy zzzdpwzKdsHO_zp!wOv~F)phCESKp;)UqhD>Uv0l>z|>{tDX*^IGGOhpGPl0pHem0v z!)*|Z{doh9E(dd);C6O7ncEDvtINgQ7P#GAZsxYa?dkF`w+(J@mzTNiaOZdBGj|@` z1ziQq?dUHYDC#O=ZfAe-KuK2#&uO@Tv2VBB+3Z(v{fw7=N7;8aPhW z3!bhD!P`|is1x$xD(I@za7Q_z@KsJILfH??>9gNJSus36!+6ruRVB0t#Yov9`E%ca z8cHdYAof^pxa1DhvDi{U(`yjQUe$Nie@{8(fto*{ER#_2s;+C(|4U_6qO1nNhaQ}| zw+G)-$M^T!BvhgN&1}T0G2%5p(@3>+Z4tH!wdikMpiZdAUumGJ*CcGhC~XxQ5MH{$ zm^Rax_UeR2l-m+05L?(P-qy7(!1tY1=>e4^+#4QfV&!Or&9CZymWl4#DQsaasX_To zD1XcA z_Xh?7@P&gz@b?ahzVP{gFB}jDMuM5-&Au~3z6*iCFhyCAWk?MB!oh)nZ>ZPT-XH9_ z;1h-}4L12gLkJ5F_KJZQM^I+}sBa_`5PZEOgFRHdzdslr^#wzg;eLM)!h?e-Fxx2q zpx_%CL?)>QB=CoPgMok$5SlID&>(g;@+srFKsX$@9EQ_$IxGeU&mBJrxBZNWGSB*Z zE}R)14tztK7opy6A<*j|=?`~PmhMnk7#g9RhW2NVK7E{ubD_BIvw={!J22QYB%nBo z4u<^U@F-l?q2a(F@`(Ze0K68sg2UbZ!B7xB6OB@Le_#-9tyEkd8;--5djiAMV?^iz zJ?Do~{8K5-U^vCwQ@kZ&w3q(ip&bwOM~v)y-qMpZvZ9B-fL0Zh;_2oQaen*IJz#E;6ln; zm73Ui_G*M8r1Bt@0q$bBy+V^vf^UAH0HK8lEzN-?MM`K{PH3?bTAmYHg8U}rC+tz0 zaTD|}%eZ}TmuK7rwJS32YPc)WiW+=V!J@tAwpAq<(|`vtF@zFfiC&jdB{0 zuLfn`e;f$D*N*ay%_-~S;?OxU5DK;V#m(j4D}C*Dd)(rfO5MBf&_g6!=aS^Qcyr^3}PTWA`bRA zbLQ9pH&GL-{{h%0zqR|`jOs~kRNhtH6?v@TO>(J%UZw_L;lqt`Xy0bpmHmcMxAgQi$*$}-+$_6k--fr#zA=qlzS1T> zyi4aW#sM;uM$^enbu*0gX zc53(e;9&Th{~J%FLf*wb&@)mj=nfyzB|$MD9BFJ2X&^-!Kaqw_q|p+~=|z1Psnep5 zUeraA*1AYrL!>^6)HRWM1OlUHh)Ae#KpW4-bhV zEuNH_NR-2(h<(n7Q@S312;kv(2JVP1N}?D2gXaP%9rZ&jq7W^C4z2&{GMr2aA;w?f7b27h#5+;4yC~tYPwvN74D1!x8*3R)W5jgW!tgh&xuWU`f z$@k3`&Fx6!H%E`GIPzoe*T#~?<&%b_)w5tNO*-H~k*UZ5CPtNcD*>j1)1JPs4HJj#4e|Cs9qo52QYtrMz$CRw5UYou!+3

3R#CintnAlPt)OBR;0 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 literal 0 HcmV?d00001 diff --git a/psets/9/finance/env/lib/python3.12/site-packages/click/__pycache__/_textwrap.cpython-312.pyc b/psets/9/finance/env/lib/python3.12/site-packages/click/__pycache__/_textwrap.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..f4e95d606f63889823e0bacf1a8ebc98736eba1f GIT binary patch literal 2446 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 literal 0 HcmV?d00001 diff --git a/psets/9/finance/env/lib/python3.12/site-packages/click/__pycache__/core.cpython-312.pyc b/psets/9/finance/env/lib/python3.12/site-packages/click/__pycache__/core.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..0e83abc0d1a39000f054882547f93f2dc2704dd5 GIT binary patch literal 135506 zcmdSC33Oc7c_#R30}7}D3QJ)p$O1r+C=e*_6bVw4KyVQ$5|l)WjvzZg5wAcN2o#`K z1uifcQ;HIUHXV`P2#%EqN_$#hq>SiHPFtGk8B4aO+sX8qR0&j2s^Lk~$IeM-`bI0Md5)Wag20b>DsW-Sxl!{qMis|GlK7Si<%1rk*?Vum2aD^b>l} zE{_^mtaVA!O-Yty+lbUBer94;EE9QF745iXWJ zBUPi7eU%*cj#Q7<^wn^<1mW7gS`L>YT-R5}VIRWvef1nJL%5-@fy3npuj*UH;fj&Q z(bavcIb4bGn!Yt0_KyTcoBEnKT!nCRUo(fRM_NYL_O0b`4Z^K`tsJgJcwOH*4%dyW zA8qSv<8VE~!M-4e8xU^qYv=H)kqx6AeH|QbM7XoBlf$bK4)ujNyawToeH%F(KzLK% zCJr|tyt!|)O^Or@%i8c6ze+KW$=1GY=(FaL?V~&TcGx64rH&b?w2<6__;KyY_?6cp zUNN4v(2%_j!M9r9w2PR&u4Qvx_ohuvvs+#-x5>fC9=RR4PHK4>zlfbOp0p6sZxH2C znL`C~$IH&X$BHDmSMHQU@ zhvZ$z>$;JL7E<%-TJbHFWYH?|EqZS^>V4QQ9g^fdFH7>H5o!4ATK>lGn+_4~dy-S` zManjPtdDZsV~BfPk2}V3-H6)|Ii`Qz%dz_q8;bPmvBx>K2eJDj$Mx8!IQ9Ty51L}1 zmJgvl77(}s3|XY+UUte)pzY6aIfqfsBYN#maNH5ZJsCNn*XSh29!2aiQ|z;sY{94g zp1P+uXv;Xlrw8#*DTVfm@B z5+02tIOEcuk?7#L0~ZG))2=DM%G}b@HImPkp86O+(SDQ+&$0y=vwddQmOnLv%Ncc>DEE199{pZ6Y z6A?;uoIgjYanUjH@sVhPGR4b6WHuC4MiDF+SH?y;(iKl!8lg}9{W4lLnCQo=GiYLe z49%o0`y&^}!!fx(tel~0IU|E-$M9P-8a@}nH$&lxkwky|EPAN_ESiK@ZhjR{P^&7Q z3J*qyE*%^}?LQ+%sM8K7BBL4G!4T5APLEB*+9d%SZFg6qj2hJ#C6XSRlP6XnKu#yN|h$hZb(&7LvqoV^1QUQDz z2rH4;`b6MtRF)&LP%$U$8mDOxz%X?M4#&=q4Tfnf11h)%hQ<^wo=Xdvzc5PZ3Y;RS z4V;c(p5RLch=?2t91CAUWFP_ny(GTv4Z1V7M8-K7jwdqSV*t3QI{XCG+`LT52-=PL zAsU-0=GMijbr}!ly!IwjAleahDIMrpC4^hXHA-1#oCNa9cErR9lBh!hzj$`zXe_aD zKQKycU2T2f^#vps)Z);8@-dwj1vcJ;BDt`9xy z($x(M)$3E$>*pMEC+DlTOdq=Mt4{fv=N@@`@0)wm)%7!nu8+=_wS4T6%7Z_T*P^7C zx{JGa+TJhm)4kbC_l-rkXS}DwalLxVHYCls2S;Vb5SXf?a>lJh&Y=4v%Ah`>kg5!S zw6-n&6K*$Yis3i^QpytQ`iE&^HzuSu72>u_m>7yfwq16{?6Uo`Gf}AJG3ERg=w9UO z)?$p`Z`oz%lnr+m-wP7@w4AbQlX2K zqz;P$kmF=wfMzQK_FyPjm~nB*SSqmUV(Mc?3PANfGZ9NfN5!(M?8Yc(oV2cI-2Du{ z{r$iMdl9WXMz_c5){R@nc{UnL7S5bKeQP0!6M%=DQ_dLF@JHCGE z)%~-z-|C$^GGFybvTWzPXIIj>OQAYvT)akQigX$*r+tK|TJX2{m$(U90ox1PH|?~d zUb3}F3B-$QEtUzU04ykoD}`9M?fp8HF=czP66?De4XU{yr41?dJYGU+m+ik}zhFz~ zlm|+xd)ShU?=MIf9nVP@Gzws^N;d^m0$E@RkeOisZ#)1(SP5h5VT}guNvk&IZA7DC z;~|WX;zOOq`gnpuRk#HmMnuLIi4$yKeH0_)4^NyKjl>fD6GYGu?gdK-yE5^sJgKf1~F0n%Om2 z#1MHX?JoJ{Jx|pqlEdNyyvr8i#XrVrDSye<-C}#$StLzU;A&BK!12}KZpZ)ZMd1BH ze|Ll9{RS6>0}i~;ltp#grGHG3BTA-Rjtq`~wxNy@Q8`dUBgM1gECOF7rj1Ru%MJrp zR;DtIkrvzAA?LI-WRsmQdoSA)I(Ap+rYT~?AXMJOk@;DvUn6Ni^xod5oHDne=x$^6G7h*78ckbFIQd@A{Q}N zI{-w$(SrDnb57v^O=7~~R5Iuq1-l2M28g^Az_viGhFT`p4*r;D{HSsgy{K%&ZBU;; zc%aEsiN8f+TYSTIQ!0|K+K0_45KosueqXj(6YyS;-b3~inCS_9;$f1N+9U&c$vSa< z+4h`ttyP;&L3?k;fq4Ra<%-7S$i+-CQ>?s$%eaO{#=;38(s+M_x1kP&kQ2U;FDk!< zkUB%Ih#BIJ(+25WNck8Hr{d0*KMEf$+{(f?afDTJeu?cW?PcJ)}*`jXP*{IW%Zv(wxTunDr#n2 zU+ef%Pu78_U&M*v`Q7ps>0kM~9Piq?9N3FFP${f|Tkt01IynKFG~+xyHa4ORP)q^U zBqC$>Q=63M=r)KOw{Ae2|MknaNr}=Y^u<=(s2LRnu65TxPm9sIZ@=)yh1V~`>BJ057Nn&Q&diFiF_JL4nhkm?Be)2!#UYftY|rL70K*B6oEK zc7`@_23R%%Tm_3(5$Px^W3)w$1O^7M3yl&tXJ8;e^&JEH;4B`LeK(VxB9Et@IezS^ zlgNR$wAzl+qZ|TEWQzOyK{roe`_&ItNB;{G;Sr)M@l@E~FOLl(;G|B^IKvZ(v5cqZ z__1T%z599NUDEzj>P|T=6 zIfruj_WKCLX-2&)eQfu*+}V1ma@F;65QKclEh1KY!(5+WELBl?u$6KrM)%YjF-6Cu0IVi`A^p5pnjp zzy`G7JIKt4j<{t95yM3*{*#Z$F1bK1L{1f4R?bb9h)F2Bt=~q9`EAiMZwrR2b28%x z{-Su9FGPNxW!@GH)9yF#icnq_*P=aDE55CkokPuX4TK5hay3$}wJHzs z%Z|v9U9JVgxl(>ouEVciu3x4+OURB?QTw?M8kYHvQ^>29d0WljQY+kYBg(Id)XGQY z)fi=J4Xv$tmzV)VPI-+<7*QW-__bRfc-g5ha;uOFxPx*NYSJh-qXsl#^RCDmQRm1S z)S?9`11x|F8ulyCtT!%87cWdVc* zM$+40iDkrFl(YePv_3Eo>IV{ctwU>jm-Yg7hezekNHK}QxXl)L&AOkcpCJs|WE$zV zWy^q|jmy})LK)92t(|qrh_x7*GbET?c07$4jXFcTr$ben)_xVLf7SMH#q4f_FtAvz zmbas?cc8D^A<%mSzZ>MI_Gbo9=hf62DYsp6 z2A@$n0r%l7wuUEp$H`Ja!6J;0M+T$e5$r~>xr!k$c6yk$qr8JXJ2nFG2e^WX2zIa| zk@MkLf~iO%VTneJ4=T~|1ehR^!3pMwKspiu`HBrJ`2Aqh;+x1wC=fWD03{tG#>vRY zB^0Kz?m08!ergQdiP#7>*p&CB0EBOyv`JDjynO~fNZ6C<>d z2bXjZ8-Q_;|M`sr%M`*K;`QPWiMSRdfluY8=2e-H6nl-9Rp`X zjtIB{=f<3`4sK)0GMT7NMVSXx08NZxTMiJ^AeDIMar8cRDgmYH*aaG(C?NY+$|$GDG26NTh5*RZQE(SAan$*TvH>Fs!&uH2w43S&tO3Np z0ErAmAxNZJiZIO$e8+XAl*FhU446Q3nX2l8VL&b>Ewvxrh5rM+V=+J+3W{mq|Dc>` zVwg)dCIw|EN8>a>Ahl#k$%8VJ$1wj$02Ce?BJ_m$!b8a7lV7KK>NEquL*#oQd`Zme zoSxQ1^rPW%j1g))NGOiRsBI*A4&cF0U7dWuzoQU| zj`UxM%3v_?pmI=yLoES!Sp>6$H3-m|D|KEp1_2nrlt&|PPV)%I2>UW_S}7Y87LBRQ z60II+I4UY&f?#ds?@2|1c;<}IfB~UnG7{Cenrat}hA%>xi^_l@Zt4X@M@J_{)$(ZV zQ4;|a!CnN17Ce-dN=GNN!bzZw;dyWZEZ0~92x%;an*gbJfRr#Ekjpp;q=PEVY9qi4 z(#}mJVS_dddIvLR=m8lKD34*GRD^B-Mj{pvvdRl!MaR2n6$N*h5zqs&(uV`H3JiEC z_FzbWQfLM5P}|L&jxryR6}lD(17Biwi&J-NdF8h5ft{^_Ci)4@f*>=>BM;Oh>LiNc zjv9@gIs2emk(@U^27DY34@DA}F!#sDY5Aq)4~S2pEOKTN*6Ju=3qS;bCqkr4^dvfn zRDTHlL}HA6D1(@(j~>uJlwAb<0)86gu;Ca{GH3<{J$gQhnh|7TVIh5}2jrBqK<-y( zGPBvJ-?8L_nLP$6#DlUq1DZ-lqSP>z0HR3}B{c~mN6-Tg$VVMYW8pBhT`UmGH809=);|$D z7Xz`W>Dr-nP#I7r1`{ABNlAzEthC6Ecqv;dZs!Ot}KXiW(9fh{c^Ha-g};9L9aT{Sk{^;Oy9i2UMTBP3u)E z$;8~pj9_&Ov1mUaA1x1jG%)b|`p!Ogj2c^ivj`_=K_Od^TFkiJMVCQ>y^2xtjn zdH3@$)zMKHzNGz7ERH&1HNnQ6*c@kujx<$ph@=XdUJyLSG_PY!(l6 z_ntV6WJnG5K7}aDWe3PKC`9E5WlzAiMg^dInT#NXQcxl&k}|jGB`Cpxf+C8O+fQ3t zU`7IR43eNv#sPhZ5nDiHY`M~E6{7jV6Bb>gRVJsmFR%<*kT(|fVMxV7Ha?NNd_wko zLDNs|3Y@?b7o!!+t5nWrD5UKa^g=`$G=S=e6`_N6N@@m7E>XSJjA)xckAgVWv(WMN zz(9}K&W6ktgH%eTpO`8|QCj_|3y`0l5pU>+unW@hHovkKgl*P8JBca{4CEDwI$~o8 zaH2_N&~N5(TCTe20?Yz%4m5IJCHJ7SDYy|2DWH2my;kmIy>+6qd7=OYS19_CklrO` z(cp6ZvO-SVOhQa^Ry+#_20GB&*2@gN!`i3UePCe8J^|364~@oiu^Qm5%hVyCqCtMN z+71jXv#t*e=(TyMa^uvtNAu~o~IFBz3g`I7c!%JRE9Q?pDT zXR58iAydAjdoq5j?tp3|A^42f46H(FrW`HTF4Dzw;BOJi;E?G~*{4|dO1y?fkz~?Q zgUYO-hZcnzO+S6f*BN@!wb%Gb*YcaPD^&?ya~)c47802^RW+Shk&#l9ARuRx>h6`& zDf^3FyfJkC;G(( z>-b?}H0NE=#aCN$xnQaQ<#@CNGWC$r3x#?+R%t1W-^+zl&=2g_`)SIpr?!y9UUpAG zow%Qr@A#T3zT%y-SxIm%7f%%9!}Y;eQEq&_Dp$@Qiqf&FQ>GSuU_^}d681* z#7~u6sX$+rpwHGB`DvlcB{7F=KV!RGGF5`FjPWVeTiB+hHGVIbPL(3HUyGS4!V_s1 z@-^kUvL7WrgAz$MKks_+AXL0`$TVKQ*kzqwRSmcJVwg0}@-7WVza{;l%|JB*_@XR9%ZL&*l{2oTByU~luz%SEla<=?3?l-wGNF_WqRsu7OBgo%8D(1_pd-tw!24THGb*8}??Lpbx^61%h_Z*!nZJPKETY zf&t|cegx(v{XE9J;n6r0WMCkaDaFo(cx39%G2;N)lqsP-i^}GW#1&F%%aBnPbW)X! ztDlNeE>olfk(mnODx5&-^zdss71^Oq;dIWznq{TRapyJmt zDA1{ElWH2Lo!30~YgXgOd%vz3Kc!Gb-_Xg?O)dB-$`(ruF{=TPldiTtZWJ71VqV{I{jdmy*7Dx@0ulrtb)1B&fs^6=a z5AMfvF|-d$YLnhI>9V?HS!=qiI$73?`$AcBs;oI#7P?;_Sg7wv)psn^Z%Wl~x>Gk_ zzkB-0`v;z)l4`TH(zcxxT65o1m-IBv4kg#^OgFYHG;T>XZkg^yv77dCb?A<>$z|K@)XVTk<;1j`|>s(lOAhqs5(%XV}p#%Kk+WVfSq$ike?O15-NwxMQz0Fy_)Y-!?TSU2OUsclA zlwRAuuy#)h|I3>0w|34RNtQLCh8rK(DzGN$SwD9$*|9g>5?pB6n`+sc^afB;NmJGZ zP5-;@rfjLywu`Hak?^igdRp&`F7wwf_&Zbn&ZK`=8tR3$RkJBs zz4=c0oo(OU`<=ZDTMwnS9-7~JIJxCW(*GpP3Cdg056#;ans%j{cFi~KPI}QB(ESgl zo3<`A?M^lAey8WX%K0WVeD(dU2dI2>c-i!$GpCY`8`J*!n@4XPoj!o#+6Y*R?|W*J zo;9-vlWTXR8=4jxLaBz(^igW+Zu++F{$t(Tt?B9-B=@AnugY6 zJ^|X2M9V%CCx3##a+W~DIuSyjh|AFMwMPEdTEB?ZNe3+_(iXPT3`MMk6_9LuwE&9O z_AqS6r9)wC#IRQ~tIX48cTiJqHgPM%;5b11dWMCCIV?*gQaXoV4M`%`u|Z}cvYL5_ zMMnX!AxUFWl}-@96I<+_qsA6o@TefdRd*+ZEwDSF{dnhTC=Q>4ilwkV6FQO_Hem}t z6?wFQ!4)LoFIn#C#J`r3MWBz;yAY&vOi7cts4Zw@XlzHo&t9U{87wdshJ3_Fs5w~3 z?=xO=_6j4>JTytEZ`+h_;U`XzBn%CdKSFTQuVF%SE_aYB{v=)l8`ev;t8Px+m=crc zj(@&pN4l=@wbi#)rvqyj0^3u8?dkO!7S{Kq*7u~>wJ)sePOa-sH?Lc0-j!ImI zS#ee>EGk|K$ONJc$OjQ1K)z@jMkxQ1ZIhr72km72ATGmd#sFy>zK2DOy;t!d5zJp^ z@T1W3ue^qvsoj~Peh5pkQ^7h=uC-o|`roMO!YC%~_P*lzlIQvhDR=ExJonuG>nDNI z)4s}S4>u;`hNVY88$cCNh?y4|d*XDC;hx^gE2zebt*psyB_Uz zuF)VilS;l3cS*YK5d9;_4+nP=_C&OfE2Ovya}|OT@~Be>R=QC`P$ zmQfM&m(+ViZvt?YFmjY*?v z20)AkQgIZ-qK<~ZTw~!HWD`QP2?iJ`sRY<6BG49(Ky97b!~>+Lt|k(q){BXOpx~j> zpc8jVW29*uR>81BUGX2q2qKeNcIqhV{AQJNsn<(o_iD0!(sTz^%c?xkpJxbQCHVm% z5)mv|h!XgXo{PrK7Q9nTK`8DM*Pgkkg4@SDdtG`32&c7TC<+B6NJ3>p4~Lq_S`Fwa zQ3^GR#5Ry4gF}wi52}hfsvZV4L6yZp1Ar`bOnM_+12)mrzEbsgObg9{i(wL`p|+46 zcXb&H0@a1bm{yJW;MjPiEx2@Lf%;Me#^x5o))u6?<6|RBhA2eB)F}!C1;n>pfxlrv zOBb{4;Be_9rV7Q>E?&xy*ZSTVS+HnSdnaWAlJMn4Jvyge2U7u+^cjYaR9{r#M;zdE zIHuQ$y4!pSiE=bC!K4I>nvAh0wSWsyc4L5FLCOdh3^444vKP{mn+f9o=V)+2u!=Df zQV(q!7_-e>9}4$Iz#*1JPJnhze}|zRvy!FpI^-JJ@G1yDAB^E)aKu=h2*!+EIiG89 z=wd*dEYX%ie*BOSc?9X%)bQgjsjP;O_LE$`rjN?2W-8LvwO@7r zgF~vQ{At_H$7kV%)F2)3w+Z9yIg<6KNRBSb^kAyd;gDd+WNm#+uZ>h^KPH? zhpuji4xeabDPErc8t zRXRwT1giW_Z-lV?0na^gR%8bM7-M5lreql*3x}Yg83=qvl|OPn@Z7*0rIs6A8-*^8 z&@AQ82n7Qb3OiC-d04QFte#Li<${_eM1wG}!yGkdX6h44##{_^2vtdCg4za%cp0TD;Z#pKPW*OjY?ob+nwiCXhZ!cN2p z2AR1{D)YZGd37@Bu3NgrAi|Xh@WrQaW2``UBJTnzP29M=3$gTd-u0Glh|fFPN0D6* z$STcfP`51I-IZPHIXBp6enFzcb@f8yS0Zs0zcgV@H09Nh6b680RCoo?|A=+mQ zpv!JB6-b$xi4Hs4lAJproq~KORu^Cd|mA3mPH} z;Uf*QNz%wG2We0d--8tL)eJO^N~WrSyWytj0;#nT0#h4i#*y%jHBNe$I>0X$?8mhY!wKVK;l(;6or)l;uY^}!yzG4?s;81C^lYZ4#Lg%NgxwDgW zmzpipkYR+s~pEHB{>bBtm+Z%%I%LW3)9X-=fHj=)Vcd`aP_8CX}V^tW=7TZ~)NF5?n(zDImHGs}zDPCc@Q?5aT$E5>E>q zkAe6a2lE$J>=UGe$0$OWUg+SZ+vJ1-gs5CSMYRk17Z6gv?E4$1=xJqwbujX^I! zMIJ&$N>fS8!MnoliSVuAjYH2yLmJe6z_2#qbB1+*>1MEDOi-l4@sNOAbBBtyf%ql0 zFwLlkdX6p)yxf}nO@plOE`cmcq2n9_vT~yLnIKE7l>)NbQogpi@_FBeq69nFApF{1srT))wv7x@$%znAd+5?D>ToQIl7UYa|r=UZ;bslw*U@C zrFa1Gn8?LolrFey!DU`>uTHsF-*pFmx`OPzbSPA#-{f zxxDMeZ&_2qR&+3w73^k5RaO+VmE0&%tQD&9V3i}wlxiV$vUc_Orb^SpZDcdMjkFKz zY9Cr@kXSi}b;S)+tnN-r%LN?WwNCJfhjld!Q)=DY9TXz$@P$VT4mPNj=xP^6S`C^( z=s70;il{SEp$A!wEwSqDjrPje#xfqnCY^C0h*w5)0|UG%FwuHuk(p}ez#9oNKtV2S zPMOOe8swcxjwK9=J`EYTic48WMe8cK; z65eOLYNH_f2cvmEqJ;E{70QZfYsp%1P!fQ0Ay})KGKv!}uEwJgXc1?eR!l= z)8$n+SKnAYy-yWUBt6aPmi2G!etq{s%kEUm?qu^Gh~T{a}x_252Q98cu$_+ z_~eKFqu6Y$-e-dVxT^N%6E~hnHg1~tZ%$TjxzluK-<@sA@|~!Lul$uuS1*0}^GSF8 zQj|-;&eNa#JrT-f07N+dda(|GnIDPgWz*ZP;S1WAOs+ZzA5DU;#*Pw3Xk>z^V#^RD zi8SKsasx-7q{B?;M3WB{!7fbhCx9{JYkCwRiueYkz9QX+B+Z#Ft$5|!)pNu-{qWmP6V&ksJ3&3<2&DhUh2|E!Q7iIZNmUE9oyQ_$!u#_Z@RRZf5@1s)jt8Y3YgoWVK7#P~dFBKlBe z%>E@s{0O&P&a8)fP2@INsS$*x$QP(HyYL-4b6xwi^L}YXvUK%5hSauOZL?3_^=(Sm zG~B#+18(Hd%E2VZwzch?@ zF-Jj?-ZM~LIZ76i>bh)d#6W;NSb{4d04@rGUjUrijkL+p5l<`v3tP=}03AGF0tygU zylK`ALzx?EAT2=be?S9R#Ykg`bI%iw$?bX2>~Sau^s9ZZ6XQA2m#OzvVW(Rvtym~& zOqDdwoSQFcC-hP>-SyF`_1`*{^aiK*Uwh)Zf_Xh%#Qm-M&Ljft7iD0y9A%$zBhQn8 z)aM4N^UW6z1_Aj^>5`=MBA}ed?Y0U$yD8$YaLa8%>B!jFxruR2Yv16J_m+H?89*RuwO=2W(9Mj>V)b@2~qhPZg6m{mZ>f3I>=^R%!|%j z##aKEuhOL3i(CP(e#u+5;Au#ay4rf^dM)_Zru=Ic{B0?J+nj&iADTY!V_)T~?%AqW zeIM1V`r3u-rS~gqr;lP$VQ|Y7g7P65>@Pfk_ujE**d4m{+EULzXj)T%FHlnw-S8}|JYs$3rNlE+WFG;N%wj&G0jT=l8T8*s<>uv zw%WAe{-`kZhuE`+6w>t0-yLOKVLB1O*dOuZ|3LL2C!SZNpO#jB`OLJcCE_IMR?Z0N zXoB=t%(XF=D6UT@F)zjNu$?(P{gE*%Z}GHcns*@9DMul{v@yMuivCFo_lnB@sXY$Z6tDvaA6NUjl1YWT(p=R3#4` z-n9KMabZ;(;JrcO>FNFrbp>f&@sa}R%+%GX1z&5**E%aN z$4L0+>X+YsK)>iarr)en+|*dgYe}E{E%k}6UaTeix0YS9HsxD8dve~_o^-d1X@+F_ zMXUtsmPNvLH{og1gnV>hfH8{AigcZlAgQ9SaRFfLljnt)DiDTf`GQ8vYv?IX3lY(% zq|L~}A{8_`h&I#VMXYz?d)|ndF%`+>poIh_lSIT&CAn=k_K1Ke()45EN1Iv%VmVW* z94jVdI8ayDILVWB8s)p>)%U4eg|Z$Iv-Q^!*Y|&Ua%TP9XWsto?a#iq_O9;GaJs%2%Is&IYr+fu9$`qWtKpOZthz9Wz@f8-GxaE;z&P=J1 zJ*&0EcY(_k2!*N1Qmtj;`7hBNjTS4_Xt9T_gYthbDM$H#5S3rZJPJ{= zRJ$X%VH{|OuKZuP<&;DuA-8rf(&wU8!~3tc04ncK;Y0x(ut8mucU|!qd?IMxsSC+V zHp4};l_oJxBCyO&E0K9vw4CH!Q%rx!R5~htPH;_wKo0 zlbiS4w3lomZO|D`0u>1+F4L_l|BJ{%;^Kl71ydF-Ga%?D5*5C8NWO)$av=I4oh@+B z6ho{?N;ioMW0VZo%A|b=qFBfkO)7Pp@j2zmQZe0E0tjZdIu|rF*MSy6)JJu>VmMVm zyp8~gl!mel`D4+u63Q+>jldYBFsNw+Qq8zvRrkzTS+`hMNs#pHGeKR9RYn3a_egY0 zTJmJ_j#}o_$W&MKj8PNda#Hr;?KNZ^L@uzH4>~%k$+DqxLoL(n`q|D^q|~zx;)Dxu zHXs$TXg_+chw7bED;7aR-xB+hn5LMg+2K-Yz0g(_jXE7couQu3P2U>YVo?Ok!O3u3 zv;%NLIh#23C?k9(Oq>DkbXMPF`i}XU=vvl_qA@m{8v%e2FLI3MNq5&XjEqyek^JD}J zgN;I(YAnbD$no(Uq^-(M(^UUdJb;srVP2{XE)8OJ-U~c208%+0o?a^W@~ji9ogCs- zCs-<&V!RB!3*?n4ItfbT03Cb4j?|T{h*bU)-LBD%Hjf!EkOLW?@%Ay}BiaSaIu0!o z5qwIKx>wE=h(pZy2n85T{1?h3cX`efvE_X~j^8m3W{A@gNDalsitm=o={+JrevXvb zIBk)<)z^o=z5Xr?q-vX|58wCIF8G>KzNVxvc&~a*+W+jL!(LMXEtB#JoK>=V&1u9R$=zQa`>&5pgY8NWnQx)xVyXGt4lpf}13w6P}b;0YdbY<<$t{Yvm zr#`6MaL2Wgxw*w!hYOtLp>* zI@nFsw`a?w5>~wzXPV3medujPfzv%dEoquv_hCseQ||w$rfGItvS!QNj#SMS((A0c zUWuR5_EbsmKbHHiSN=kMUMLA7>KE~~X#Ee?IQCaMe$edhdDQiT_96;D>e^pW^h0|g z!auBZ?O#<0(?x>>8(n(Z7?T@+j?5lJZp1wX>&7^6;3e$HtbK9+T+O$)bNYLzB^8riN!l!Lm7lgt`8pcdPZnbvRD+{KiyXh^QwIbX3W z>D_g|s^RA6zW%xC18JXs=HLguW|&^SQSy4pTqG6PcD>;G#8*o&L95C7u&ib2>DxAY@&n(txl<|MwxoNT*vQ}%2|CswhfRzMh`nMn0^pT`8XQI_|C+K9XtUVj z=Or_|=3xWPj;sf{Er5k*G(0*lJ zkbcMt@q)s?g(c|Fzwl^kxJGs5L=JZ`Ie_PcM-UP?vrG`fiOr>#v}CGS zz1>Jtg?6i$DgjnxBmUrmFPQQL=hn{qHYVL01%txZE3Sj;FKV%oYSf9_ZQDupvG=wu zq`k@D4dysz1=%wahe;rQ{j=b9KCeU>p;x1Hi_wkP*+TPp3qlzuk)au1e?NQG6DC18 z!Nh%>-Pnak;En+v7aZNOOPSJR6A2Q;920IR>7=8Ca)vWGN{6$#H7=9#Do5^zAuyZY zDt}DRCHt^J&`-WqiV>&Wrkj)Ax({Oxg<&%}X7MsXS+>6p+}RyNSb z|Aub=6W!+MM!FHoU(oG8(Cz=gE#oF#aU8uQvy3j|dNv01uH2*de?zw))9oj8BetfX z!D-P{eo41;bo(c|fw>@Ll00OBSf=seL7GJ%{ta+5e-9_KeAb4eS@t=kO^;qVe*Nj2 zr*52@Ii9NOn0M~U7E8g-bSn()ThpN}>Bsk{+e7Kj&FSX#blt^#W#v)cBRT%vxOXo&R^U*70l!N0my|H8=Zi^v&890-I8SO?N8qgufg4 zPUKE~DzGP2^=Q_|$;za<`qzqY70+(H<;#|HRE4yvk*Mz3!CQ}ID>=$9tqNqTI9M$; zta`2eR{QM96bSMfj;ocLTi&RDy?$qB!VUO$&=*phAJcdMl}f!Bs_4bPRoU4Og&&WSq*-r0KRNGkYPYW3sUHJk)9t(%tq1j5-RVsmhLQAw|K{ zMJX8oU%#C4wq}bcs+fxOP^ele@PBM?aW&1H%u4u~d;0CZ+kNj8r8@V0LeGm1B*;>N z>=Bz(P@1*Zx$3WnZw}oUnmIAs^hWFJtuuY8>b6fL#8YCCBD=%uDxNJ_l<<>X)!=$; z?&*cjM^l}Tz7tM$KAx2j^WM{o^pou>c6H3W@Y>|9$+?!f7v7$@Ju%mwTC+VXA^x4F z@3p_%{@#fnHT_lVU$nm0m+E?Ik>VF?3ju`{Tw0l{VP^0X2|sG_6k6*-SCtmK{If5- zasKu5bK%!7QHK6IPk*=XJALojzVkWC$Dc($6&S+m+tqh$x9ea!@2a@-!Xo`p?uB3M zd$I5Sww)h494;@;`OEU}n$7%szo__?`m6QVyKf%2aUfMx|A`BUs0w8`?#$&yAFJPQ z&;Nc)-uH)Y9GdBV?ZB-Avzy=OdcAAz^qr>fwtlB|E}Ck=$(TD+{#~h}uDt9&F0Mf1 zwq_;#%*p)oPWXGn?+*W{{I9D1qAIob_#(Z^wiUSAW_swzvbNb{i}bTtW_MM8?6$k= zW-75ccGblB;&7 z{Cl!4#F#2XPez64i7NC;&DEOg9b4t?abNkR5$Rva_!kzaH?4*U1Gqn1Up< zc~?Xn@I*&jS-mY7UX}L&9wT%d)as@2#$hY6TXx}Cj3OL;QYIHioP0P|^U^O?&I!k= zcyL@s1->r9;VE8(E7jae@U8^Ue$#U)o~yX6bQqOYYeZY=Fscr#x)A$8ro*VLzUAJP z=`bpbmZOHwp<=lb?XBS&ty~5j6}D^*&~JXUq*m`Yi}KL=Dx|67G}Sn2W|dsV7~Z+`I{`V|XLZYbC;FSpwaQhzZID+j->Y)tkXK%9 zI<}|r0c~jemuW*}_3~{%jjcw|n{!xJqc#eF-{8Mk8v?&ZJ4$gdm#Yu;2ach`xqfAQ zA=d$ZSB4S7CT<+-OBew6;0+*F@CO6OU9tG1jwTOL@!7z1@x$jA|!xgmX zA=+Wn7;rndFwP&DL(>TD7d1(MW5C=Hh<#vS0@Fo&M=pNB^FqT_J0;qYlRlv;+|v!- zN&cDNbbO7b)5n^b600#$b)X#u?-ST93fZ1|tPM-6xKx(QKn8YtB09onDd|Gk9K&`i zo`cC_tzqjspz@{r!4M-aE^(9FUA0$pIDJ${GebmU^nhVbJ+B`21cfXd$26|lGQ&QB zPIn>(g{BlKxZ!%Kxz5hb?heQlOJ&li0Edp}tSCFnOO=eN0$jC$nlP3>&6H@(W&`Yl zCwqlhs!WU4dPDe@#gx`BVoT8TVjFH?)snKb{t~Lx5YUs#G-6d%2{3Gh)-U)Q#ClPx z@gj$LNfB|%6Ri=O?^p3K={KPj-O(YjjpIZLf$>ryRn@`kT#@GQuZcYU6-bXAhZnvN z-Hl8dvOFwDGemCyp*6BUvgS2M$&|nzj-qb=fxj4Rf34PQLxz?dRs6yz@fRw=3!1C7MhiuU$0H=x>o|O0%TWEQ!Q%=aZ|ci}fX0 zL)c)30?|P^6Q_k&_KqbEYbUZqWFhjdr^!qOYIFG~2v1g-$BP)MoX78>BB~#Zd!3vj%!glWl0T*IhfnqR73h;IHpC{|_{VmkSQvp8)2;b*tIO2_dpZ zj}fgT6k!5FKU9;bX}F10kPKo`M|7%GnNT1ILC8lmaMuORK#yY+XP}v`e{*s1)TN1<(@G9aR8&k|_RoE6A(0fSuf&Cd?8HRS3bRvGRmjB zgi8K0Cm1e!e4$lNS{3yXR{ItJh$D3vHnd}&NG(E8-qi{fY3qT=RyFl<={vpp)JEe%kzy&QV`cO- z#xndcmNKdoa(S@Sic|g$SmGcS@IS$CFH{qVvdg$&9X1+QstEV82&kC*kk8o)x`jK5 zTwJQGr?e4dqNM4@G=Li+y&yt;8853^tJRv!AqmWHzD!8`5AXp<#vM|_nuYp}srroz z_1jbR+yA=$k*i0hd#+cdeHAmUANba!8=J4Yt`B~-80riSJHhVsHBHM4rGZpw01o7` z4!f^7y{dI?=wlA;e3XBu9Y|PO{>pP#pPQMOe(uAPR&q9X{Oa+Uo>~80?>bUHT6f=9 zFuukav4AoMI|RhsXyUO$fa#D5{X@a~vl~8gR@w9vCFom|InvBZrwP zg=!unlYYbG=G--0-M;cMT6}PiJ_ogF8B%Cn*R~V{EW9k|ZYee($z-*e3^Aba&j>=w z7(zZRmOv{uKRaJ~D(OD;Yf~bVpU)c?b;mDyLF+|fguwd2+8$4zqWX4S*!iG8>Bu-z zM8FbJ+}w7ojMghNH~WELETew*DWQ9NJ=_cVeTza^LI@>g}H&A z>YXn=o^&4ebGsjwrn4fMr~h$%$c9Nj)%cTj znvGA*4KZ&_4>ORn?zD!cL#cyS!JZ`f78(9-9ia=@fMe3MMst~#wW z;Lh8Wdb@PhL6#6JZ5-axjXS?-BfrttHaejjJ$GZnPmfxB8o zY%1FQeptqU#NQ}|!A{bQF@)iS$n z?#x2yiB#x``OuLC|C2cI;G^KlpR;Mw?{3{;3l?Rn2bt-SQ#5IWaOG)}rtGI1H)tD$ zdg%5(-5$ja1k1N5%qs|?GCDSd9J<9h2cb_n0GDE-<)u00L?-K(Z~phFt)s~C=U1fv zS}zrK-N)G*h4(=+3|}2imaa`#REg6y$V*2HdFlA})Lq}UcPhWv@NUDxt|K4pI+8A{ zxmkLn^i%4lp9Xv0>-kar-QdYZ7akE;UXg`YgbKE?Zkd;vOT9l+bhRCG_{T&KY9;fP& z*f>*p0UDxX7vebAWgK0>6zL$9R>AC1a&< zqIL2vq{P|=h42Dm6u{>^4y&^CAylZXZ8)OJ8TU-Nt?aJAX0Wg_(^g0Lv0q|+wbcIV zTCwJtK0&H&d?j>A=#YJ_q_kfyGHk|7BV!>&drP;hvq_0HT7FuMrixy|$Xzb_ouUi2 zL_m9s682m!LMv@ANmE6`En2+st9_3=0afA}CKcMe3tz9zi^8MUljMtElzs{QqSj)a zmL9eEcc?|tFrl%$E1|~?x97dWBSYCAC9tlDYnYH)-jyJ1$Jg*CEoA&AXr1EA)VtfX zIOA7qiAD(-sf|Oa{@LqcG0H2{qg1Qy$|Ggic)}_XyfH8WMAO)1# zZv+Ria%)H#v}^S^VNs(5i8A;?J%ITH#F}QtF73Un+jANtWF>RPY*CrU4}xrSe?12p zL+hPjLHPf4s|-JtokVt#U|NWsL?9dxJRA^t5OG0n$kZ#u8!#~eGA`$9CBAavR$t=S4PN*DLX!ILFf7K{!2Ar z;j)R?6eK>a$%AA^pyw1eNm_WrXtuapiC4u=B=tiGAe|HvTH5xaJkeYl?W=p7Ooz75sUaHR!mX@-F**Fn_zYhfV>Dy52N^ni6 zUnpzXd^>9pQQMB7$~C}NNE}s7z+g;i z8Y(fVS1uIoff1Qe0CAVd2cXb5;3!9>hVrtuhqY=L-~jFwfdTnQ1ZopuIzoBi_R*uL?gQ&0>`0&y!j;ndg$7^GB+n4W zsyY;hOmZy?mjIpxQQj3ez!ZAm%*fbjuqkn%gA$9gV``|tM3vmrl&P3V>^v$2r@a8Q z+%*GiebUnTj3E7&l>PwrJMq$f0~UNBaDomlVi{2vP620mfbguJZ?kR5WyoRI8|PS4 zi%kyf$0cXckemwY@2Ps^6J5j9I(J!E@ff%ml{5wBj6{}f(DFI>Gav-V40NVV*^SJN`Pf4(Mo!}-%n z=y-gsYkL2Ek3Z>Ib+5K#zBV*{7cTc~;*U;PqBvsI0ES8q&KZu&&Bm$cq1^S|0cCNdwEwce|4_}ZD-&B?O0 zzr0u3^oiswS@%)Ry0pJ8T~>ax;6}mM-S^5WZ@O=|XUeJIg|b%I{~&4oCsG0G3GM$! zZang8es8^vc2uT?Y_HZ{|`_6`@Z-4=C?dG-}Lm?d%k|;f$#k_ z2ExF-(UAB*lK}a!nB~I{+FMY!iwz^$y?O&k#BWQmCy+AlWOa3e*VViKP+qh zv`Q*p_sdVKrLrotrl|I#N}Tdqb7Lj3$`eAX zJee&*x?jY9AJFiAi+|r9>HSBl_HA-}-&=(6_p8e&yv|MGO|E^r3ctU-kivU>Pq-XE z@U-@9a{OSEm%@9t?BDA6VaWM}Tl(QviuvJV`}RB`IsW}_iu#e{Le!634hp-Aj`$rv zD(^g8@&hsPUr-={?M@!$M&*gWuB3xLWZuiL5EPsZQvdh$b}=W(Splp0ysT5teiN- za0=jhQ)Q=JE==f>4NDI~I)BGTme%g@&(HxqXCvh1Mrd6yy5dbuoXKuxuZK^Y$l4Af z*hwy^<8C68RY@YDqyXH(k6a1`$gYsKB{=*~qY4Nk!rOrGsRHUk&w^-L+5>>-5IaZ< zC-geqo9moX_%mdB9pnI!EZhbIm0QyMy(WWhkQ2+${%6NVWTTyg=_r4d?@bFP>HLx| z9m4Q$85s%_Lm3OO-Z1(G=Zk#)sb`KK>hJA7cHpv3&<~jRdRA-L&X7r~l`;zKA4BeK z_;6qVr|HFzv)(CK#%OtjA{iZpt-AT2z%hXe&P)TRn?CEuXGXvDDqjZd^8%2ug`mKu z?KJp&HW;by0&oP2ly6e1Z_w=tL}Uup?h@`Z%a*Kf^p$duZa>C1nhwB8iqN^pq@v1V zqKM#KdrbYv#VWMU#KB^axZSvk1?DianQS(*n5|b?($tDy#OGLY)=J)5oO2Ax{=%xx z)T++8!8=>$S3R<@>ao>IXU689OEx^R(C}!g;nDeq$EJ_| zw3-bNZ^mxKW zUhx&-s+QfW4Wi2WMe~$qC~NtV-#lym)F~TywRYmwk`eu6P4`F?3=*1)x_BKEDTFbi z75BF4Y?nFp{~5XG2*)!}I;4%kQl&!?`@7Ut#CavB*R|6La_>E}7G7ay*TLR7=?)6% zZ!b~=ov?F0$@fsuMd6ddCQEZ=;z|mo5HeR*95nin1}`}z-9>SPkrg-H3hDMLec`3h zA5o}@LO-F<-_os^9+`&PKp`fi805%jom|1`0v3Y05{hC!tr~m%y=A^UXek1Pn z*<$IS?TGE;LZ9on?LJI*A)lG4ygHV3Q3Pld)s*(>h1Tt<*6nu&-`V`V?eA{CGn{Je zPSx+r@^{cJfo*9Kf6?r9wagY~VFcPT*Zuav+XwG#eaH4a*SoGeU8#<}WE|R(U1f81 zk)aoonqSzkWoP%O}Y;gIoe#6H_t**-ZpgJ_O zV;7!LPhZ(9Lsy5cpSXH1TSzf(&0P7BR9Q=wK0;GrLklawtcRYwQgQiW359xXF4t#l zGiS0A{lXgd)a_GudTu{2p5J-;d#Bz#^=)+ojo57D%wVhBbCu2duF__PAYM zt^3PgtG`u0+jDD8sx+8&;RTv!va>Fv7`J9rTzO+GTSPI%Qhi63vO&w#c9zgnsZ?C^ zi4UPgVW&!Qev3*3TK;(|0fTSLN_g0!Gp{1GMkfT;rq{N8Try^J)mnE1y~*ndj>_!{ zjzV9c8XWXWtDCc&D|$lh7azYVBhyf_?JVa z*KAj+B9wLE6_sC;Eu>Ixu@oaLtSR)k&F*T4O?Tv0gv@Q*g^e=@-zooI)w@-nQmn$W znC9*vrn7!EsG&u;>6g9;GA|euc~C=g-RwkFuNE#O*3t<~z}97^be!C!Q7GdRKf~ z67k5T`19ef41eXaeW-pK+RSpr%O!nYxe_LC<;cN80JL)N4mmj&|I6M!pPEa7Y7APY z=elg4AZ0a--pV;;O{9YBC5%HWSNd8&3BInw*Zzk}S&x)edP>?y=Us9GjS%u&g_PB5 z${IX3;<;9RrnardbDi8FuZh%?aV}y4Fa&Ji6h<4GkZM(4Tr=Vt^Ws_%w>mFwE#lU2 zTr0-JqW9EULL;{9TNo6sLp}k{hf-S25U0EzX_`1qTcm(tz#>OE$bD15W8IFiZl0Dd z+WJ~RD0Q+cmGFPTR+PKISN@xV?)W91yND|6U~;3r3vA&}3s z3tg^$<<@Jb3a#wFU)@(jY4Du?qwWIt--UL7xMtMG~m&xd6AkWAEPXc zf5?`MldIbn5^4zcJc~D&P0L#l=HVe5h+F>uVwtAx#6XRbFEr6CqC$liMooIi0u$N^ zf|slMvk|)%^?T-Ys_NT1*ONsR+JRd_P{RCdwU@O#VVcOjt8FXPU()`9q!P?ijeRRT z>40NtM0Kk=sfav193k(o=7A!uE72kfY3|L{0kYOoQ`-|6kB*F;>0%pD23B(h!k!gs z^l)EI5=&CPBYAsv(yG0 z6CIo3&Q7YeNs5~{%KRv@G{FO@{%L2Ov%rz0#5!E%)GIc|jHUi)oU2Fug|wuK$Pz+6 z>-j8X&^U^P7%DJjHJIUOt<^~BRm4u7g|b@BL_KK|m@B8s=tQmbZ}S2Wbw^^v5g|Dc zG7xfeSvGYM3*1$BUa?vh%|Pdnch(%>kIHf+))hDl?_FA_usmC^e;Am+a>fy3nrf#C ze6XyBuSXJMb)l*82~q`s_dGuN0!Wx${0Z@Ico|`~)^;O%f^*~Ogb1CAFH z3~c!h);_nl)s5 zhzw}TYB_7m94$F3@w#@(+l0Cn^WgzN5d}+ zoY^2nc^8yZNVw2EiJ-C-djy>8#wa#ZYz$<^Cni|DA3`%IZ$M=-59?%ndF@bkA;V0u z0a?O;x&*P>1zw8Kh9}=<->|_1Q+p#_Et!(O0{##2Yz_SzaBro4RT~HIoEL3zJ88`$ z7F!r`!8B0nr=0mBzHh(E@5L8z7~8LFHNuEb>L*UONLhp@;-QJBVm#@Fe^VYj>7?fr zPGju%Xel+5Zg0i~6$VI@m?J|SEBckXR0-2YDFQ$4f{2}6KRpo+Hndvr5Ekm1KjZqoA36tM** z`CDL@xdND|n+b?i7@~aXR7L?qW@GaY2#%)k8gO*aUw7jW9o$qo@9&&0O1sO&nW*U< zUEdx1&e(f{cXu3_uY5AKRGcN|GoK1oM7*4?O6j}W9I@4j&3 z3%O6(5~--}Q>n117%soc>To*G&p+`={-ZWlOMkm&Um+B6Q5Egd(ag(;A=PCoL6xSy z$_m6fGSRZYXyqazO9<5Ru!2LwrktE9OpYGpHBV@bh$DVj!+?}@u%<&!LaPfY9tgb@ zP)OQVhsJ}XMf$PsV)+zyJgMHP{~j5K&J%>Fwkw-|At^-58gqHPz?F77}R5bl9K84$IrsK;Gn~pXx;a@Dk zS^;<8Q;r*CS%T@MFsI(m(<f79tV0flYR+u}5m+|=D zQLm7l1>6*rl)v)))#q`fV0HaMb$hD1eQxV~^~Pz>eNQzVRa)M1eM=Iz&*L_|@4j)! z;0u`4gVYDwMJR&%gr*$#iHaPx1oUgtmd7c1RuWfC1=KG8l5JK1Y@DoTtjCw^I1xAg z83kso){smTjt)dBZA9>UQq?Ub4@DO``8)#kzz?C8#k!2D^hSp-lVv2klIRUOGk%=* zJ%Zh3?)kHx3sfZ$C)}m}0FBHUPU_N3fjF-=ZzMo=cjVX8I%;3W6P-=DPj^n%T@3`Nop5OHNhwg4(`f~7+K8SP3aXG+NKnM-z zj}V^E*kU%A3zE5m88Fn8#?ZrWLNl*+mKY0b;EHReHhIKR%Ifi-XP@EI^|1F)HI+p# zVkZN#{0#9WfWv6yO?b_O$(W=iAb{|j6`3_lKY{dAJ^>}bfHAG}9$KZmPq**mmNSfR zQS1ra^2YEyjUilo3lwDqBtN6EJcchZmTsx7V`2U757zG{3+Lt({+G18S21nBUsZRr z|3?4piNCH2!sENQ^p(R`4_}WgRClDRJLXQzS8x8%3y+&pbvsCv0}g`Zn*vc^#mNCA%*5#B8QyUQE=v=y3 z+`3MK1{!hN0vTqSVk65;sSu9qcmGqH2AL{ z{_+=+?$tc;GX=-FA96s0b`*@oiLQDGERGcm2OL{kTd~HA-O!tn9dJqFN~okHL>UFL z4W91`Uv@&f#@N@`;a}4&7fm?~8!Ne38{W4(8Yzl__D-%b5434$HFsLQ!dj3fqr#iX zG=(@egoAqwPwMHHM4tAP+|3LJA9tU!%A1R&S{Gg+#~ZsbmD;-qMSU z_C3^l_#Y^2cx?E6WC8ofEBH}b==QgCqgbJ%;V`w6nwUcyWr~P1!2GVs_GKW>umIK5 zRuK4YMrK!}k8rHSiG{{3A2e=(_T2RoH$QvhvtRq|xvg*Sy1nbevh8W1BlivR%CLIt z^aMlK$%B&(Cs3|nCTR>I!nvek1nq-NA((JOBVniwQ9C}R8*fo*Yk*zF7w{u?rL2p< zItEuL?n_9SGxxk^3P^bwY4R{{98r@s%QW3X?L5ovykFC>P_sEzv-wWTe9ew&?~i>A zv)dM09{Hf<5s>>?r=zIh)km@te&%-b&%cGF8&B^g7U>7x3CgO|-db!%F+tOHtJ77h z@0C|T@o>I;^QR?+WySEDTU5Ms)g?IMNjHK(E z69;GS5Jxwvv=XTsja(u+UocmQ??Xo_fa1vE3Wng%VHJvC5;Idmj2CRZMB<#WDG+g1 zNYTSCCd7L>fLyGLrpN$|%r=w)1XvCdX1=@`Bu(D(SH9p~lk%>aEtqqB=wb3l+UVa$?%<}&)?74;xn)Y0bz7JYBM*-}O@128VU-SVj9BPCa2G^57o zHjY~k-e4qSuxGS2YCVn03R|jLV%Aj7MDM!W9;Z19Fjb1d(gGCB7`ZuVi_ zcZHEqTNJS7IVT4W(P8$?2Ng0NF*gm7BBm-$BHEslG=x(|Vk&32n26Z_m%2BBZu30P zL;(UIK>{QI0^Gn2+*eVesFhl&U9v6NmK-~(Q;H@inX*LLKS;}B$V7JB6Vg>;(snAc zaVjctuc(Q8Otqbwp0*P?-8?h*o(l+c2(#+B%#81y_VnDjkZH$>+cWn*@B95L_*1ge zbZ+LCh=2S3Z(rW;U7nW?7?z(B-wPU76G%vZj+8(1*Y8mo@C~7_5(9UbunFh_I)%iw z!3^FPAuo#1*o7N9*fewtzD_kFU=E_tO-vUZ4$Mf}&MQbT-=a=8zO2)&!xMO0(rx6q z079CC2-Z;dJB0+8Mh1}2j+b^oA$#6m74t*u{MwPLN8b}pxhEoyi zP~Z5XTVbAfQn%7178a|@N$iJ(XhMeO)p^idh2-Q-wLC5H4(){6PnQRv)Hl(2V~XrH~{)lHC`&_a&YKTfP@jm`t6Qs28hinl8Sb)P47e?pw%4 z5PB9Av82RyeQNWZa}~3wiet`VAXOF3Ih*)C7;^?E+NLt!SKK=5`zFzxyv7kPex>R2 z`L+L&>C|ZG%}R zZNUU-GKne^B=08gGJ!IBVwx#%f~u_l`QQ&!_p=#;ZK(r|`X))$Z-1^l4>DK zyyfZIu0u{CCX<+UX&$4|E*Pkn@qDmQnRj(PmPf!t)NN_LgN`vK&&{Koqpr}0x@q^| z)q`<=%e;S6%)e1Vc6WML&A;{US>QibW2>P z9tH+g9Xc`joYoI6`2#H+*>zmBUMc{~%53UZt@**KY5>7)lh&IvJG9-eHjtEVFLzmW zz-YPFxSwCJ%i0Dv$z4|AmdW#)#wHW(53W5e5$MMk#3Iph7?x_nm=`;=o5+ifK@Bwk zxGr8uXZ4BjLIzkS+-+&Uw%`=qF?>77X?D~!ey(qu&P8PaSf_hwK z%vbqF>(rNju=Rc48t!+MF>mG6x;bw>^}E)nZw9V9~R zqCTKbdeZmk_V?)L3V!q(N{PD+1y9-IPvX&FUP?C+Iq0Ka@@14>OkP`F+HyOuWInGZ zmRB_+y4`3Qn+C+DjI?TDSk@cEiT7)p+v?>jYw%(|XL`%w{0kja~vcFV$jdan~=upx>tpXN_ z=kyzPoUYLBl&k(K^{QIA(r9-jUabz5Cq&l_Sv!eG$p>;=uUu>A(@om7a)qVIB&0rG zY%0?aOW#15V2$)Gd^cFTpR|++HV!j5RM0@qNL{KTT&Vu5(20u-Hw@O@H5?4q2|19O=%<&0+{Djm*B`pI{?Ki=cg%meWW40nvZ=_m3s*0^ z?`};91Kdl87JYg1zKWQyVyY_cs|A0nvVOj@Emqk!8;Dl6#VfbRoaI2a43FLSVczN) z*X*$$b-vU2-qHBBhklaxFa!WWAm+Bkf^9RqX9KhS@!+1(`$qPTuOmj-QR|&_tXCvC z&}T#rjyq`Z?!@gvUSPTF&KE39)}hy{@<< zZqt@TO+UeuyfS6bXk%wMO(Uzc{l*ZCgEjc1umk%GJxAV+tfd^!*TKlox`MWhN%)gw z`e!xMkQe5F7cv^0gFW{KpoR7!6lF2|RQ>9D{dT<}OX-@j(X7M@>ws3$I5~qG6&?<@ z507?9!~_yvW4i@^CG=I2j#Ws*tf;8+ds?I-8WuLGCk*g}w3DZf;bgM#M!-973s)9Z?C#B&qP zu1GWbq`D3xlk$Pk&^${$l=Y!Mpu90#Q3ouN_0pqQVN6y}Oj&6oj*~Wm<2_|TDnTVC z?fiW!o|6XhHp%d=bb%*W;0ZYazNu3|d;U1^z35Z)Lr} z4G1^bpv)}>BljLn+Nt8*{s~PxZHPyYcN^L>VVBkYrUvH<)+$K1J#U@9etJHzIU3mf zL1>Q*a=Uu1wZSKCr0h}7NW9r~rf=XZQ!>&X$}Ed7H`7Ze!#)G;Rd_e%Nt7l%=^6TY zmwtF#JWSEC{v?@5Lt#PNJM(n4Nl8wSEg{@SXm$Z+L1^brxhm*WZ3k_vir1;!e~K^u z3D~zlcNN&TKXv6zz}4^M+4-`zSXtX#*?NLrDW5E#_Wz`4)tKYM!pf=jZ`RHgwk8Tn zE)Tsjv{+Jc29++RfJBI(EJq(Tu>t}B zXpa|cpL6a=c=BZ=-3FI%;XRo78%G{IcJRpIqhC3;Z{NNK>p!eQ=^Cm{t=!jAMVpzh zyQp4?pc5A8uTwaRM`zalU+DHG{m^EEImZ&I_z1x@iJXOmlve#2%K2 z{$4>1V`_Cj1Bk>*p`R`n?X; z?~hs8usyMHOJePY1dNN})Vj7Y(ZtuG8njuWICQ7D%u%CQ8?)6r?x8YtFQaz~#eQam zN9N;`$ER(u8-L{bBhy*2(zaOcx+DyVYm!-t5qj&D4U-$DnqtK*G4JZ6i{81(Wc{>k zZJ$j~a+J_*?fl1iB@fsOtrrF6B^ngtKQ8RQ(f$iznf6M9Zwl3U3vA1AWP$0?Z$7s+HL zPyUlD-m1M`J5wBM+$MWYPIv6GQk-<2c|e?RhROTzE;tg-#3y)((@e+P`)=%;ZM$*b z65S^A(;em01r)vDoY zmH3&$_c+aF^NGCs@|!G21KIWCG;@|u@7c+hbOY7Wsww0irA@ZP5t|H*0rgNwoF&>u zq#BTi(~bl0=eWaQK3)-az>B5{$<)K9)-d4C43h_8vk;j?`LKUlv$x{=OnjfU!uRQB zCbwZ1LYpu!bSCI-^AO?eu>GW$4Qq4Q6x#z+Z1QJpLS*%j@6Z)fkxj9^Y>KVK5>jhf zy%2RIhxQ?~4`$)n@E4oQc@ajwemwVwE5iZQ1m#90D%EH#J%Ll!o`5JJjG*&i1f6G$ ziH*DS`B?$tSTQf0!isNCiX0UpM+F=g<;ScRgeiIv!WDkbG-)kKIS}`X{bGf8LF!R= zE8j^Lu)!dkjL?fYZ^iJ7P3164i{nFRGDI&?OB_ncD5c506?IQ0>ZKgAOpezibhw=I zDc5EQwN%DN+~r^Qgm373F0{7OV{a|FCjZELJu5H4q-%wOA+2+Wvfjd$#9&{{7?>?=4YtQx?^P@oWpiy|Si`F7C^$nw%RC)u z)C>@!F%OZuW*glE14OpB6^IF1dLf1sGh~MMr?A+SL1U4wf@FJ48t6G8_OGl5cvAFz z>{WDK&xole`Y7Vi>Yi0dz_3NxU}vw2!gYuZG%)bo)GC-IjaiML7qxlgdPowK?dqnz39qFz3&wG0%u?`Eh#7mnq9f93X_rzgK;obwmgL)7ZP9; z*h`O6OkE9ydkF6N38aRaR;I$;VxE%?SB~wIeGBKC4@KtLFXU=nN$I-MZcOqEo|KHX zEI2q%Ld9Co=E71Lxy*tV*C z0|-L&mbLba8Sv8qCz``{sGOvc%pUI%n>g6=meS^fEpLgTC+^HO_u9drGg(Q&mTLsB zL+4v+$l0&5&J-qc#Cj<(fd@Jc?`aMF zM#sbZkA9^ER@T2EKU=Fkqvx=76JfQ-gIgcaFH$_dxU(~WH@YwT^j={&wKTW|pMkf! zYzI7x97^xd54W{fmcOWjL)d*1V`BlPM5lP7T5w9hZv%LKSlWvh3N9`4H#k0yS&dZs zcNG1f(hrMWc#lhxQtIS<$Se%X)nFc%Pwv2~&*{HI^G3)|@6TZ_9MH^#W6rv%yj#w? zMOTmv*(x_h%QlT1SyXI*Yqye#aMhx#H0r8>f_tLoAxQfdYc@skTe*&2mM8LpupiFC zrnq7aJt!rva{Ei|j6?f+@tEVbzjUJKjmO^ix6BN@{k1>(+U;O%GR<1FddX%h&WCDv zUOrex!5U&R=L;q?al#D>uQW((_*;4ywUAjH<&0V|n{lL=fhG z%AkRI%$G@WYpwxiJ{;i@SDq3`HoDxm?WGrF&$jl%`=kaGqah7is$%YoaEFFKP%}*4 zfJ{l7=;!b0=MU(Iq=rgJjqOI9PU&6x;Z99flu&gUc%l=WT*0Gp;*sdQ1{>ufL+{la zD%&t6MW*o;dT^?tGSpR_ivihgbt>|cK-0(`Hr1?+Ik!QP8yBBuimR8%To}sQMKdz%?FZB@G`kp7M&3j|MAOi^fTocr75Zeb z!q6;cR(W~UJm7P4^JM3aJ{rqzn68Rvx4>xDne}q!Xy#b;d~QQ5w_(oN2puEY;*K>{ z3@RX$I#ZQi_UUd1TT~*`BE6T7_eP=UZ#qtVFs2HN?Y2j7{_6f^HC$uj}!il4y8h31h`g%aX=5o)i56Ri@=I?eFC z&vg-OaJxZF;>X+19-heXzc6Rc~E$sBYD&-abGP;ZlZE+P1dM_!*vu z5NSP!YiL(XNm0@vSJJw*nzu-LOc`lOA!<`HL@~>tK{7>DFFt5S3nEi1CnopVCJ|0c zSf=LXKEsXXkHX}4#4=*TRAGJ53EzG+!}6i2%bA&C_R})W2M8yblo(b0 zay|#qw3dcE0i_)#({J^lRjV9-OT_Q`P8xwhk3zrg6vUz5xBfx80suX1!*lzPE%mt! z^uUu!3|V%l?+!EW-p3mZNaH{fEn!2 zN158KH6f^mJf->pRifBMb3W0mAWc3fte$!_TDX0>|5oAlnP+2#+s7Oq6ckS6MGMwU z1#T6rna+yOgkN&mBFZq~;)-S^%@@rEN&_mPo3bMA_%T?vq62YG>mz8n`vM(^hQ z|8FP>E4iFF5fXAb+TskB+%4N>l*cmU5&lP$?e5I{*L}c{#_5@#(FxKkMwAi44z+tD zJk>4TFD)XC&#l_NQQjNqV?rc!kY1%S7}ULi!_34E+gWnMtl#2`C;)*q1=ccCe*OD}=)%aT9Rox*8@c&am>v%Lsrz;cZc3N;My6u82~+pnM{SP#@r`95u? zo2u?Y;2JYyg`7JLId8(QB!iXq6|s^opZzp(@ex*?SN;&~K!>baZKk=ZbKqd+W^=it zP1VxGG1#-0H8BNQCWDg*XoIu7^Ow!5n5!1TG_1j4D3qYO4hr9Tw7AREou)N*_#dcW zEt~2{Ibw;nNUH7!xF48r4!K=Y+)m4SMzx1^Io-d!|kig9++)@f7HE zs(?b;Nny#xaltNuLCNYX5gG;|1ID4PUZGTp)kMnFyB62b*I- zzv^y)F+cvU$(UUv!Rcr_o@H#yB(jaXO-GP^nj2@XdKJAZ|ta{(w zf*oJ+T6l_adq$qSv@H=Ry?kW+$W&J>Q1@n4jOs7G>TtaAa4c|mWG`Dy{%uv$xMwVD zVt1k-IA5@e^e}qj1?$G_ib=)s=|Hrk<$VbG9hU0mJ5JzDzye-4@_FN#>EI8B-_Ki* zgaioFRR3In)amm#MDx~zL*fk}NA99ebHx*}$^46q+}+i-zo>TXUS*k+(|uj5rhXlE%1u8CCx{sUZ;RR{cMHDfj&#f&NC4cWkF zNeki{E^#bD?8Wr)e4bbuY(g_!I23W+LxY>yDNSe!=9;kgawcF5p1Vo)8bg941H1_( zDvCygyeFs62MY|VrKVa=n0ITk9nYGJ=GugG>_O7US37b$nH6J zS)!n5WcQ^5P;K%0Uw&@%xe?Eu3`5qln3D;nmDPmM@fq zlxbcLD2G~4tNe8>AKwS3pT5x#2;8Z)X`cJYuqZv=nk>qrIsVmnth*i@xe)-ym)n&>EAX1mx^sb|%%F=3ySkI@CUvVq` zjae^!Pw}O0eA8zW&oh^&^pB~rT>98Nj!WM#e}2Ito;PG2mdM&=`R1HvX5O4XjSJe} zj;5W~T1UNlz8?EqtJ!pA9)1X1z1|fDJ&FE?!S+-@5N%=)soE1@3!M&%#rXHj@-{nz@Ya5U|Y={0)aOp7jMoe5Y) z>c+M7xAf{wdPUz$JLqR8{g6Eai9{HiIU*KgY^f~RxQatwktr*Kev^uPmg=hp6EC*b z$uwJL(HpJT)?Zyuh)6|mvO?(3=rRdZBvfX_El&m4YU3?W<3~=Y3T% zUscqzdaC={lUJX_1q^_(IVans(()18oRd5}c>_cMe*|0cJm|pA*S5!M+h^Nu+T*o* z;T#DF zj0g9PWh~^Czysy<#0Q6feGyh}zPzM?cL*n&bYDN-R0P51Q9p zJvtL6%AxYM+c&y@^zcO6oVy$uEDVku_#ij`^JGrRNFq=|7*oY%-8c^O?tif8FzNB>JU}QWXu{}B z>@>2Z8pJC0<-bK&7wL!AZ=oj7Q<*k1zJ_dosi+BQ)v0d5cMf)Oy}%ys>^>W2*hQZG zRHmuIboe_&k+Ka>nQ8wWO?Q8dEI`cwBcTMY1AUYGo-Jg<%wte$bk3pS4&(C^)y@!Zyt-AS+bCNf{X z?pFD_+n&OS!nmh$s`ZwqhPK)?xNTEMuRV74u{m#xY|Tm2xu|Dj)VYz@D_#x^GD>Pt9yp`|qes7g!3sZy zUrjMvWHe|^ZIfgLLc>}`ux0XM{64iHEpcc;r^QnlbyjdK7-W=c1<)`go+|pTb@153 z3cjo=X47~*GQ=n(Ud&G;D`L80=&gY>!p#QN0s&)m$@*q=FWecDIhv9GMTH0&3PGYh zr4*6BrD6~#iTOb)!s`n5ixiL>l)5hQNWgVWJ7YO(9kyXJsLon?P6SZt?JqmJZH!Bg zL8tIlLE1up1Kd>;uI~>KI~|%{2GHuu?cmS?1Hgf85#=N0(5xCqNz(<~JAE#6b4t35 zId2}E72sOe-#_PX1%zS{nsmcgKB?1ODxw_3S(6#?lnK=)u0j_*r(4pkU|Eq+cq5*#&fe=J1zAHsv7plY;@4)= zRgMz8*-Z89qjCP*+J!ikKNaC*=F37zgZn-Fn-(t;CQux7oJb+hAU+k4iV z8)BOdEz#5DacdACZ%kTnni=NPdx0goOK!?`6q5ZCPI~(#+-mkqpU~T6*)FT2jtrRS zEG(El;p^mqv?9l*gg=Fuc=!9sEz zjOF9@9#cbfJS7q$lJ9yg_@Sx+HlRzf5z zuy7F8U*`GGrmtZAW&YM-W;KMcB`Mj(ZBKR&#EM*I$7vGtrW~^64Ts<~GZ0TGB@k|b zik)`S$<|$&u@JfPhI`n>)+wwsby<%~S%q22Ps z`8@^U0$4**k2aC0$m3qPs4e8s6w=I&kmn+_8@Z^3t6jKDEylK_WWm9PZCwvw{qG2| z_8h7DLEH?gSf)(LMum0$wfzd-%GffpiHht7l6Eh8gF0Zzuu&0d?2#1``#B}%CU!cz z&-8XbB@?|e!ArY8fi6Q=io&AEmBJ2X>RBO>Wo_*CPzNl$y8D4z{PfclJ$=sBI;l1* zMz@``h1$)kaglRmVWVvXQon14@4jBJ99S0)_Ejnk-%i#l?I(7NoU~BFC#cBXPzdc8 zR#cQTgNe`=FuKvw={^H{u=W%BO&xp_F3%?{5SM+lt1HqY=TI?WH1ocvSKT{?mOODn zuJi~vx{BEpS%DbqN)BYK+QSRk^7Bs4`GSj^QQQdX|6L+W*>YnwRt^IXfi{)IkXjH8Sr`P<=kp0!POJ&%)l58m@N3!cPY(j%kt>%wbhOqBQZ**jI-hUX!Oz#kiJuS|Wrpt0|)f0m)udr#z*4X~L{a zv2esK0ML>;kWXmhb2nJRwRDhv-lZNQbG3HT1A1@ZYAv|Py@H(LpilG+-J>Sz9K;I~ z{Gh-sPx)Bn@^juAyX`ixr1wl!Pupg~?>o07%HT=y3qT6$q96Jk_u>xfi;FCL`zenT!zgWj{)XlT~8Byg8zon7?@cklp4$yd6tW? z9{F9OIRbE;PJt7r>A7|z0>k0K-O};|rLRy*)bB8IgeH|qQk#*KG>1T9W229oGQe>k zz*ADs0J4`J*9+VIux;2jYL%L_jyY-#+lfT~p&XM`+K&{(p{Y@XtxtgvlF~-gq>MvA zf>cQ47ogJcIKCXVh0|ZMLa6RkzSYiB2vSoTb16qy75-oJn12cMu?!jtVW*~NWVQth zXX@U2QIYvJT5WW9rb~4rD5wxx@%7Y-ItXdZ$%B-wiTl~90X>ZneW5IA80>I6NWHaP zS@E#m>DJNSv(RAg#d;27d&R^<*foe{9$;N!{ZE}7;5|Xj4C%a6PGtjK-SAV^Wc0(( zF^~=ea4meccTi9dO3b{9@>BuNA}oPX3N>n(2$6$|H5MfRWzq|a6UBWmMQ^_BYaWm} z3&efbYF%0HpMLsGFZB3jv;(r}073U;PozhWNoF3u(ITLOwEKBJyl1{CJ9G${j+F(} zvJ`0JBaxm^om}Ml#>S`4qd6lD^;FH|_qw5u$S`^S)tb76Cz}OZ_n8Q*khd(?TA(F@ zwHEf_;yZTI%7=b}ZIpBl>_l!1siSw8@aOb%f;<>BOG;XHWL*Skt^VH#tLU!pL|8Fv zvDp0|>Gr$$kp)YDA(O@Dq!2zBGE9J)27=m7ze#gA$?LJeCyLu9H%{$|7Pn3BgUo2A zBVN2=WOu^top+bS+%U0%8hXN?KXQmCwT3KmXe>)#`F=~cR=ZH10$ zN$f_2FkxvKm0-b6!$_hmb3{TBpA-Uit~kZ+pq&2!KK>{0a4RjD^^0vAN9;g!f9=4; zv8js5N9O`HAA0>`dtS|)c<7a!tIsBFY1s#@i=G2Z4!THqS1slTNB55$BiTK<=9qVt z-g1>r)iOuyk$7cWv~o+LBs5>r5-VvL**CU+^Z|0kRPee_fI+?Kdn@mH-qfL3(Q48? zDEQ<3pVEo1K@GXRAdNoomrNXcbw|`)xyYuBVm-iAWjL6OFU4((WOr$Ov?i1bcHJZ6)b!rUXx`nBrh8rKwj+BQvXl0=;?E>U#fY%(=B;4 znB^sJJui9u;TK)-q>mAeZo!lOEA9;mNp_zer^R{U7 zURIJTk9o@9SQqou-44O?$q%x|(#Hl~$zBXq&xh8;LTl)DJo~Pz;LPV;1%>NK+CLh$ z^|Ti9dPq7IE1`9pqCKcuLy8t>n!roow)xLg*%U7g656h?xKr8H>XbEpkLtSs0azLH z<>Arcc~2uHA%3r^k(uB`Mm`XnSanTP`q&zxUDoqV21kx;2HkBvSgu=7RCzweh z)bKz5Er5w;L!Ml3S-aul17ocWq1|=mt4{4H_&dVp>2x87&Hc%LlE?6|Uj za{pAvwS8CjO>ewZzmCbyJVW0&5`#K6K;I?D^Qb{n5bwnESvTTN)GqGWcV+ zB5Tg(+Z+-$d+72`wNuDYahmQT2;W)%^>axJZb|Tq6YxaSGroEJ`Qrd_akwYCuAH7c zJ?%%>p6fl+L8wJ0EqFd#@DZJsY?gE{2Sk3A&uk8N0Zl=^IZm3){8PH+;VTwe zj34z-)R>lNfa>MpBn@YYa!%ORW6E*vNoVP8LOAb^@%0E~@*$C-jDU=s1 zAJ2ksx8R@b7Jl#HYoO~X)J})WSCLUw@Pd&2x&&OB`j&z3&h|*BAoO9SDuSBh3#JQY zCIJbA1YjG)Pv8weIgl|R5h2G3d$KO_fB-fVcnN?!Q>0cJb{;3x)!p3#58lXyf|sHA z{DuI^h@S<%Qsmr#)Qx;8{3Mwpfd{gmc{O*$-s*wF2AM;AR+fz&?deg)JO=3xt4^j0 zfMh?rJz(GvbQ^oxLWEooCr+?^6~itXlVPzA~EzDTkZK=|Uzq9qITQIMymj(2lsi5D}x=#K94_wIOY=6?`x1G<`ki zjopO!RJ2(WI58?-snl{92F_dyKR^ZGnz%!f1J$A@EEckelPH>Puw>adYSG@lLsb$$ z9Kn#e9HhzXS4^fgIDly0P!M*3%Z z^(KDQZlot2OPAN0j*R?ss(vl&%33ifWhZImN3Q z)4k=(YuG>o{|BmL8eyP;i%PzmHO@8zW zs-Q*h%^!Q>w+Ep+FFG(dwHEkL*iV@`LqBKfr;mO#8kwo!EK~sNKk8I4Gw`(l>1PU> zd)3MmZyJTBpWmn4{~M&i8k8BJc=JhTa^0po8BWI*196Ib(0Wj1B(1%UEBhw*O>K>p ztcm$rlN1)3ld_s)Cf#Kb<>{iUKpK<-?AtB3FdIVu&Ibz#LUu;A*1o22fiIw?Dn z3uU}TElS2Btmp5{9jkfWKbKK@JEvg8^P$T#=J@R`QM_#Z{D3`C6eh-4V%a$I? zahS0jhry80bJU~8>#xIW!oQ>rHKH#M2V>L-pd6#XPjEy`||iuA~EH8f%Xyyh6OEYB6+wM=O> zt4XLAcxqNdT$6aWV!7`2PDRbnN8Sp03gw&@=yVH<}*_*G?q<0UJmu~wuZ*N}M{=KbMUK5n7QSgOynRs+8#xhq4jEeV(R zlyaR>Pfibq(1K-rUx7N_p3;c8y?bxIOTRR$-;g{8(!-TVw}R8HLb@hlIcAgR$a6Km ztqiaHT{iaJH3(DnOU7S|Z>vQetstQ$m#g~*4oN!nt8m}Q_buSu z(5zzewV2h>PgWyz(*;{Yn{*5vx$6bYupOk$0gV`tKeQR`QW-1YO@Ia?v&8e~6z>>- ziw6yN0V);n&kU(wkHicFg%NRtSq>*2hi?i=zi&q?Gymi<9QdQSnwk{BwQYB2aXJrYcF1%w&F{ID*NBnU=&+eZ$> z!D_j{fhX)LZ7->m=1AQ8~Km zq=%?m%7w@z%SZ)c8fu7hLHw80LrKZNp;GuwC(m>tyQp6!)QZutBD6vIn8<12HG;0t zlwGK4_%AtwYVHxLh@sG4ZdY^!rBxrK{&5T+oLHU|>e zC|hG+0zV=u9Pg7o!mw9K4|(kC>46rMX-tZSRaYMkGJ%Q@9V@CQMeiN8Bb-ZggcO`j z8n`D1BpQ#T^#qn9_YiD{dc%q)I`56tG-Uuk>II^O$oEZ4=wLs$8InMQVZ5CuKr+6x+)IVix!I z0k*j-Oi|Mmf+u1hDIk}Xc0&nFBI68For#3&d!8fyu(H?XQHGatN~{P>`_?)$k0X?6 zXgBs>ka@r&cMYh>lZc%Y+O`U%gFP`S5`erZ2+Udu)d^jmT?J!Z(KD9&5oY|ZXS<~K zkm93Atrs8(1H1sUCl6Y#%qM%!JdHkZ3hIQqt_T<3=OR4F;fl(dl{EUO&+|MC1xdo#rU?f%Msol>jB6cAs|NXsRk_cDp&$lk z4$_l}pl9akL+GLY8jy5Y%dI}(e&}_wW17vWu zh@der0(pUK2|>e!Rta@5QuA_G#&pUfNehhurp9rq_t_pyUB_6z7iKHE=?asJNT3Ik zLh4i{L^x_Rs9I&g`5h}{+OrWBvE8SQ$3wn{7ajI^4 z;$wwrj5#s|<3Xm3Ka5Kyf5!Qm`aTwm0eBltEfD5EBYOC~>x3u)t+7!l90$=e&>cR9 zgbYoiG%j0A^qf}<6u}e;60n;TniW?@T~B~nNOo(mFay;?QBve#)p)hu}@~9w*5seZtDhQS+XU@U(6alQr zy^`iKx$B9%$W@`Hs(j8Z#&9erT2c#xw$-BH<&CS;JdS!$9(Ng68(TD8_Prn_F2JFf z$vnq1Aodfyihw#Nq6zaHmXofhhz`-WS`SAfhO}XDoaNaDCB_OE=_M{URfmweV$491 z{|vxd)MBWUtV|hPAWOQsesm;RonI07n)QdZI#m7LvI8*M5OwtrU_GLAO@=wLpir;! zqN^{L`hhkS)HN0nqWg+o9YH@o18)t|Q_ak#Pi?O~;`N=LYZ; zLe0KztZAUqdQYLId3nQ%9meLdE7GetPg}@TvvYXC#n)m#CGEo|Rr(QxH47PXXOiB* zqXh?#0O^nTjZDZ$A5-8idYz7TM~zDifKgA6*~l;(SIR+(7&iPZy@p>BYeK-N{+Vm_ z3t@KHI+XdtG!YGfeL}R2T!=$2=EgO}&xeM-WrkSJVoo_md_^)rJ^&!P8qz-#2A&yX zR4P~@tcmjSa5_6XO9vj0MF)Nf<4PSea60Z>YF>b_)2ZfU2rkz;)!Jm2X)3FBC=2h% zGK!BOC+^f747qTpVxbSYai=mOGf|VDyR7$l>6YFbJTES9G>q64(`*C|iJgtM|;lU9Q3`+;T-Mzp&TVe{r3$yhXueD^}#`J9gp}rvDd^JHy8+!;~H938h8q1 z0&y@~o2IaPmA-@~7;LSR=ML>_d4)Vr3wWKfxYiLN(2oVSW$?ZgKLM3UR5cvjn19RU zgOb^bZK2kd!KM`>6LH8T6MFGPw|KvitI1grNF%0I4Di8z)f4Z%q2xga< zHnA0BHk7at9YWcqVfvxIzTlP_F`ZOVJh3jgvF#x$>s$nh!u2BUJ$bg}NmlY=PU0z6 z%&cUY$J49iqpMu}EaZ0zs=m`mk4c?KQ6k;y1$!ShXDn8gSO`mIMGan|&5}d$s8hVe z3DESeOPP~WCw5MhXLT5uv(Q#q6+WP}$dB6T9{3BTNq`7a{UNl4U&oul+y@ngr>Zej z50Pzz)NL+W?$lc{vp;aU@gGwB`E`3^>-Hwx1-IO#6Kf}imTYP3vtrIxIQGjNTld=L ziSS%mD^w9`o91ga#%eas+GkJ2YxdD=$n)L45ja2dzkFfz!n~)30Qd?^u4GPTUhzzN z#vO}=MPv90A#ip=J_(nB%3Vo4`3)>e6qF&1TX`zq<(J^0D^bhN2H}Y?U`T1YW@g>n zn{RA>d&i9(w;Ffd&JQK>Yp43JUATJT+SjjsJzBdFYKxmn6QvbbzC8Kmi3g@jX9i|Y z%|4X0S@U*U;eoIq7bZ}?TdS3O1_04bo z#%yVP)&BPa@%qCP*~uJBplG7wmG-Gsu)9j8x$?H&F07h*V6Jd2w0#RpC!Trb!W&1Y zOXH}j^|xwve$ck%>Z+TC6B)P5>Jw%4(*@I+(bnBJ_ukz2UPZLzepGjP5SkA~K_GS2 zc38(QBugz-TgTdy1r~3^&p*zxl+=6#M~T(+dC3tDzF1zBbfgtkLv1#%`ky||+Ir}ormL`<04sGFMlnwk0j zP>#}k$-+~0nby+AQ-Vip~0N!3S#5 zdq!k14k&i2tQBks`r%zPOPLsU-+z#FP6oP(lGeqpQQ^>_V{cS?cnkm}lak_sN06#C zp$ceFZOYYVHEkB<`HiMc_zhtt$1-%)7`=(|s`>J^Sa}=pfBC+wa=xrJR@N%t&j%V~fyQ{CndYhN$?OC^ zgSxqLS5SO;Xncqi;hq|Q>Q0`^o0YV@H0eg!Qs-ANCNv)3xJTy-4#LMjL{2kPVR7qcub>)JCm&tCGKF2c}qMYM= zTp~6`|=0-Irmwv4+Bl=<=GPs^^wlyh}|zkG+Oj4+QRj>GW)h$E+HW4g(wcV)Y7N zs{1!&M?TEZOO<|wxJ(^M0|kQiEe-&gqz$6OP?~6OcvPWP=QA6eIKwK9=_8tK0I>t4 zT4gKD)5~}8m}e11dzb^TcRF(8n9rSleG7jc1MZZ%~+n08Tio{VhJL7LYW zsf$y5DF-PDOSwAbOciuPg32o(IOOmY2X(Nne~U=>3y=ww14vT=jegx6a!l&g$qeMR zSXqV7oICf_z|%@4p9r1ol_LGJ_>1B>a}Mk#C3fAytH?O}pKA~87D@q%gh!iWlt5rg zx07&;B9xnxws7D(;SJ4y&3pwGZA)lRZ-i$=osBe4SHeds#h`qoNFa2%(#QegXq{3B zf|j)^Awh8+V_|9+SZ1JGkPnSziVYVLL|_f`jt||B!>A0_&ykeI*<6+s393(afgcU- zG~{-@Ko}LkP2cyh*DT3;5-$ArG6w`yLSc+ zG2f5YM>~)-7Sfm&IiXGfw1M5rUEvEx2`^WDe*(-1?9(nD^2Z5qj_mAvd^aMtP$%!6xwBo#v}S-K$dCCAc)>61vSl*4?THqD>O_DId2 z%D2>_Um<@c8z+io$bK?Su@=q}rslj(KZOXTXYjM&WAR%jdCTpTS=bW2=N5I0oMb3xN=~F z;AQF&A;b@Pz0|)0k&S{%Ql^CE&SH-e2o%s9l@Oql+=Bxkc1X32S-z@N zyi14)LtUq!o&&uoTC~I_N~iQAgP0KKfN(s?7_(g!@{)oN#Q5@4X7S2)nlz>l|HJ=_ zL$Jnq$gf6W44ZFiSwH@kPU43gZ$W4vPsYSy(#il9y*eJi)W^&jy|4uVm2crHtrm{3=cFFC6%Bl77f`%wqhPVAC zA6e3~OW-S@pz3xYFPgtL9%!5O-`w-DEv+DTv7i{tLtjZU6Jb7!(D?pFR*vP{m1}Ig z@iNpjO|)Fo&A5%vOPJWLcn0hY~$@e5OV)8Sd$*oAn()~I*u@;$WLWylQgJ8+_|br|6G$Yoe0z$FjHwjY`GO&lYh z`P4Jh)ibvF(sg+DizPckeWNr4H#Z9oR<}S7d3q63o2s2KM6l`zl)J9uMF^oy zyKDO4!5X191}{=jsTme?cZ5|PTA|bcm{(RV8*E%L*jFK=8xEcCfhL9si-FBNUy^i5 z>(RddqlSdE6^Z@o$3PWzxpFkSG6wd%)3a;{ywmdwX*-e!OKJyB0zHtcfv0$yMy1!N zLUyWo{H4c09%X2NGK4WuSPG1lym;B_c;T8c$A|v>v4L0Hrvlf4SA)0wO}B%!w+lmw zlHG}t1Gh`crySosw3J~l3V!Oe6jw}=IBf9h;2%e3*ZzrCKVaS`t%N;f~mM4yRP(1_9QL1 zeAD_?*7dAEZhd?GjrFnm%|D}Ou)B79Uv3w?#fk8h-pO7#BfJIF9lJGq+w0F<8JHY^ z$TNGJ0DJ^WOZGNwbaHZEK0bPUV(qQ$QVRHxRSWr$RSWu%mA=JqR!;U_H4I%VVdy#; zqC9MSY1?goVZ3n1_2aXSxmDY7754)?a>q|S=$^m*wWzaH^deNLdeAlRXYR)ZaRM(| zFRUOo5egv@;`ixekfV~)3HzG&G>GAX9j^0^G3mlI<3442BHbxm)4C~4qA4n6%jgvw zQRoMp6%I)UgIZIjzH6kOM%p06ASUjIzhDuyaA@?*2l3EPaD2oF*ZbXf!GV7C3zw#Q1vOD%T? z=Qkr1&?Kpe<6fC&sWIS35)E>JI+ICA;Af!6f~!O%Dj#NO+NLS1>~l&bV!c!|l$Hui zk}ecg_8?+`KX8EN(#PoMRXj6rBHyGyBo#JtA{PRR|46|I61$zjGHn=|z28pV;v8ZW zvYIWUTcWNqjJgk9ge?c5?Hg@#uDaVkhM>4yHeNPmzvjB?ii4}O>!%(cJOGSkCcW&N z%Tio^rRnvivGm({1tbH${F~#yIkhjI*EE*)pZ$4>;?h?RCNnL?wd~4k`E*8oh5O4z zT&z5#^)2>%Bic$HjQB`BWJy>t-cm12IZkJ!Jix6s+{LhzuHqqT{UD7*Ugl_BTgZ(7 z)w*Biw22Bfj81AA!|0UOAcDbStqsIfsN>f?NDUycOcI2)xH%TuJX;kHZ3n1{D|=)+ z)+GXk>-gPs32@ko#*5~Ct75)Y(@(^Gt&AfxlF4<+*wEej;!;QD3Voahpho4=JfzKH z?5o{!FBBfdB_kN7X0xTa7K%d|uvTys&=}@(qFo6!4Ck%%Pq`-rTQmI=sp#u=5+8?FvtNa_89f5{{bY>j!!VP1N zPhFOrHmGF*8{AcL%To z>X2avOtrww8nUq2}JNH2JEtymX$ zELYJ~@E7<*zfde>QUaZ<7fkJ|4DE#+V-^MrSIV43Iaz~Gc{e0l zqZM05G7}!Sq8}ZMQ8wd68{(b~QRfD+SkT7PTsX3p7Yp#WaXvXq#5AU6>3vX9`jVF!B%9z(?l#VU*(#g0-lNmI=E zX|TvoRpU8mBxr7{O-$8P^GKDy6bcWpSCihpUMNYx#s=C0G@!I$#Ha~m!zz3U>E#Dm zw3N^xt6<2+i^M07v~Y(b#e^24hBn0TaMeI|ms(m{MDm~}B@8GIKvjbSf)!1=07BcI zz}``CXq)MBsaVshRni_3LV+iGNS#2bD45tk0N-%X;%DaNr{n-7#-ad6|y6fucKdzc9-tc$c zj-PJW77uQ}acaglxqZ6g{o>}CQ)3y?;PwvzV7y^`!|N4SYA0)>6|J%0+8OwYhrZR; zMMa&w4)EU7w&`Ot?QzfcsB`--J_0$ugBQFXd3FWt4Q}#JOn=94lB_6*1OP=#L$fJD z9xJ1AwK0@588wMY1yLoN5M-*oNpOfxQLVY?^(wl`q^m6Yd7W-GZ^jk$>?A!S%}B{Z zw>**7(XEeee@1Uh=!aAn7BU_XzWgMXjWhkl`)S@v6a6Jfc_POpqMsxp1*9L-_m9vs zYBeDuJ4DZjWMse-{<)1sIuZb3@FF0p_gjJ3_i&n}pz`7oFrwCNN^ISkC@M?rJ(zgt zkpzJJa9vdgEqS`wx)Zw{;7-?k$?6C$0;rjwn61~cu4YZQUG+fropjI}aFsmXmrswL zp732M0K+ZsTKU!TnToe-Zq!68HpYrJ#d0<$GdQHv;x9;M@@1BW3@A{r_g>vQ-TGGh z_4b)30Pa`wPR&ejtZ8SodS|SpBj($cbn$0y8SHvOAUGGyG{HCTz&iuc`n@-w`I~`v zadCgF^nqCJ;bb;{kYn-sXd#)X8vT0G!;id_3m;$RD!G7H;iR7*1uT$>a>jUu@FEv2UmYu4gIcP+Q9J9u(G)G*7V~b0HG*%a^^VP!opZ58{%uGdT*kCm-ivfz2L+3IMYs9FLdb9*w~=BOqx zY-%*ycqgH1SHr@C&qkDJ;Za%kxIF#LThCs9cBcC}94fcRGPf)NW1Gwe(sPn&c6ffLd9@A%$WW^fsR zxAJ{MbISL%Dc|oO-w#a5y_0*VTCcTVZJ&NZbhzo>SkyumqH`tU#aYYO=Zbg9fp3z#fS6rPK$SSn0Gtx1o9n3VtCQ)uj#5s8&hTd4aJ6B2 z_l)oDyc>Dbhhmi*lQz828X<2yZ^9Gx)x|RFmmGMLtZ#Lck+W@_W|-^CmvE>3$UBcL z(bMEfYlb6FxX?~oa5-aNqEj+A6ORkPHO3=Ok1uCif3*Ic^-J_LneTN3rZbWjoMdG9 z$c-aQbepVBhfnNB2}3g%9|vy)XFGnh_np15)?G{VEa}a46wAdbUa45ci5)wC^z1v& z-t2zot5nQlV=>u<;zVT974=ocGOMY$#mRcBBb$ng6T08v^+8Mkb??;OthyPwSs!b^ zFSh!As@H4+AkUrJPXTjhtZ%2^NS}$^aM7#WWV*w#k(`_3G>zVfQ!*#dv4bArM1H(+ z();oLm>vjD4(3bssFAOhZez+!g)Aor-g+=gv+HnU_+J8WnXBeRz33sw)iwdj$1b*4 z2qPf27{2oEA)Gx~;Y|Fkf}5XAuj~=Sh>7hc)DU)@UGhA3kBqH#dj)@V-P@S{%~retri@h9r4$3V4Bfh7Z`ArE@?5FUvsMGY9=YS5T7|w|q_(_Ssq74~ zSgeLIt5X>Qkz=eu-!HjqXw$mpRTI{;QW~x0OeaNjZATZ0R(nZkCT|dEo{0O6{2?V5p$N*HXfl8$yt1;Ib0AmUO6Ym1CN$vv@ zgzPv|xC|$NJu?683Y~;QY?#=QaS_zQH2|;hIYPmp(DE*@1FGl@*rX|Vi(D9yqX<)i zH0yY$%Fu$S7>dfNizN5iT??f&d_4 z)&NBySEG1Jc||oqZ=d~f;#Lo!q;BfFVB-jr3yz#XKM+6u<3j-C3;?AN4GflpVw@Si z01L3*ZpHjdV?^wOA&3l;CRf!Hu;T0?69mE~6zmD5ZUshJB=lr2^!HJt8fFtJS1ad< z6Z-&F0u&#SjK1B3@C&ves6GYh4{71?GW;qH$WSe_XdJnpavL&)8Bha&aDpz~Y#Nc; zxW;%4nS(GE$S`bu!T>IWNpuX*0nmUz1;Nh)5;b7QpmBJ(sBxmQB^5bHL^Z>Aa2&sun z@gSd(?Fbm>P(AJM#lXb~lLJ%aYJzg_JjuXEP>|ARy(P38jf33C8ApT+=&tLNYCLLv zQ91^vw=&n+q`tw}7uZ9_ikEwj=zIElRTI-^Qq(VIFZ6ge$I(?CapWRT_jC&;Ic_j> zpEyPPjgrI&)5aD2MB2(W{4ua*vMAr|D1#}-n zVw92)p|;DC0nt$~1U1ud(Z4w#6rQkO7|;qwI86X;5}J%MtSw@fp6JDD zECCN!0n;>(MajRh24KbChdEDcKLLV;A+N5QaEZ;Jf_O#%yub@H^b$bE@`MKF#!Oa6SIn_ak-AUF#OfIfqo2m zV-vAkr*;`+S?15{$t@KJ59LzO4j)v|Q0|7U2G~0t3fTdI17%?V#DSnZgn$55L#Ss| zHNaFO(TGZk@NA1T^()DV6FWtjuxP>{U-)^KX*Y9=OMMoOVZkHeibmWa8eZd=93+<@ z66#JP#7>;pZAOEA{z6lV3T1;XiFpG;4UAm5VU#IJ%xq--sZfWQ=Je%O;*eKTf{s<` zAMQ-%gxoyO-Go36!Wpt&4IzF&cvt?BrUX(IpT$Mk=Mf#L+^YOn+l0Edl&rj zO0Opi0B^x-le*|GWNAyB^jp{|EM#eE2`n}TPZ0~b%g4FUByA(U{ANng%`MmcHmo{V@_76cLu~W?#!>>UOC61xHfw<-1J9XoV zvY7}C}GJ zhjjG!L(YrY_}YXS<+cptOHQM7$bGT6Utx<{%>11|k-@37FXC70afnjOQ?fObftm)M zhz`=ta+*YuDM!D`&N@vZ%alWx4yk+d!LWP8OAvPi$)~o=P?l7iQi2UiNbMZXd^1aF z5km=brHnAa|EYDzpnfE}<6{W**QvEMpj-9Fi@ z#xIJYt$-#e8dIyOwlQgF{BgpjF)<*FuLgW3Ho8xTk0tdc{&6@ zl?+MEFK2-hpl>)85jSU$6W}6g3H&L-E#%4sR;OmZ0908)%Mi^fg%B!2voKNQsfTQE zL-jl8Il?SY6(ulA>K@Z5$BrX8o6&Vzk)#kt2Pi& zU?@@ELg$i1uo{m&2>}rZy@tx#YsFWKXZA!ZHr=XtbF<@;i?Zj1&Q*CG5dGii{;g0_Sf8tuDqy= zkp~~2d^}pzFmecAeBjC*>mM6JVnt=Ln(DflV7zea$ev3F7fY!;keWB#s(kFt)3bpe z6}?mRmwV^;JQ~~cXuRbyfs$C!M1@9X@{4hi^?}QaN*)=yT~cx7@Z{m?XXZ*;k$mO{ zo{B_yh%-{j*ooz^g1`rv2?cIZITzPb#Dy}nBI!&#e9KdAXfJ5veD$TT!pLRlcZX*7 z04?&?y1g9Wfq4GmsQ2)qzhK^9eal}x9hh&}daGe8zdRbxKNj^KgD%g!Cv*#5>5pCO z{C+2jRs2qIbn}AKUMT;)G)S;Z+g{mrJ6IL1zAqlUKN`3n30&U# z%2s}KC?32o8n_ScF$1Awro}5fJ$9qJs|S&dHvBF9NBpo8U-cCX)hyovajg=cK%6qu zHO10G#CXbqrz%ORy~5Kh?M}JEQ{)=$GdQJ?!2-lsEDS-eQip z9Vi;#9}CpS1C7w%bo%C@x+zb}k%0?t+ARE%KJ%~*f6&4ocHj)FFc`i3g6Qj^3^TP)rP-yx zkmGrertpcKlY>C{zNZ?#fTqb9c3i3hl@3V0AP_T{Mgt%+poQ(Albu5u&swDaueoat zZsWSny97Xj1W3F|kRV8aZ;+Iz2SrKLE3zor)PsJAwk&5nv?5TlWLb)qlwu=fExB$C z%Iz3Tnu;7JBihM~;7U_dGif8wG>O_KGj4yhSb`bAu+*Wa&h%dfisU$H`=j5vcOL+? zw39ZS=?;1CV)yRdyZ3qSd3p2sWdCILnxoDm?%F zYGiSs@5BJht#ouXM%OSIJ)@^YiVCCsnfB%iP|J-IX2V=Q_sN1XluuMp{lHY{mX16T zEuAO>gmhU^t$xuLYCy{cxf_3>mJ%+0|I;i?SS}oxD3$i14mG-6uk5JxHQ~Bed#IDr zC|7u3%C$zSvr${ruD0PxZ9k*usMVik!t!~2ZLEZPCramrDU}7gCIZPZ9V{>+ix$%3 zrZMk?dCXnVH>+6Rbg$y4N{7hLLwn58t}*Y%zXr|&vy04$Jvnhp z%t2%h39>kG8Hz=~`8!QCCD`r6zzH#cL`FFh4GLl7XwNYcT&*seVa=!p5B~3k5ELRQ zOaNYn_GD_~+2G6?^A^`?mC<)$c0%UAW7Lg990bF<_0*9UzY;yNJ=UtyBH(eUK+gp_ z?MgDzmR3*`uaC{IoqzmB@3oiTJ;~L?qsW)P?F~A+gdo%gx z&W?2sol!|{t^UYqFXUX5lB6bzc(x<<2pkp-fCMKG054K?GLZrKK_ls~#*0*$gF7Bb zOgV+xSFMVbwC{-6h};Al53sGUTaXxPNY29SwxlyOGk=c)+HXofrC&O8RsahxQ! zfZseS0dSSsxoY!f0qQE5^yI2kFAfZuax7;ifY4k8w+{p6o0PLK*s@$Hmyj{|tOClB zYnYODtF|T-f_^?ht@5`hDb$4Fwb~swXKMrTDxyyK*}r*f;{*5!YCv{`79CAk08*Z2 zEb4Q|lEcY8^F67ShthSsQr=xyD5lLzEgeaBGCcRlyy=}sXAj==Br39=;G9?Xv}Rj6 zuI_z%Z!&gsZMtRK^nt|gnZ7J2p#8J^-x^Bn{;;M#>u<~WSIPcW*H7HEq*rfW^zR^m zSKF*@Zug?UGaGEa^6c!hZ;d4Od{_gcAtiD0*n2O&`{K1Ti~jA|n)gb+3pL~LVU)J6;nLSl`m^oE3%f`g;%=VNclCnnl7}5aOjF(wS5nMN*!lWlb z$=Q~_kti;t|J^AuQ`B<3^qR7y6Wz69o(5&Wn+&wTh`CvqC+u}s&h_^wDc)v8H5Qcq z5BMenO{(iwy`I1c77c)NJ(NxEYV)m$+Pl{TPX1Nwy zAv10Km{(bPickb!r#bC6$dQ{G!`?jW3r_9HR=VDN=F&4+U;WgcC0~6UU~s^Uy|gv! zZ%Di}b3Wy3!zF#&lWEtj;*YvNMc%NC8x2*!8!bN*z3e-Hfa0KHCNXmaaxi zn5_+FYP;pyZk!NGT{aNT)-~pBNd2i$icOPqS!$N3AZ^2yp4pzF^p&2BJt*6Qn5PK& z`tbB&HNr#)INOucCy~Cg0r^*QyxJoBJ{lQ}0RM9kvw);?TozVKn_}q zA4ay#x^+6y4bcK?bwIT_putrVHNR$`EP-WJ3EpHd>Qq_-mV*Q|hc;V&NMR7k2B?Wj zo(4~-d8)BUUuiJ56@NLFNi((|7Njv4k-6FV zq}N#BdiskIa+Uu=@uW!-QsArSbsBJl(3-t(dj&DXeG}__yI%Y;l$!7rXU3GEQMoZT7na*VnP_cKv9{X)4qklLtRF5_IrEEDBppe^vEO$QRwzkkv` zVV63;aAbJY9&b1@?AN{OeKm&QO%qh1WSi8w(c^JKa$tv%4z4!RpU2bN)s%WH^%&=R z@=JOe^(^Wl7J*c~!V?dv>Gb&Gsuj}i*3+nG>fA*hs3ezhP3ppOHlGuVec2(^89!Oj zJAG>1sxhcUixiGl8_j~cE%0R3gjupqm@)EdCaMtnziU2iiPkFTrb+XZ0|2enU@z4f z=A^NvIL2->#IJ?3lnVI}2@LJwq!0}~<6V0kcL>T+S1r&X@EE%aHu!`tgZ0}qWj3PZ z$C_~6ysYx@bF7-M{BiGdSY23MiqZauB@&YXy9Aht3R{ziNQq1*K^HQk^y|2lv%zEZ z2-9SPK81&VaD^q3g0Rbs+GFOS*tjbAgE`yC*WmSOl*q)fSeHWQk<~hB7%4akI+vj! z@eeQ^j1A(&U~__J-`JJxO*gEWdNlq}!uGMFF5A|bayBcx>7@C+iodMLI^8qkOiQM& zORnom*R4v`u1;0=$j+Wb$&$wxALRS1AJJ!CLJ%tfdOOHi?VuWExB)b^Xt)7To|r6v z{Cfau%~b@o2B1wc6n>XO2;{`*g8%}NFRBC$VJ%BlK+G==AJEi)qc3^n`|Ib6D(JO9E-CegzK(E`n!&h_vULl8dn0pZy(p=z$;#F%OfFR|SdV<$10D9wW0eVTJ*h^b663Fkx52;}0( zDCLsIH{~3#G2l*SM8h4gWh)^dIWo3}1t3z{tKJ-(8k~NC04_GjO&ikHeL$&EOxrKLGV>7lVqlXI zl3B(USg-|XANJ+xFVo)97yqLrFL1-V7Q9_qe<0&uE&Ere{Qbnkf@`&uf7Mc`ITPxW zLw%{njq_)@u<$31?>DA5?@evmmkRDrP&O$?7!#MjX|C;h^I{FmU$k-ZEVZnP?^*=BPECE>o@G_ZKDA!9)u(J7 zw;i?WM0x$-qGN4#!{(F|f6Z^7f^)M>;~Kef&9psR>C99HA%;y=MzVp1OrT2+bjA07 zY-@OD>-@9whM^C^M{EWRP^Ps{ZtY98pfXb7&C^x4U4fYc*9U&kn%uVN+6*K2tF>>} z$~3&worCG{Af@nUV2wHp5rD z-|0>aUq1ZJ!z2TJSnhrJ1DEXG2MK1Ad&%v&Ybj~+O;>^U>8{SWD1&5grfd5`*Y>}g z%!Zq%t3C<0%srb9uTNBc>F525ah9H?gI@g-^cf{*|PCZ3vEKlAd;3rUyk>AJc0=HZ+BZkEwS z4DvVF-Vo^x>0A)cV6Iz!;7;eb#vn0bbc}0^4IPNah^e8&1deNL4WP;ke+KvrfbNv& zC~jOZLy4+lssn8tZisk1}O+a56&F{>{+apT7?3mK9cqfTv zX3(poYJC%m6w98cpE?dHB$X%&KUPYM>jr%eR}K0auF|Bi?7&q6_L|~DLVV2%Onzlc zfqr9({ZcjVBXQd)$n@YSoP2U0gDebkOmfGFJFwCsF7tUnd6DrD6L7-%Pj`FI)zhIj z1qE&9NeH^+s&j+r8Q7|j%y9H2IKzeU(4gWkoU2(Csk<|SEEtZQIK>}_Y>;Qop5-Pl zkgk&NBAAH6AcsV)%4-X(X81FZG;&BhZY)8>%mc(T6TV_de-0u)1F~0U8r3C>C_PN$ z&BSD|1%U0;iPZg)^i?E@sapg^rwoG9<-Q11sqFz8JZ@xw!87O0gxAaA_4B)Kx)#G* zSpSC3icV)T9X+PYMtXa>3iichqjwYt%}lF>k+5tgXh5D4qfU#TDug9tSu^~~=blr< z$S8%;x`)VQ7kM5aj`mu-+9!NUbuw1q3gbv)0uB!(*lX2L+ zNj9e|S1aJBS=#2K>r}cj_T~k9bJpp}INM}rTgtf(D8`q|r^{2$)+LRmujxsio%jB* z_D1aw8*enG*FKb5vn%Bri0>%`uq{oy+I8?+Y#|<8IJ7>aVHazYw$c=cihB(q8KXrD zd!CY%qtWVSBuHh@gVYv^;VB|U6z}Z&fA?Negkfv=4ypC?N{D4lBU&cNqpHETs2ofM zCHE={8!0P5$vut>T)xPrntjMZdV&%uqC-YjP^Zb+_+%9w{p$Gh%S4E4sN49JZo`u? z13+%=bCmkbd1Qgjr2$}WKW#NJRm7%abB|BIa=j%v{@&!flj+WFa`m>jZOK;6JV_d2 z>3ZIryfn#O0VL19(|Frg2M6BcS7NiVw67CPCk>>NbJ2!Th$5lBMzxZ(b(yMUDOZ&w zs!gp##vBBza-zWD8SHkRHSQo6*J3I$pbN&RQBfz$kAm*`1yhFZY79APl&PK{K(F;F zht{TLN73^dovJ5-7Mbbd;5hLk*%1{X;xIiZ;*d5LK|n$vQG#v}l8VCZPFM(F#<14hsZd})FWYlj%-=s3u>%Y}AY1Int7e@L& zQ2Wt-;V1{BT;^DZRzSuJr4gv{LQzrVC01V%&k4p3C+IsB7}cD3{y`RDyE0ly{XlaZ zr?Y`I4(K;%@KQ(M98gdHjorz!iJgnJor~Vi8@m*Nj!P~HIfw@rIFk1%gsN~W4-n4(yRAt-}KM($n-L>d#m2It1(^6=m zV4-IK%mJ=Yl{}jEuS-~N*LGxTd*s@lL}`AF;Pfeu?DDGwu$LUO4kbmeT-%Ej zodqdcu{OSW;L-swB~s4tZKp@3I!$}}7oGhdKRTTDKKYO5J_sj8IF*n)wu9p`^39Q3 zJ7wSQ56;DRr@T)VIN{6J73Av@U^p=Toe^?Y6zok^Z;xJjO$bvV**lfho!XoZnt+?mwl6_sohEv`1{q|Qu0pNfPIP>otf&=~Lh!dcb zdkAzAA%fvO1>loS{{!$zwhWaK*+Nr+bcovcJ9MT)Odg}36_kWQOwxemppbW}b|4EFgufvO$$lV6z9b4Y zjVglV+6~#(&g{C4SkSV85ESyV9Z*tf$W{jkN)q^zxDGWuU`p19?>3K%mi?kJm?XOe zf~m%T`S|qlndscEq<7|wT)jG9#&1~(gpnW=%`-=5%HfVQU(Rn-2n~%_4$U5#8&0mD zJ1hsG=fZE;g}R1(B|oo%SNObxpF36D#{t8`FWF2 zU6<#TmT#d#11m7!%I^^@LJAh7>W4z1dRODf@ks}zomlE3lRam&~n3ak52QwE)K|uNC#y6RKU-CTNUsQ z59I|!4*)XaT0YdQ;7n4i;YaAMJj+vtlr1U5$%kbNY-(G+h`uH^l)#t{wY6e_Z1D=;x`Z1d2h=5?HbQ~1RX~0X7 z!a3BsPmm@hfUh)Y2r!rcexrd`!*BQVqc4Y!kDeZt2otJ;NCt32&J*y)u~BG`7lD_l z<^dd8g&1iJ>g)til>pvNkQCfu=W{F{f^(sAXvVNQP*?%pSwYcQp`ifJ&_%v>M2fP~ z5=V@wf=cI(j+6Q8F+=bUDtXSTVz($D56r-m>>?$m^FWlNde8<3q>pg#mk1bJzT`p# zOmHM#e&|j>VeDTrS#sL9LOK%w5wMif5w*N90E)B(rY4b40S?)s<{>|p#G ztndWL05koP6XJx4!!a;-BLnWC=3qG6aFdUJ+Q(&bEidNAfv z$AD(H`aOK#*c-U_8^+ADdsC38!kxg&Q!mfdrX9^GM-K>S zQ8(f$4G%OIoC2PhI+3YrmaE9LyDAbledutLab{#Xa=B-^C+%*I@1j-(iz(~%C5|SZ zoCzm7aSg4n_#lKMp2UW!{glofui%7*W`R`1X`=dPZNGpMw7oc{*ux!%6(_TY)5eKD z5o7A4XV{^0hrnp0sjq{401{mRRa(ZAG8zX_b5!%`^m$5YFiY|4a;|8p(RK6nlA0ZYpfEu_lOXEt4WCn~h+`X}l{ z-#~JJ0l=!urEBD9JhwQt@sW zmXTaQ#A=GlsQUr>S1KW~pin}WJJAd4eAthrJ#8s>``p>(rd~zERAUGav(kbAXi!#6 zjfG!`lyu;#nV%Jg%yFACh()4GV8w3Y7CtnyF}t9MDQ73c8}v;^*z#qH-Cm6}#s2At z+YzhQzP!j_=VSVC5+mZntyLLoK(+?Bq#iI0oi{q6qhbyG-1;!@M^K^=BK|L6){NkF z+)0Rq&U8KvCt&DWGkpi^O2?360gDDY4}~5(>ggwA))=y0h`wh;{w#e3Jk@j7iv_Hg zDxoF}&P#>R)_J$gQ@~3h9}gC~K+;Mtnbpq>LtvR_i7q_}p#S-zse;vv@#i1L1irLl;GK);EFfLPyT{thezq|Y~rmR64A-&&00-%1ew zodnvCh;aN7(WOU3?r7l=kvIRBNmypOVf{1wTd?7?R8*bhZaU zt`tym0J4+TAwkY|^b8;qnf2M2L_HIrG8{GU)QPW1)P*G)1-WvjF$sg|F^Lv0iMXv? z;gZPoTsgKv(m1Kz}a z0#?&4;x^~Xj-NX76%&%wS_@nMa(Qb?b{~qUTPHZkK+B z#CTE|dle^GXGHNM!S<10|469%NGShEsQ5^5-w^_Lgw{Jk=#J3B!umS`{u+NFc9`{_v6MVnSbYjR>&xxHYjFPhg}5VLxcKOVY(5$+UQvgPi)iQ-T*iSfqD4U#i!!?WQ+e^87|%Ls1bLH@cnvX`ow*K z&OhrNsSwxP6)5~{z_-gHcHR{zyuZKVoLQ`izi?lm`2JVRB}9ph_XUdYpDcf|L~M=k zzb{aH|2a#iST|$8FCfZ4BbFiM*~{mq;b9x6b1w3~p4|D~?ss>~;dOAtBG!E7#W2`$ lmj=U*`zI@RTg71f@O^>e`;R#XMez|a{_>{+J7H7Ue*+v~#>fBw literal 0 HcmV?d00001 diff --git a/psets/9/finance/env/lib/python3.12/site-packages/click/__pycache__/decorators.cpython-312.pyc b/psets/9/finance/env/lib/python3.12/site-packages/click/__pycache__/decorators.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..b3a01c0ea3442bc60a1efdee6ec2bde1a7af5dfb GIT binary patch literal 23978 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 Mb{zSda+wVKzYH+kF8}}l literal 0 HcmV?d00001 diff --git a/psets/9/finance/env/lib/python3.12/site-packages/click/__pycache__/exceptions.cpython-312.pyc b/psets/9/finance/env/lib/python3.12/site-packages/click/__pycache__/exceptions.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..784ae2db470c3d5138a33d71a0e6b953d18486da GIT binary patch literal 14741 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 F{};dTXV(A# literal 0 HcmV?d00001 diff --git a/psets/9/finance/env/lib/python3.12/site-packages/click/__pycache__/formatting.cpython-312.pyc b/psets/9/finance/env/lib/python3.12/site-packages/click/__pycache__/formatting.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..f5bc5f5e44284bf5966632bcf07696ed58c991c1 GIT binary patch literal 14060 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 N+x7BODr4mEzX8Y~uJ!-` literal 0 HcmV?d00001 diff --git a/psets/9/finance/env/lib/python3.12/site-packages/click/__pycache__/globals.cpython-312.pyc b/psets/9/finance/env/lib/python3.12/site-packages/click/__pycache__/globals.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..342a89993b4c7e08321e1211ca75dd005514553c GIT binary patch literal 3125 zcmbVOO>7&-6`ox#C5og(NtPT}O`LI(CSZO@TS1VPXq&pS-6(PC)Yc(pQBcF3A-VE$ zcRMpAML}sL!+;y~klfru4+&5-RvjS8sqQJrr3lcA1UGQ9aR3+1#Wy+3AxIDHn^{t( z1O+WRz|P;kee>pf?|pCoHaeO_(Ehr5zP2%p&_C6p-(am<_mqLq6+{s=TvRe(G+nb1 zE5!`NjHN_h{NBiuS~gx9qA_Z@!;M5KVIUK+*tMQeX#~EUy7xtYMl*DrCN9Ny23p5EMt1s+GP9U9!no_(#JvO1B3KR2`JQCUG8__)%RCr4lTGgNIJ~!& z&|r(fqH95S1$EGdQQUxz55Za}N&NN8`GzO+Cx~QT-u9{E)$+D@=4d_;Op5&X@>Rzp zp3U;iYvo<1k`Fqv?t4$?j?LzUBiT~{u`iGs6M5Tp>sN>?azQ6NP-C)eH#r9z z%XVZlAB96x@N|{2Yv{H$+=a=1F`JKo2v^a^)whx5JgwGBpYF!hWK4A#=yt)Nj?ysv z5hhpA2$DM>Et#;jr%^*HymVVqNbPCVRBpW1`|=!m7|ET$mO4e$2UYVC#1Fk{{>aRpX+09#QKR<5xzg=*8Y3yT2}qVMNLOquO-B7NT1r-Y>Ad)N_LQNW!B z;f~u;R#%%YuKFC;nHw-JuxQ$Kb&;NGX4m~i+^##Y+i+@i376GM9LNODgoJB59=7Ym zt3d=~M+%Urla>QID@36J2k$~LLLisaY8HGPG(~+si6?QP!DPL#*vq<{u>F874kF%D zlFQ*1*bY}DlrmZ<;Ae72BmISdaMHk0z80`k#gJVJzQqOJ1ZB#yD2Z{4xJ`gu;Kicv z!7GsU{Jy)jvC5|dP5G%s9G6tw$af5|uac&#KXxz$-zt(!S^}6$i zgKypc=KWVITSt!F$jojgX1}_Xp85R?o2kdXKqd%&l9|3Wd3f`|AK#dq`*312{X#c} z#t&`}q4fB_wnvo2*FqJVi;rf}M&|f5r^uBjyFkou(Y9f%*|l{vV+F#T{TUvgXQn&a#Hz z0vuGrNI$?XYcXIB#b0VGLZFz9>C0;*!dT!3QSDHLK?hTqg1wzfJ`CHl@Q6w1qD!7$ zKYi1h+OnoTvJUE7g>l<=eZDIS)Wrraw~E%yRdjBkxKQ)$9lD1?V63NCjr}6zoVuK~ z@~3%4W*%{SEU4TIB~)LmpV1LJ_*K2BO~O@|)PQ5>tG&$LArQsKiWlW$qDL;U0uojv z$>@{V2gG<=QGyn6egA?I2sE5J`4y!7;OZ9~{i3*_3o)dsuD_1}5-?W-e-OIC#0{r` zpMAH*0B=CB+`9>X6y%;&vQIzgjcY8Rw_Un%` zldpAN?QA9v-A-k+JF>D#@Sj>!Fo>`yinud`8 zVl&g*YPOx|?cY_aH>_<0!_{BDv$C;rJ-d}Z@r7F76Th37HpZ0{4DU|-dFH*D>+@U3 zPIc9~d(e!e(=*T)ml61KTQkl AD*ylh literal 0 HcmV?d00001 diff --git a/psets/9/finance/env/lib/python3.12/site-packages/click/__pycache__/parser.cpython-312.pyc b/psets/9/finance/env/lib/python3.12/site-packages/click/__pycache__/parser.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..d26a06365c70cdfb68551653dbe8985b057bb8df GIT binary patch literal 21490 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 literal 0 HcmV?d00001 diff --git a/psets/9/finance/env/lib/python3.12/site-packages/click/__pycache__/shell_completion.cpython-312.pyc b/psets/9/finance/env/lib/python3.12/site-packages/click/__pycache__/shell_completion.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..ba344f65295038fbe37a6e8c57295fbacdcf43d3 GIT binary patch literal 22762 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 literal 0 HcmV?d00001 diff --git a/psets/9/finance/env/lib/python3.12/site-packages/click/__pycache__/testing.cpython-312.pyc b/psets/9/finance/env/lib/python3.12/site-packages/click/__pycache__/testing.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..bfe589411eb0b7b96627c196f88f255a3870dd82 GIT binary patch literal 24567 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�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 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/psets/9/finance/env/lib/python3.12/site-packages/click/_termui_impl.py b/psets/9/finance/env/lib/python3.12/site-packages/click/_termui_impl.py new file mode 100644 index 0000000..f744657 --- /dev/null +++ b/psets/9/finance/env/lib/python3.12/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/psets/9/finance/env/lib/python3.12/site-packages/click/_textwrap.py b/psets/9/finance/env/lib/python3.12/site-packages/click/_textwrap.py new file mode 100644 index 0000000..b47dcbd --- /dev/null +++ b/psets/9/finance/env/lib/python3.12/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/psets/9/finance/env/lib/python3.12/site-packages/click/_winconsole.py b/psets/9/finance/env/lib/python3.12/site-packages/click/_winconsole.py new file mode 100644 index 0000000..6b20df3 --- /dev/null +++ b/psets/9/finance/env/lib/python3.12/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/psets/9/finance/env/lib/python3.12/site-packages/click/core.py b/psets/9/finance/env/lib/python3.12/site-packages/click/core.py new file mode 100644 index 0000000..cc65e89 --- /dev/null +++ b/psets/9/finance/env/lib/python3.12/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/psets/9/finance/env/lib/python3.12/site-packages/click/decorators.py b/psets/9/finance/env/lib/python3.12/site-packages/click/decorators.py new file mode 100644 index 0000000..d9bba95 --- /dev/null +++ b/psets/9/finance/env/lib/python3.12/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/psets/9/finance/env/lib/python3.12/site-packages/click/exceptions.py b/psets/9/finance/env/lib/python3.12/site-packages/click/exceptions.py new file mode 100644 index 0000000..fe68a36 --- /dev/null +++ b/psets/9/finance/env/lib/python3.12/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/psets/9/finance/env/lib/python3.12/site-packages/click/formatting.py b/psets/9/finance/env/lib/python3.12/site-packages/click/formatting.py new file mode 100644 index 0000000..ddd2a2f --- /dev/null +++ b/psets/9/finance/env/lib/python3.12/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/psets/9/finance/env/lib/python3.12/site-packages/click/globals.py b/psets/9/finance/env/lib/python3.12/site-packages/click/globals.py new file mode 100644 index 0000000..480058f --- /dev/null +++ b/psets/9/finance/env/lib/python3.12/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/psets/9/finance/env/lib/python3.12/site-packages/click/parser.py b/psets/9/finance/env/lib/python3.12/site-packages/click/parser.py new file mode 100644 index 0000000..5fa7adf --- /dev/null +++ b/psets/9/finance/env/lib/python3.12/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/psets/9/finance/env/lib/python3.12/site-packages/click/py.typed b/psets/9/finance/env/lib/python3.12/site-packages/click/py.typed new file mode 100644 index 0000000..e69de29 diff --git a/psets/9/finance/env/lib/python3.12/site-packages/click/shell_completion.py b/psets/9/finance/env/lib/python3.12/site-packages/click/shell_completion.py new file mode 100644 index 0000000..dc9e00b --- /dev/null +++ b/psets/9/finance/env/lib/python3.12/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/psets/9/finance/env/lib/python3.12/site-packages/click/termui.py b/psets/9/finance/env/lib/python3.12/site-packages/click/termui.py new file mode 100644 index 0000000..db7a4b2 --- /dev/null +++ b/psets/9/finance/env/lib/python3.12/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/psets/9/finance/env/lib/python3.12/site-packages/click/testing.py b/psets/9/finance/env/lib/python3.12/site-packages/click/testing.py new file mode 100644 index 0000000..e0df0d2 --- /dev/null +++ b/psets/9/finance/env/lib/python3.12/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/psets/9/finance/env/lib/python3.12/site-packages/click/types.py b/psets/9/finance/env/lib/python3.12/site-packages/click/types.py new file mode 100644 index 0000000..2b1d179 --- /dev/null +++ b/psets/9/finance/env/lib/python3.12/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/psets/9/finance/env/lib/python3.12/site-packages/click/utils.py b/psets/9/finance/env/lib/python3.12/site-packages/click/utils.py new file mode 100644 index 0000000..d536434 --- /dev/null +++ b/psets/9/finance/env/lib/python3.12/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/psets/9/finance/env/lib/python3.12/site-packages/cs50-9.4.0.dist-info/INSTALLER b/psets/9/finance/env/lib/python3.12/site-packages/cs50-9.4.0.dist-info/INSTALLER new file mode 100644 index 0000000..a1b589e --- /dev/null +++ b/psets/9/finance/env/lib/python3.12/site-packages/cs50-9.4.0.dist-info/INSTALLER @@ -0,0 +1 @@ +pip diff --git a/psets/9/finance/env/lib/python3.12/site-packages/cs50-9.4.0.dist-info/LICENSE b/psets/9/finance/env/lib/python3.12/site-packages/cs50-9.4.0.dist-info/LICENSE new file mode 100644 index 0000000..f288702 --- /dev/null +++ b/psets/9/finance/env/lib/python3.12/site-packages/cs50-9.4.0.dist-info/LICENSE @@ -0,0 +1,674 @@ + GNU GENERAL PUBLIC LICENSE + Version 3, 29 June 2007 + + Copyright (C) 2007 Free Software Foundation, Inc. + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + Preamble + + The GNU General Public License is a free, copyleft license for +software and other kinds of works. + + The licenses for most software and other practical works are designed +to take away your freedom to share and change the works. By contrast, +the GNU General Public License is intended to guarantee your freedom to +share and change all versions of a program--to make sure it remains free +software for all its users. We, the Free Software Foundation, use the +GNU General Public License for most of our software; it applies also to +any other work released this way by its authors. You can apply it to +your programs, too. + + When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +them if you wish), that you receive source code or can get it if you +want it, that you can change the software or use pieces of it in new +free programs, and that you know you can do these things. + + To protect your rights, we need to prevent others from denying you +these rights or asking you to surrender the rights. Therefore, you have +certain responsibilities if you distribute copies of the software, or if +you modify it: responsibilities to respect the freedom of others. + + For example, if you distribute copies of such a program, whether +gratis or for a fee, you must pass on to the recipients the same +freedoms that you received. You must make sure that they, too, receive +or can get the source code. And you must show them these terms so they +know their rights. + + Developers that use the GNU GPL protect your rights with two steps: +(1) assert copyright on the software, and (2) offer you this License +giving you legal permission to copy, distribute and/or modify it. + + For the developers' and authors' protection, the GPL clearly explains +that there is no warranty for this free software. For both users' and +authors' sake, the GPL requires that modified versions be marked as +changed, so that their problems will not be attributed erroneously to +authors of previous versions. + + Some devices are designed to deny users access to install or run +modified versions of the software inside them, although the manufacturer +can do so. This is fundamentally incompatible with the aim of +protecting users' freedom to change the software. The systematic +pattern of such abuse occurs in the area of products for individuals to +use, which is precisely where it is most unacceptable. Therefore, we +have designed this version of the GPL to prohibit the practice for those +products. If such problems arise substantially in other domains, we +stand ready to extend this provision to those domains in future versions +of the GPL, as needed to protect the freedom of users. + + Finally, every program is threatened constantly by software patents. +States should not allow patents to restrict development and use of +software on general-purpose computers, but in those that do, we wish to +avoid the special danger that patents applied to a free program could +make it effectively proprietary. To prevent this, the GPL assures that +patents cannot be used to render the program non-free. + + The precise terms and conditions for copying, distribution and +modification follow. + + TERMS AND CONDITIONS + + 0. Definitions. + + "This License" refers to version 3 of the GNU General Public License. + + "Copyright" also means copyright-like laws that apply to other kinds of +works, such as semiconductor masks. + + "The Program" refers to any copyrightable work licensed under this +License. Each licensee is addressed as "you". "Licensees" and +"recipients" may be individuals or organizations. + + To "modify" a work means to copy from or adapt all or part of the work +in a fashion requiring copyright permission, other than the making of an +exact copy. The resulting work is called a "modified version" of the +earlier work or a work "based on" the earlier work. + + A "covered work" means either the unmodified Program or a work based +on the Program. + + To "propagate" a work means to do anything with it that, without +permission, would make you directly or secondarily liable for +infringement under applicable copyright law, except executing it on a +computer or modifying a private copy. Propagation includes copying, +distribution (with or without modification), making available to the +public, and in some countries other activities as well. + + To "convey" a work means any kind of propagation that enables other +parties to make or receive copies. Mere interaction with a user through +a computer network, with no transfer of a copy, is not conveying. + + An interactive user interface displays "Appropriate Legal Notices" +to the extent that it includes a convenient and prominently visible +feature that (1) displays an appropriate copyright notice, and (2) +tells the user that there is no warranty for the work (except to the +extent that warranties are provided), that licensees may convey the +work under this License, and how to view a copy of this License. If +the interface presents a list of user commands or options, such as a +menu, a prominent item in the list meets this criterion. + + 1. Source Code. + + The "source code" for a work means the preferred form of the work +for making modifications to it. "Object code" means any non-source +form of a work. + + A "Standard Interface" means an interface that either is an official +standard defined by a recognized standards body, or, in the case of +interfaces specified for a particular programming language, one that +is widely used among developers working in that language. + + The "System Libraries" of an executable work include anything, other +than the work as a whole, that (a) is included in the normal form of +packaging a Major Component, but which is not part of that Major +Component, and (b) serves only to enable use of the work with that +Major Component, or to implement a Standard Interface for which an +implementation is available to the public in source code form. A +"Major Component", in this context, means a major essential component +(kernel, window system, and so on) of the specific operating system +(if any) on which the executable work runs, or a compiler used to +produce the work, or an object code interpreter used to run it. + + The "Corresponding Source" for a work in object code form means all +the source code needed to generate, install, and (for an executable +work) run the object code and to modify the work, including scripts to +control those activities. However, it does not include the work's +System Libraries, or general-purpose tools or generally available free +programs which are used unmodified in performing those activities but +which are not part of the work. For example, Corresponding Source +includes interface definition files associated with source files for +the work, and the source code for shared libraries and dynamically +linked subprograms that the work is specifically designed to require, +such as by intimate data communication or control flow between those +subprograms and other parts of the work. + + The Corresponding Source need not include anything that users +can regenerate automatically from other parts of the Corresponding +Source. + + The Corresponding Source for a work in source code form is that +same work. + + 2. Basic Permissions. + + All rights granted under this License are granted for the term of +copyright on the Program, and are irrevocable provided the stated +conditions are met. This License explicitly affirms your unlimited +permission to run the unmodified Program. The output from running a +covered work is covered by this License only if the output, given its +content, constitutes a covered work. This License acknowledges your +rights of fair use or other equivalent, as provided by copyright law. + + You may make, run and propagate covered works that you do not +convey, without conditions so long as your license otherwise remains +in force. You may convey covered works to others for the sole purpose +of having them make modifications exclusively for you, or provide you +with facilities for running those works, provided that you comply with +the terms of this License in conveying all material for which you do +not control copyright. Those thus making or running the covered works +for you must do so exclusively on your behalf, under your direction +and control, on terms that prohibit them from making any copies of +your copyrighted material outside their relationship with you. + + Conveying under any other circumstances is permitted solely under +the conditions stated below. Sublicensing is not allowed; section 10 +makes it unnecessary. + + 3. Protecting Users' Legal Rights From Anti-Circumvention Law. + + No covered work shall be deemed part of an effective technological +measure under any applicable law fulfilling obligations under article +11 of the WIPO copyright treaty adopted on 20 December 1996, or +similar laws prohibiting or restricting circumvention of such +measures. + + When you convey a covered work, you waive any legal power to forbid +circumvention of technological measures to the extent such circumvention +is effected by exercising rights under this License with respect to +the covered work, and you disclaim any intention to limit operation or +modification of the work as a means of enforcing, against the work's +users, your or third parties' legal rights to forbid circumvention of +technological measures. + + 4. Conveying Verbatim Copies. + + You may convey verbatim copies of the Program's source code as you +receive it, in any medium, provided that you conspicuously and +appropriately publish on each copy an appropriate copyright notice; +keep intact all notices stating that this License and any +non-permissive terms added in accord with section 7 apply to the code; +keep intact all notices of the absence of any warranty; and give all +recipients a copy of this License along with the Program. + + You may charge any price or no price for each copy that you convey, +and you may offer support or warranty protection for a fee. + + 5. Conveying Modified Source Versions. + + You may convey a work based on the Program, or the modifications to +produce it from the Program, in the form of source code under the +terms of section 4, provided that you also meet all of these conditions: + + a) The work must carry prominent notices stating that you modified + it, and giving a relevant date. + + b) The work must carry prominent notices stating that it is + released under this License and any conditions added under section + 7. This requirement modifies the requirement in section 4 to + "keep intact all notices". + + c) You must license the entire work, as a whole, under this + License to anyone who comes into possession of a copy. This + License will therefore apply, along with any applicable section 7 + additional terms, to the whole of the work, and all its parts, + regardless of how they are packaged. This License gives no + permission to license the work in any other way, but it does not + invalidate such permission if you have separately received it. + + d) If the work has interactive user interfaces, each must display + Appropriate Legal Notices; however, if the Program has interactive + interfaces that do not display Appropriate Legal Notices, your + work need not make them do so. + + A compilation of a covered work with other separate and independent +works, which are not by their nature extensions of the covered work, +and which are not combined with it such as to form a larger program, +in or on a volume of a storage or distribution medium, is called an +"aggregate" if the compilation and its resulting copyright are not +used to limit the access or legal rights of the compilation's users +beyond what the individual works permit. Inclusion of a covered work +in an aggregate does not cause this License to apply to the other +parts of the aggregate. + + 6. Conveying Non-Source Forms. + + You may convey a covered work in object code form under the terms +of sections 4 and 5, provided that you also convey the +machine-readable Corresponding Source under the terms of this License, +in one of these ways: + + a) Convey the object code in, or embodied in, a physical product + (including a physical distribution medium), accompanied by the + Corresponding Source fixed on a durable physical medium + customarily used for software interchange. + + b) Convey the object code in, or embodied in, a physical product + (including a physical distribution medium), accompanied by a + written offer, valid for at least three years and valid for as + long as you offer spare parts or customer support for that product + model, to give anyone who possesses the object code either (1) a + copy of the Corresponding Source for all the software in the + product that is covered by this License, on a durable physical + medium customarily used for software interchange, for a price no + more than your reasonable cost of physically performing this + conveying of source, or (2) access to copy the + Corresponding Source from a network server at no charge. + + c) Convey individual copies of the object code with a copy of the + written offer to provide the Corresponding Source. This + alternative is allowed only occasionally and noncommercially, and + only if you received the object code with such an offer, in accord + with subsection 6b. + + d) Convey the object code by offering access from a designated + place (gratis or for a charge), and offer equivalent access to the + Corresponding Source in the same way through the same place at no + further charge. You need not require recipients to copy the + Corresponding Source along with the object code. If the place to + copy the object code is a network server, the Corresponding Source + may be on a different server (operated by you or a third party) + that supports equivalent copying facilities, provided you maintain + clear directions next to the object code saying where to find the + Corresponding Source. Regardless of what server hosts the + Corresponding Source, you remain obligated to ensure that it is + available for as long as needed to satisfy these requirements. + + e) Convey the object code using peer-to-peer transmission, provided + you inform other peers where the object code and Corresponding + Source of the work are being offered to the general public at no + charge under subsection 6d. + + A separable portion of the object code, whose source code is excluded +from the Corresponding Source as a System Library, need not be +included in conveying the object code work. + + A "User Product" is either (1) a "consumer product", which means any +tangible personal property which is normally used for personal, family, +or household purposes, or (2) anything designed or sold for incorporation +into a dwelling. In determining whether a product is a consumer product, +doubtful cases shall be resolved in favor of coverage. For a particular +product received by a particular user, "normally used" refers to a +typical or common use of that class of product, regardless of the status +of the particular user or of the way in which the particular user +actually uses, or expects or is expected to use, the product. A product +is a consumer product regardless of whether the product has substantial +commercial, industrial or non-consumer uses, unless such uses represent +the only significant mode of use of the product. + + "Installation Information" for a User Product means any methods, +procedures, authorization keys, or other information required to install +and execute modified versions of a covered work in that User Product from +a modified version of its Corresponding Source. The information must +suffice to ensure that the continued functioning of the modified object +code is in no case prevented or interfered with solely because +modification has been made. + + If you convey an object code work under this section in, or with, or +specifically for use in, a User Product, and the conveying occurs as +part of a transaction in which the right of possession and use of the +User Product is transferred to the recipient in perpetuity or for a +fixed term (regardless of how the transaction is characterized), the +Corresponding Source conveyed under this section must be accompanied +by the Installation Information. But this requirement does not apply +if neither you nor any third party retains the ability to install +modified object code on the User Product (for example, the work has +been installed in ROM). + + The requirement to provide Installation Information does not include a +requirement to continue to provide support service, warranty, or updates +for a work that has been modified or installed by the recipient, or for +the User Product in which it has been modified or installed. Access to a +network may be denied when the modification itself materially and +adversely affects the operation of the network or violates the rules and +protocols for communication across the network. + + Corresponding Source conveyed, and Installation Information provided, +in accord with this section must be in a format that is publicly +documented (and with an implementation available to the public in +source code form), and must require no special password or key for +unpacking, reading or copying. + + 7. Additional Terms. + + "Additional permissions" are terms that supplement the terms of this +License by making exceptions from one or more of its conditions. +Additional permissions that are applicable to the entire Program shall +be treated as though they were included in this License, to the extent +that they are valid under applicable law. If additional permissions +apply only to part of the Program, that part may be used separately +under those permissions, but the entire Program remains governed by +this License without regard to the additional permissions. + + When you convey a copy of a covered work, you may at your option +remove any additional permissions from that copy, or from any part of +it. (Additional permissions may be written to require their own +removal in certain cases when you modify the work.) You may place +additional permissions on material, added by you to a covered work, +for which you have or can give appropriate copyright permission. + + Notwithstanding any other provision of this License, for material you +add to a covered work, you may (if authorized by the copyright holders of +that material) supplement the terms of this License with terms: + + a) Disclaiming warranty or limiting liability differently from the + terms of sections 15 and 16 of this License; or + + b) Requiring preservation of specified reasonable legal notices or + author attributions in that material or in the Appropriate Legal + Notices displayed by works containing it; or + + c) Prohibiting misrepresentation of the origin of that material, or + requiring that modified versions of such material be marked in + reasonable ways as different from the original version; or + + d) Limiting the use for publicity purposes of names of licensors or + authors of the material; or + + e) Declining to grant rights under trademark law for use of some + trade names, trademarks, or service marks; or + + f) Requiring indemnification of licensors and authors of that + material by anyone who conveys the material (or modified versions of + it) with contractual assumptions of liability to the recipient, for + any liability that these contractual assumptions directly impose on + those licensors and authors. + + All other non-permissive additional terms are considered "further +restrictions" within the meaning of section 10. If the Program as you +received it, or any part of it, contains a notice stating that it is +governed by this License along with a term that is a further +restriction, you may remove that term. If a license document contains +a further restriction but permits relicensing or conveying under this +License, you may add to a covered work material governed by the terms +of that license document, provided that the further restriction does +not survive such relicensing or conveying. + + If you add terms to a covered work in accord with this section, you +must place, in the relevant source files, a statement of the +additional terms that apply to those files, or a notice indicating +where to find the applicable terms. + + Additional terms, permissive or non-permissive, may be stated in the +form of a separately written license, or stated as exceptions; +the above requirements apply either way. + + 8. Termination. + + You may not propagate or modify a covered work except as expressly +provided under this License. Any attempt otherwise to propagate or +modify it is void, and will automatically terminate your rights under +this License (including any patent licenses granted under the third +paragraph of section 11). + + However, if you cease all violation of this License, then your +license from a particular copyright holder is reinstated (a) +provisionally, unless and until the copyright holder explicitly and +finally terminates your license, and (b) permanently, if the copyright +holder fails to notify you of the violation by some reasonable means +prior to 60 days after the cessation. + + Moreover, your license from a particular copyright holder is +reinstated permanently if the copyright holder notifies you of the +violation by some reasonable means, this is the first time you have +received notice of violation of this License (for any work) from that +copyright holder, and you cure the violation prior to 30 days after +your receipt of the notice. + + Termination of your rights under this section does not terminate the +licenses of parties who have received copies or rights from you under +this License. If your rights have been terminated and not permanently +reinstated, you do not qualify to receive new licenses for the same +material under section 10. + + 9. Acceptance Not Required for Having Copies. + + You are not required to accept this License in order to receive or +run a copy of the Program. Ancillary propagation of a covered work +occurring solely as a consequence of using peer-to-peer transmission +to receive a copy likewise does not require acceptance. However, +nothing other than this License grants you permission to propagate or +modify any covered work. These actions infringe copyright if you do +not accept this License. Therefore, by modifying or propagating a +covered work, you indicate your acceptance of this License to do so. + + 10. Automatic Licensing of Downstream Recipients. + + Each time you convey a covered work, the recipient automatically +receives a license from the original licensors, to run, modify and +propagate that work, subject to this License. You are not responsible +for enforcing compliance by third parties with this License. + + An "entity transaction" is a transaction transferring control of an +organization, or substantially all assets of one, or subdividing an +organization, or merging organizations. If propagation of a covered +work results from an entity transaction, each party to that +transaction who receives a copy of the work also receives whatever +licenses to the work the party's predecessor in interest had or could +give under the previous paragraph, plus a right to possession of the +Corresponding Source of the work from the predecessor in interest, if +the predecessor has it or can get it with reasonable efforts. + + You may not impose any further restrictions on the exercise of the +rights granted or affirmed under this License. For example, you may +not impose a license fee, royalty, or other charge for exercise of +rights granted under this License, and you may not initiate litigation +(including a cross-claim or counterclaim in a lawsuit) alleging that +any patent claim is infringed by making, using, selling, offering for +sale, or importing the Program or any portion of it. + + 11. Patents. + + A "contributor" is a copyright holder who authorizes use under this +License of the Program or a work on which the Program is based. The +work thus licensed is called the contributor's "contributor version". + + A contributor's "essential patent claims" are all patent claims +owned or controlled by the contributor, whether already acquired or +hereafter acquired, that would be infringed by some manner, permitted +by this License, of making, using, or selling its contributor version, +but do not include claims that would be infringed only as a +consequence of further modification of the contributor version. For +purposes of this definition, "control" includes the right to grant +patent sublicenses in a manner consistent with the requirements of +this License. + + Each contributor grants you a non-exclusive, worldwide, royalty-free +patent license under the contributor's essential patent claims, to +make, use, sell, offer for sale, import and otherwise run, modify and +propagate the contents of its contributor version. + + In the following three paragraphs, a "patent license" is any express +agreement or commitment, however denominated, not to enforce a patent +(such as an express permission to practice a patent or covenant not to +sue for patent infringement). To "grant" such a patent license to a +party means to make such an agreement or commitment not to enforce a +patent against the party. + + If you convey a covered work, knowingly relying on a patent license, +and the Corresponding Source of the work is not available for anyone +to copy, free of charge and under the terms of this License, through a +publicly available network server or other readily accessible means, +then you must either (1) cause the Corresponding Source to be so +available, or (2) arrange to deprive yourself of the benefit of the +patent license for this particular work, or (3) arrange, in a manner +consistent with the requirements of this License, to extend the patent +license to downstream recipients. "Knowingly relying" means you have +actual knowledge that, but for the patent license, your conveying the +covered work in a country, or your recipient's use of the covered work +in a country, would infringe one or more identifiable patents in that +country that you have reason to believe are valid. + + If, pursuant to or in connection with a single transaction or +arrangement, you convey, or propagate by procuring conveyance of, a +covered work, and grant a patent license to some of the parties +receiving the covered work authorizing them to use, propagate, modify +or convey a specific copy of the covered work, then the patent license +you grant is automatically extended to all recipients of the covered +work and works based on it. + + A patent license is "discriminatory" if it does not include within +the scope of its coverage, prohibits the exercise of, or is +conditioned on the non-exercise of one or more of the rights that are +specifically granted under this License. You may not convey a covered +work if you are a party to an arrangement with a third party that is +in the business of distributing software, under which you make payment +to the third party based on the extent of your activity of conveying +the work, and under which the third party grants, to any of the +parties who would receive the covered work from you, a discriminatory +patent license (a) in connection with copies of the covered work +conveyed by you (or copies made from those copies), or (b) primarily +for and in connection with specific products or compilations that +contain the covered work, unless you entered into that arrangement, +or that patent license was granted, prior to 28 March 2007. + + Nothing in this License shall be construed as excluding or limiting +any implied license or other defenses to infringement that may +otherwise be available to you under applicable patent law. + + 12. No Surrender of Others' Freedom. + + If conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot convey a +covered work so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you may +not convey it at all. For example, if you agree to terms that obligate you +to collect a royalty for further conveying from those to whom you convey +the Program, the only way you could satisfy both those terms and this +License would be to refrain entirely from conveying the Program. + + 13. Use with the GNU Affero General Public License. + + Notwithstanding any other provision of this License, you have +permission to link or combine any covered work with a work licensed +under version 3 of the GNU Affero General Public License into a single +combined work, and to convey the resulting work. The terms of this +License will continue to apply to the part which is the covered work, +but the special requirements of the GNU Affero General Public License, +section 13, concerning interaction through a network will apply to the +combination as such. + + 14. Revised Versions of this License. + + The Free Software Foundation may publish revised and/or new versions of +the GNU General Public License from time to time. Such new versions will +be similar in spirit to the present version, but may differ in detail to +address new problems or concerns. + + Each version is given a distinguishing version number. If the +Program specifies that a certain numbered version of the GNU General +Public License "or any later version" applies to it, you have the +option of following the terms and conditions either of that numbered +version or of any later version published by the Free Software +Foundation. If the Program does not specify a version number of the +GNU General Public License, you may choose any version ever published +by the Free Software Foundation. + + If the Program specifies that a proxy can decide which future +versions of the GNU General Public License can be used, that proxy's +public statement of acceptance of a version permanently authorizes you +to choose that version for the Program. + + Later license versions may give you additional or different +permissions. However, no additional obligations are imposed on any +author or copyright holder as a result of your choosing to follow a +later version. + + 15. Disclaimer of Warranty. + + THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY +APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT +HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY +OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, +THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM +IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF +ALL NECESSARY SERVICING, REPAIR OR CORRECTION. + + 16. Limitation of Liability. + + IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS +THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY +GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE +USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF +DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD +PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), +EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF +SUCH DAMAGES. + + 17. Interpretation of Sections 15 and 16. + + If the disclaimer of warranty and limitation of liability provided +above cannot be given local legal effect according to their terms, +reviewing courts shall apply local law that most closely approximates +an absolute waiver of all civil liability in connection with the +Program, unless a warranty or assumption of liability accompanies a +copy of the Program in return for a fee. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Programs + + If you develop a new program, and you want it to be of the greatest +possible use to the public, the best way to achieve this is to make it +free software which everyone can redistribute and change under these terms. + + To do so, attach the following notices to the program. It is safest +to attach them to the start of each source file to most effectively +state the exclusion of warranty; and each file should have at least +the "copyright" line and a pointer to where the full notice is found. + + + Copyright (C) + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . + +Also add information on how to contact you by electronic and paper mail. + + If the program does terminal interaction, make it output a short +notice like this when it starts in an interactive mode: + + Copyright (C) + This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'. + This is free software, and you are welcome to redistribute it + under certain conditions; type `show c' for details. + +The hypothetical commands `show w' and `show c' should show the appropriate +parts of the General Public License. Of course, your program's commands +might be different; for a GUI interface, you would use an "about box". + + You should also get your employer (if you work as a programmer) or school, +if any, to sign a "copyright disclaimer" for the program, if necessary. +For more information on this, and how to apply and follow the GNU GPL, see +. + + The GNU General Public License does not permit incorporating your program +into proprietary programs. If your program is a subroutine library, you +may consider it more useful to permit linking proprietary applications with +the library. If this is what you want to do, use the GNU Lesser General +Public License instead of this License. But first, please read +. diff --git a/psets/9/finance/env/lib/python3.12/site-packages/cs50-9.4.0.dist-info/METADATA b/psets/9/finance/env/lib/python3.12/site-packages/cs50-9.4.0.dist-info/METADATA new file mode 100644 index 0000000..81f71ff --- /dev/null +++ b/psets/9/finance/env/lib/python3.12/site-packages/cs50-9.4.0.dist-info/METADATA @@ -0,0 +1,22 @@ +Metadata-Version: 2.1 +Name: cs50 +Version: 9.4.0 +Summary: CS50 library for Python +Home-page: https://github.com/cs50/python-cs50 +Author: CS50 +Author-email: sysadmins@cs50.harvard.edu +License: GPLv3 +Keywords: cs50 +Classifier: Intended Audience :: Developers +Classifier: Programming Language :: Python +Classifier: Programming Language :: Python :: 3 +Classifier: Topic :: Software Development :: Libraries :: Python Modules +Description-Content-Type: text/markdown +License-File: LICENSE +Requires-Dist: Flask >=1.0 +Requires-Dist: packaging +Requires-Dist: SQLAlchemy <3,>=2 +Requires-Dist: sqlparse +Requires-Dist: termcolor +Requires-Dist: wheel + diff --git a/psets/9/finance/env/lib/python3.12/site-packages/cs50-9.4.0.dist-info/RECORD b/psets/9/finance/env/lib/python3.12/site-packages/cs50-9.4.0.dist-info/RECORD new file mode 100644 index 0000000..fe11118 --- /dev/null +++ b/psets/9/finance/env/lib/python3.12/site-packages/cs50-9.4.0.dist-info/RECORD @@ -0,0 +1,15 @@ +cs50-9.4.0.dist-info/INSTALLER,sha256=zuuue4knoyJ-UwPPXg8fezS7VCrXJQrAP7zeNuwvFQg,4 +cs50-9.4.0.dist-info/LICENSE,sha256=OXLcl0T2SZ8Pmy2_dmlvKuetivmyPd5m1q-Gyd-zaYY,35149 +cs50-9.4.0.dist-info/METADATA,sha256=kOpbrvmDkkbWPYKdG2C6yPX_QrS2mJSMNILxGDSguMk,638 +cs50-9.4.0.dist-info/RECORD,, +cs50-9.4.0.dist-info/REQUESTED,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0 +cs50-9.4.0.dist-info/WHEEL,sha256=oiQVh_5PnQM0E3gPdiz09WCNmwiHDMaGer_elqB3coM,92 +cs50-9.4.0.dist-info/top_level.txt,sha256=UBEotoWNbmA_aSszS4gokveyc8I6ZIfELJxG43wm4_U,5 +cs50/__init__.py,sha256=PF5DXfA5rPy7HxvLmQqnOeGRiJCv4vOWHccgUcYtrz0,344 +cs50/__pycache__/__init__.cpython-312.pyc,, +cs50/__pycache__/cs50.cpython-312.pyc,, +cs50/__pycache__/flask.cpython-312.pyc,, +cs50/__pycache__/sql.cpython-312.pyc,, +cs50/cs50.py,sha256=2TivkQafao5FB6RazhF2NVVYq9L-qyx8-89QXhClvSI,4371 +cs50/flask.py,sha256=i5olysPOt1MVxyZTrifhVRq2NK2Vl2idr94nPP05Qwc,1201 +cs50/sql.py,sha256=DLV1w34YYhi3k7DZeYxBTsxdOiFa7xG9SXE-6HF2mX0,23304 diff --git a/psets/9/finance/env/lib/python3.12/site-packages/cs50-9.4.0.dist-info/REQUESTED b/psets/9/finance/env/lib/python3.12/site-packages/cs50-9.4.0.dist-info/REQUESTED new file mode 100644 index 0000000..e69de29 diff --git a/psets/9/finance/env/lib/python3.12/site-packages/cs50-9.4.0.dist-info/WHEEL b/psets/9/finance/env/lib/python3.12/site-packages/cs50-9.4.0.dist-info/WHEEL new file mode 100644 index 0000000..98c0d20 --- /dev/null +++ b/psets/9/finance/env/lib/python3.12/site-packages/cs50-9.4.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/psets/9/finance/env/lib/python3.12/site-packages/cs50-9.4.0.dist-info/top_level.txt b/psets/9/finance/env/lib/python3.12/site-packages/cs50-9.4.0.dist-info/top_level.txt new file mode 100644 index 0000000..eb7688b --- /dev/null +++ b/psets/9/finance/env/lib/python3.12/site-packages/cs50-9.4.0.dist-info/top_level.txt @@ -0,0 +1 @@ +cs50 diff --git a/psets/9/finance/env/lib/python3.12/site-packages/cs50/__init__.py b/psets/9/finance/env/lib/python3.12/site-packages/cs50/__init__.py new file mode 100644 index 0000000..7dd4e17 --- /dev/null +++ b/psets/9/finance/env/lib/python3.12/site-packages/cs50/__init__.py @@ -0,0 +1,21 @@ +import logging +import os +import sys + + +# Disable cs50 logger by default +logging.getLogger("cs50").disabled = True + +# Import cs50_* +from .cs50 import get_char, get_float, get_int, get_string + +try: + from .cs50 import get_long +except ImportError: + pass + +# Hook into flask importing +from . import flask + +# Wrap SQLAlchemy +from .sql import SQL diff --git a/psets/9/finance/env/lib/python3.12/site-packages/cs50/__pycache__/__init__.cpython-312.pyc b/psets/9/finance/env/lib/python3.12/site-packages/cs50/__pycache__/__init__.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..75864fa968970fe4cae7a983dbd3697e221cbd0c GIT binary patch literal 620 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 0 and re.search(r"^[+-]?\d*(?:\.\d*)?$", s): + try: + return float(s) + except (OverflowError, ValueError): + pass + + +def get_int(prompt): + """ + Read a line of text from standard input and return the equivalent int; + if text does not represent an int, user is prompted to retry. If line + can't be read, return None. + """ + while True: + s = get_string(prompt) + if s is None: + return None + if re.search(r"^[+-]?\d+$", s): + try: + return int(s, 10) + except ValueError: + pass + + +def get_string(prompt): + """ + Read a line of text from standard input and return it as a string, + sans trailing line ending. Supports CR (\r), LF (\n), and CRLF (\r\n) + as line endings. If user inputs only a line ending, returns "", not None. + Returns None upon error or no input whatsoever (i.e., just EOF). + """ + if not isinstance(prompt, str): + raise TypeError("prompt must be of type str") + try: + return input(prompt) + except EOFError: + return None diff --git a/psets/9/finance/env/lib/python3.12/site-packages/cs50/flask.py b/psets/9/finance/env/lib/python3.12/site-packages/cs50/flask.py new file mode 100644 index 0000000..6e38971 --- /dev/null +++ b/psets/9/finance/env/lib/python3.12/site-packages/cs50/flask.py @@ -0,0 +1,47 @@ +import os +import pkgutil +import sys + + +def _wrap_flask(f): + if f is None: + return + + from packaging.version import Version, InvalidVersion + from .cs50 import _formatException + + try: + if Version(f.__version__) < Version("1.0"): + return + except InvalidVersion: + return + + if os.getenv("CS50_IDE_TYPE") == "online": + from werkzeug.middleware.proxy_fix import ProxyFix + + _flask_init_before = f.Flask.__init__ + + def _flask_init_after(self, *args, **kwargs): + _flask_init_before(self, *args, **kwargs) + self.wsgi_app = ProxyFix( + self.wsgi_app, x_proto=1 + ) # For HTTPS-to-HTTP proxy + + f.Flask.__init__ = _flask_init_after + + +# If Flask was imported before cs50 +if "flask" in sys.modules: + _wrap_flask(sys.modules["flask"]) + +# If Flask wasn't imported +else: + flask_loader = pkgutil.get_loader("flask") + if flask_loader: + _exec_module_before = flask_loader.exec_module + + def _exec_module_after(*args, **kwargs): + _exec_module_before(*args, **kwargs) + _wrap_flask(sys.modules["flask"]) + + flask_loader.exec_module = _exec_module_after diff --git a/psets/9/finance/env/lib/python3.12/site-packages/cs50/sql.py b/psets/9/finance/env/lib/python3.12/site-packages/cs50/sql.py new file mode 100644 index 0000000..81905bc --- /dev/null +++ b/psets/9/finance/env/lib/python3.12/site-packages/cs50/sql.py @@ -0,0 +1,656 @@ +import sys +import threading + +# Thread-local data +_data = threading.local() + + +def _enable_logging(f): + """Enable logging of SQL statements when Flask is in use.""" + + import logging + import functools + import os + + @functools.wraps(f) + def decorator(*args, **kwargs): + # Infer whether Flask is installed + try: + import flask + except ModuleNotFoundError: + return f(*args, **kwargs) + + # Enable logging in development mode + disabled = logging.getLogger("cs50").disabled + if flask.current_app and os.getenv("FLASK_ENV") == "development": + logging.getLogger("cs50").disabled = False + try: + return f(*args, **kwargs) + finally: + logging.getLogger("cs50").disabled = disabled + + return decorator + + +class SQL(object): + """Wrap SQLAlchemy to provide a simple SQL API.""" + + def __init__(self, url, **kwargs): + """ + Create instance of sqlalchemy.engine.Engine. + + URL should be a string that indicates database dialect and connection arguments. + + http://docs.sqlalchemy.org/en/latest/core/engines.html#sqlalchemy.create_engine + http://docs.sqlalchemy.org/en/latest/dialects/index.html + """ + + # Lazily import + import logging + import os + import re + import sqlalchemy + import sqlalchemy.orm + import threading + + # Temporary fix for missing sqlite3 module on the buildpack stack + try: + import sqlite3 + except: + pass + + # Require that file already exist for SQLite + matches = re.search(r"^sqlite:///(.+)$", url) + if matches: + if not os.path.exists(matches.group(1)): + raise RuntimeError("does not exist: {}".format(matches.group(1))) + if not os.path.isfile(matches.group(1)): + raise RuntimeError("not a file: {}".format(matches.group(1))) + + # Create engine, disabling SQLAlchemy's own autocommit mode raising exception if back end's module not installed; + # without isolation_level, PostgreSQL warns with "there is already a transaction in progress" for our own BEGIN and + # "there is no transaction in progress" for our own COMMIT + self._engine = sqlalchemy.create_engine(url, **kwargs).execution_options( + autocommit=False, isolation_level="AUTOCOMMIT", no_parameters=True + ) + + # Avoid doubly escaping percent signs, since no_parameters=True anyway + # https://github.com/cs50/python-cs50/issues/171 + self._engine.dialect.identifier_preparer._double_percents = False + + # Get logger + self._logger = logging.getLogger("cs50") + + # Listener for connections + def connect(dbapi_connection, connection_record): + # Enable foreign key constraints + try: + if isinstance( + dbapi_connection, sqlite3.Connection + ): # If back end is sqlite + cursor = dbapi_connection.cursor() + cursor.execute("PRAGMA foreign_keys=ON") + cursor.close() + except: + # Temporary fix for missing sqlite3 module on the buildpack stack + pass + + # Register listener + sqlalchemy.event.listen(self._engine, "connect", connect) + + # Autocommit by default + self._autocommit = True + + # Test database + disabled = self._logger.disabled + self._logger.disabled = True + try: + connection = self._engine.connect() + connection.execute(sqlalchemy.text("SELECT 1")) + connection.close() + except sqlalchemy.exc.OperationalError as e: + e = RuntimeError(_parse_exception(e)) + e.__cause__ = None + raise e + finally: + self._logger.disabled = disabled + + def __del__(self): + """Disconnect from database.""" + self._disconnect() + + def _disconnect(self): + """Close database connection.""" + if hasattr(_data, self._name()): + getattr(_data, self._name()).close() + delattr(_data, self._name()) + + def _name(self): + """Return object's hash as a str.""" + return str(hash(self)) + + @_enable_logging + def execute(self, sql, *args, **kwargs): + """Execute a SQL statement.""" + + # Lazily import + import decimal + import re + import sqlalchemy + import sqlparse + import termcolor + import warnings + + # Parse statement, stripping comments and then leading/trailing whitespace + statements = sqlparse.parse(sqlparse.format(sql, strip_comments=True).strip()) + + # Allow only one statement at a time, since SQLite doesn't support multiple + # https://docs.python.org/3/library/sqlite3.html#sqlite3.Cursor.execute + if len(statements) > 1: + raise RuntimeError("too many statements at once") + elif len(statements) == 0: + raise RuntimeError("missing statement") + + # Ensure named and positional parameters are mutually exclusive + if len(args) > 0 and len(kwargs) > 0: + raise RuntimeError("cannot pass both positional and named parameters") + + # Infer command from flattened statement to a single string separated by spaces + full_statement = " ".join( + str(token) + for token in statements[0].tokens + if token.ttype + in [ + sqlparse.tokens.Keyword, + sqlparse.tokens.Keyword.DDL, + sqlparse.tokens.Keyword.DML, + ] + ) + full_statement = full_statement.upper() + + # Set of possible commands + commands = { + "BEGIN", + "CREATE VIEW", + "DELETE", + "INSERT", + "SELECT", + "START", + "UPDATE", + "VACUUM", + } + + # Check if the full_statement starts with any command + command = next( + (cmd for cmd in commands if full_statement.startswith(cmd)), None + ) + + # Flatten statement + tokens = list(statements[0].flatten()) + + # Validate paramstyle + placeholders = {} + paramstyle = None + for index, token in enumerate(tokens): + # If token is a placeholder + if token.ttype == sqlparse.tokens.Name.Placeholder: + # Determine paramstyle, name + _paramstyle, name = _parse_placeholder(token) + + # Remember paramstyle + if not paramstyle: + paramstyle = _paramstyle + + # Ensure paramstyle is consistent + elif _paramstyle != paramstyle: + raise RuntimeError("inconsistent paramstyle") + + # Remember placeholder's index, name + placeholders[index] = name + + # If no placeholders + if not paramstyle: + # Error-check like qmark if args + if args: + paramstyle = "qmark" + + # Error-check like named if kwargs + elif kwargs: + paramstyle = "named" + + # In case of errors + _placeholders = ", ".join([str(tokens[index]) for index in placeholders]) + _args = ", ".join([str(self._escape(arg)) for arg in args]) + + # qmark + if paramstyle == "qmark": + # Validate number of placeholders + if len(placeholders) != len(args): + if len(placeholders) < len(args): + raise RuntimeError( + "fewer placeholders ({}) than values ({})".format( + _placeholders, _args + ) + ) + else: + raise RuntimeError( + "more placeholders ({}) than values ({})".format( + _placeholders, _args + ) + ) + + # Escape values + for i, index in enumerate(placeholders.keys()): + tokens[index] = self._escape(args[i]) + + # numeric + elif paramstyle == "numeric": + # Escape values + for index, i in placeholders.items(): + if i >= len(args): + raise RuntimeError( + "missing value for placeholder (:{})".format(i + 1, len(args)) + ) + tokens[index] = self._escape(args[i]) + + # Check if any values unused + indices = set(range(len(args))) - set(placeholders.values()) + if indices: + raise RuntimeError( + "unused {} ({})".format( + "value" if len(indices) == 1 else "values", + ", ".join( + [str(self._escape(args[index])) for index in indices] + ), + ) + ) + + # named + elif paramstyle == "named": + # Escape values + for index, name in placeholders.items(): + if name not in kwargs: + raise RuntimeError( + "missing value for placeholder (:{})".format(name) + ) + tokens[index] = self._escape(kwargs[name]) + + # Check if any keys unused + keys = kwargs.keys() - placeholders.values() + if keys: + raise RuntimeError("unused values ({})".format(", ".join(keys))) + + # format + elif paramstyle == "format": + # Validate number of placeholders + if len(placeholders) != len(args): + if len(placeholders) < len(args): + raise RuntimeError( + "fewer placeholders ({}) than values ({})".format( + _placeholders, _args + ) + ) + else: + raise RuntimeError( + "more placeholders ({}) than values ({})".format( + _placeholders, _args + ) + ) + + # Escape values + for i, index in enumerate(placeholders.keys()): + tokens[index] = self._escape(args[i]) + + # pyformat + elif paramstyle == "pyformat": + # Escape values + for index, name in placeholders.items(): + if name not in kwargs: + raise RuntimeError( + "missing value for placeholder (%{}s)".format(name) + ) + tokens[index] = self._escape(kwargs[name]) + + # Check if any keys unused + keys = kwargs.keys() - placeholders.values() + if keys: + raise RuntimeError( + "unused {} ({})".format( + "value" if len(keys) == 1 else "values", ", ".join(keys) + ) + ) + + # For SQL statements where a colon is required verbatim, as within an inline string, use a backslash to escape + # https://docs.sqlalchemy.org/en/13/core/sqlelement.html?highlight=text#sqlalchemy.sql.expression.text + for index, token in enumerate(tokens): + # In string literal + # https://www.sqlite.org/lang_keywords.html + if token.ttype in [ + sqlparse.tokens.Literal.String, + sqlparse.tokens.Literal.String.Single, + ]: + token.value = re.sub(r"(^'|\s+):", r"\1\:", token.value) + + # In identifier + # https://www.sqlite.org/lang_keywords.html + elif token.ttype == sqlparse.tokens.Literal.String.Symbol: + token.value = re.sub(r'(^"|\s+):', r"\1\:", token.value) + + # Join tokens into statement + statement = "".join([str(token) for token in tokens]) + + # If no connection yet + if not hasattr(_data, self._name()): + # Connect to database + setattr(_data, self._name(), self._engine.connect()) + + # Use this connection + connection = getattr(_data, self._name()) + + # Disconnect if/when a Flask app is torn down + try: + import flask + + assert flask.current_app + + def teardown_appcontext(exception): + self._disconnect() + + if teardown_appcontext not in flask.current_app.teardown_appcontext_funcs: + flask.current_app.teardown_appcontext(teardown_appcontext) + except (ModuleNotFoundError, AssertionError): + pass + + # Catch SQLAlchemy warnings + with warnings.catch_warnings(): + # Raise exceptions for warnings + warnings.simplefilter("error") + + # Prepare, execute statement + try: + # Join tokens into statement, abbreviating binary data as + _statement = "".join( + [ + str(bytes) + if token.ttype == sqlparse.tokens.Other + else str(token) + for token in tokens + ] + ) + + # Check for start of transaction + if command in ["BEGIN", "START", "VACUUM"]: # cannot VACUUM from within a transaction + self._autocommit = False + + # Execute statement + if self._autocommit: + connection.execute(sqlalchemy.text("BEGIN")) + result = connection.execute(sqlalchemy.text(statement)) + if self._autocommit: + connection.execute(sqlalchemy.text("COMMIT")) + + # Check for end of transaction + if command in ["COMMIT", "ROLLBACK", "VACUUM"]: # cannot VACUUM from within a transaction + self._autocommit = True + + # Return value + ret = True + + # If SELECT, return result set as list of dict objects + if command == "SELECT": + # Coerce types + rows = [dict(row) for row in result.mappings().all()] + for row in rows: + for column in row: + # Coerce decimal.Decimal objects to float objects + # https://groups.google.com/d/msg/sqlalchemy/0qXMYJvq8SA/oqtvMD9Uw-kJ + if isinstance(row[column], decimal.Decimal): + row[column] = float(row[column]) + + # Coerce memoryview objects (as from PostgreSQL's bytea columns) to bytes + elif isinstance(row[column], memoryview): + row[column] = bytes(row[column]) + + # Rows to be returned + ret = rows + + # If INSERT, return primary key value for a newly inserted row (or None if none) + elif command == "INSERT": + # If PostgreSQL + if self._engine.url.get_backend_name() == "postgresql": + # Return LASTVAL() or NULL, avoiding + # "(psycopg2.errors.ObjectNotInPrerequisiteState) lastval is not yet defined in this session", + # a la https://stackoverflow.com/a/24186770/5156190; + # cf. https://www.psycopg.org/docs/errors.html re 55000 + result = connection.execute( + sqlalchemy.text( + """ + CREATE OR REPLACE FUNCTION _LASTVAL() + RETURNS integer LANGUAGE plpgsql + AS $$ + BEGIN + BEGIN + RETURN (SELECT LASTVAL()); + EXCEPTION + WHEN SQLSTATE '55000' THEN RETURN NULL; + END; + END $$; + SELECT _LASTVAL(); + """ + ) + ) + ret = result.first()[0] + + # If not PostgreSQL + else: + ret = result.lastrowid if result.rowcount == 1 else None + + # If DELETE or UPDATE, return number of rows matched + elif command in ["DELETE", "UPDATE"]: + ret = result.rowcount + + # If CREATE VIEW, return True + elif command == "CREATE VIEW": + ret = True + + # If constraint violated + except sqlalchemy.exc.IntegrityError as e: + if self._autocommit: + connection.execute(sqlalchemy.text("ROLLBACK")) + self._logger.error(termcolor.colored(_statement, "red")) + e = ValueError(e.orig) + e.__cause__ = None + raise e + + # If user error + except ( + sqlalchemy.exc.OperationalError, + sqlalchemy.exc.ProgrammingError, + ) as e: + self._disconnect() + self._logger.error(termcolor.colored(_statement, "red")) + e = RuntimeError(e.orig) + e.__cause__ = None + raise e + + # Return value + else: + self._logger.info(termcolor.colored(_statement, "green")) + if self._autocommit: # Don't stay connected unnecessarily + self._disconnect() + return ret + + def _escape(self, value): + """ + Escapes value using engine's conversion function. + + https://docs.sqlalchemy.org/en/latest/core/type_api.html#sqlalchemy.types.TypeEngine.literal_processor + """ + + # Lazily import + import sqlparse + + def __escape(value): + # Lazily import + import datetime + import sqlalchemy + + # bool + if isinstance(value, bool): + return sqlparse.sql.Token( + sqlparse.tokens.Number, + sqlalchemy.types.Boolean().literal_processor(self._engine.dialect)( + value + ), + ) + + # bytes + elif isinstance(value, bytes): + if self._engine.url.get_backend_name() in ["mysql", "sqlite"]: + return sqlparse.sql.Token( + sqlparse.tokens.Other, f"x'{value.hex()}'" + ) # https://dev.mysql.com/doc/refman/8.0/en/hexadecimal-literals.html + elif self._engine.url.get_backend_name() == "postgresql": + return sqlparse.sql.Token( + sqlparse.tokens.Other, f"'\\x{value.hex()}'" + ) # https://dba.stackexchange.com/a/203359 + else: + raise RuntimeError("unsupported value: {}".format(value)) + + # datetime.datetime + elif isinstance(value, datetime.datetime): + return sqlparse.sql.Token( + sqlparse.tokens.String, + sqlalchemy.types.String().literal_processor(self._engine.dialect)( + value.strftime("%Y-%m-%d %H:%M:%S") + ), + ) + + # datetime.date + elif isinstance(value, datetime.date): + return sqlparse.sql.Token( + sqlparse.tokens.String, + sqlalchemy.types.String().literal_processor(self._engine.dialect)( + value.strftime("%Y-%m-%d") + ), + ) + + # datetime.time + elif isinstance(value, datetime.time): + return sqlparse.sql.Token( + sqlparse.tokens.String, + sqlalchemy.types.String().literal_processor(self._engine.dialect)( + value.strftime("%H:%M:%S") + ), + ) + + # float + elif isinstance(value, float): + return sqlparse.sql.Token( + sqlparse.tokens.Number, + sqlalchemy.types.Float().literal_processor(self._engine.dialect)( + value + ), + ) + + # int + elif isinstance(value, int): + return sqlparse.sql.Token( + sqlparse.tokens.Number, + sqlalchemy.types.Integer().literal_processor(self._engine.dialect)( + value + ), + ) + + # str + elif isinstance(value, str): + return sqlparse.sql.Token( + sqlparse.tokens.String, + sqlalchemy.types.String().literal_processor(self._engine.dialect)( + value + ), + ) + + # None + elif value is None: + return sqlparse.sql.Token(sqlparse.tokens.Keyword, sqlalchemy.null()) + + # Unsupported value + else: + raise RuntimeError("unsupported value: {}".format(value)) + + # Escape value(s), separating with commas as needed + if isinstance(value, (list, tuple)): + return sqlparse.sql.TokenList( + sqlparse.parse(", ".join([str(__escape(v)) for v in value])) + ) + else: + return __escape(value) + + +def _parse_exception(e): + """Parses an exception, returns its message.""" + + # Lazily import + import re + + # MySQL + matches = re.search( + r"^\(_mysql_exceptions\.OperationalError\) \(\d+, \"(.+)\"\)$", str(e) + ) + if matches: + return matches.group(1) + + # PostgreSQL + matches = re.search(r"^\(psycopg2\.OperationalError\) (.+)$", str(e)) + if matches: + return matches.group(1) + + # SQLite + matches = re.search(r"^\(sqlite3\.OperationalError\) (.+)$", str(e)) + if matches: + return matches.group(1) + + # Default + return str(e) + + +def _parse_placeholder(token): + """Infers paramstyle, name from sqlparse.tokens.Name.Placeholder.""" + + # Lazily load + import re + import sqlparse + + # Validate token + if ( + not isinstance(token, sqlparse.sql.Token) + or token.ttype != sqlparse.tokens.Name.Placeholder + ): + raise TypeError() + + # qmark + if token.value == "?": + return "qmark", None + + # numeric + matches = re.search(r"^:([1-9]\d*)$", token.value) + if matches: + return "numeric", int(matches.group(1)) - 1 + + # named + matches = re.search(r"^:([a-zA-Z]\w*)$", token.value) + if matches: + return "named", matches.group(1) + + # format + if token.value == "%s": + return "format", None + + # pyformat + matches = re.search(r"%\((\w+)\)s$", token.value) + if matches: + return "pyformat", matches.group(1) + + # Invalid + raise RuntimeError("{}: invalid placeholder".format(token.value)) diff --git a/psets/9/finance/env/lib/python3.12/site-packages/flask-3.1.0.dist-info/INSTALLER b/psets/9/finance/env/lib/python3.12/site-packages/flask-3.1.0.dist-info/INSTALLER new file mode 100644 index 0000000..a1b589e --- /dev/null +++ b/psets/9/finance/env/lib/python3.12/site-packages/flask-3.1.0.dist-info/INSTALLER @@ -0,0 +1 @@ +pip diff --git a/psets/9/finance/env/lib/python3.12/site-packages/flask-3.1.0.dist-info/LICENSE.txt b/psets/9/finance/env/lib/python3.12/site-packages/flask-3.1.0.dist-info/LICENSE.txt new file mode 100644 index 0000000..9d227a0 --- /dev/null +++ b/psets/9/finance/env/lib/python3.12/site-packages/flask-3.1.0.dist-info/LICENSE.txt @@ -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/psets/9/finance/env/lib/python3.12/site-packages/flask-3.1.0.dist-info/METADATA b/psets/9/finance/env/lib/python3.12/site-packages/flask-3.1.0.dist-info/METADATA new file mode 100644 index 0000000..c49ceb9 --- /dev/null +++ b/psets/9/finance/env/lib/python3.12/site-packages/flask-3.1.0.dist-info/METADATA @@ -0,0 +1,81 @@ +Metadata-Version: 2.3 +Name: Flask +Version: 3.1.0 +Summary: A simple framework for building complex web applications. +Maintainer-email: Pallets +Requires-Python: >=3.9 +Description-Content-Type: text/markdown +Classifier: Development Status :: 5 - Production/Stable +Classifier: Environment :: Web Environment +Classifier: Framework :: Flask +Classifier: Intended Audience :: Developers +Classifier: License :: OSI Approved :: BSD License +Classifier: Operating System :: OS Independent +Classifier: Programming Language :: Python +Classifier: Topic :: Internet :: WWW/HTTP :: Dynamic Content +Classifier: Topic :: Internet :: WWW/HTTP :: WSGI +Classifier: Topic :: Internet :: WWW/HTTP :: WSGI :: Application +Classifier: Topic :: Software Development :: Libraries :: Application Frameworks +Classifier: Typing :: Typed +Requires-Dist: Werkzeug>=3.1 +Requires-Dist: Jinja2>=3.1.2 +Requires-Dist: itsdangerous>=2.2 +Requires-Dist: click>=8.1.3 +Requires-Dist: blinker>=1.9 +Requires-Dist: importlib-metadata>=3.6; python_version < '3.10' +Requires-Dist: asgiref>=3.2 ; extra == "async" +Requires-Dist: python-dotenv ; extra == "dotenv" +Project-URL: Changes, https://flask.palletsprojects.com/changes/ +Project-URL: Chat, https://discord.gg/pallets +Project-URL: Documentation, https://flask.palletsprojects.com/ +Project-URL: Donate, https://palletsprojects.com/donate +Project-URL: Source, https://github.com/pallets/flask/ +Provides-Extra: async +Provides-Extra: dotenv + +# Flask + +Flask is a lightweight [WSGI][] web application framework. It is designed +to make getting started quick and easy, with the ability to scale up to +complex applications. It began as a simple wrapper around [Werkzeug][] +and [Jinja][], and has become one of the most popular Python web +application frameworks. + +Flask offers suggestions, but doesn't enforce any dependencies or +project layout. It is up to the developer to choose the tools and +libraries they want to use. There are many extensions provided by the +community that make adding new functionality easy. + +[WSGI]: https://wsgi.readthedocs.io/ +[Werkzeug]: https://werkzeug.palletsprojects.com/ +[Jinja]: https://jinja.palletsprojects.com/ + + +## A Simple Example + +```python +# save this as app.py +from flask import Flask + +app = Flask(__name__) + +@app.route("/") +def hello(): + return "Hello, World!" +``` + +``` +$ flask run + * Running on http://127.0.0.1:5000/ (Press CTRL+C to quit) +``` + + +## Donate + +The Pallets organization develops and supports Flask and the libraries +it uses. In order to grow the community of contributors and users, and +allow the maintainers to devote more time to the projects, [please +donate today][]. + +[please donate today]: https://palletsprojects.com/donate + diff --git a/psets/9/finance/env/lib/python3.12/site-packages/flask-3.1.0.dist-info/RECORD b/psets/9/finance/env/lib/python3.12/site-packages/flask-3.1.0.dist-info/RECORD new file mode 100644 index 0000000..b1c079b --- /dev/null +++ b/psets/9/finance/env/lib/python3.12/site-packages/flask-3.1.0.dist-info/RECORD @@ -0,0 +1,57 @@ +../../../bin/flask,sha256=zaXbHAv5SP4TfgPSmg7YfZyaRULwN2y92HQvttDryzQ,245 +flask-3.1.0.dist-info/INSTALLER,sha256=zuuue4knoyJ-UwPPXg8fezS7VCrXJQrAP7zeNuwvFQg,4 +flask-3.1.0.dist-info/LICENSE.txt,sha256=SJqOEQhQntmKN7uYPhHg9-HTHwvY-Zp5yESOf_N9B-o,1475 +flask-3.1.0.dist-info/METADATA,sha256=Wvf66xwUclGRu89cNcvErpaMf1rMgcxeqIkTc4EmD90,2718 +flask-3.1.0.dist-info/RECORD,, +flask-3.1.0.dist-info/WHEEL,sha256=CpUCUxeHQbRN5UGRQHYRJorO5Af-Qy_fHMctcQ8DSGI,82 +flask-3.1.0.dist-info/entry_points.txt,sha256=bBP7hTOS5fz9zLtC7sPofBZAlMkEvBxu7KqS6l5lvc4,40 +flask/__init__.py,sha256=6xMqdVA0FIQ2U1KVaGX3lzNCdXPzoHPaa0hvQCNcfSk,2625 +flask/__main__.py,sha256=bYt9eEaoRQWdejEHFD8REx9jxVEdZptECFsV7F49Ink,30 +flask/__pycache__/__init__.cpython-312.pyc,, +flask/__pycache__/__main__.cpython-312.pyc,, +flask/__pycache__/app.cpython-312.pyc,, +flask/__pycache__/blueprints.cpython-312.pyc,, +flask/__pycache__/cli.cpython-312.pyc,, +flask/__pycache__/config.cpython-312.pyc,, +flask/__pycache__/ctx.cpython-312.pyc,, +flask/__pycache__/debughelpers.cpython-312.pyc,, +flask/__pycache__/globals.cpython-312.pyc,, +flask/__pycache__/helpers.cpython-312.pyc,, +flask/__pycache__/logging.cpython-312.pyc,, +flask/__pycache__/sessions.cpython-312.pyc,, +flask/__pycache__/signals.cpython-312.pyc,, +flask/__pycache__/templating.cpython-312.pyc,, +flask/__pycache__/testing.cpython-312.pyc,, +flask/__pycache__/typing.cpython-312.pyc,, +flask/__pycache__/views.cpython-312.pyc,, +flask/__pycache__/wrappers.cpython-312.pyc,, +flask/app.py,sha256=GE7QOE_N9THDjuzKx0gUI9aF4hLh0xwBDa7hLVsjy-o,61725 +flask/blueprints.py,sha256=p5QE2lY18GItbdr_RKRpZ8Do17g0PvQGIgZkSUDhX2k,4541 +flask/cli.py,sha256=XdmkBD74SnT0jrt2gqyHrE9oXGdWlcdTrJQR-i5aApY,37093 +flask/config.py,sha256=PiqF0DPam6HW0FH4CH1hpXTBe30NSzjPEOwrz1b6kt0,13219 +flask/ctx.py,sha256=4atDhJJ_cpV1VMq4qsfU4E_61M1oN93jlS2H9gjrl58,15120 +flask/debughelpers.py,sha256=PGIDhStW_efRjpaa3zHIpo-htStJOR41Ip3OJWPYBwo,6080 +flask/globals.py,sha256=XdQZmStBmPIs8t93tjx6pO7Bm3gobAaONWkFcUHaGas,1713 +flask/helpers.py,sha256=7njmzkFJvrPSQudsgONsgQzaGrGppeBINevKgWescPk,23521 +flask/json/__init__.py,sha256=hLNR898paqoefdeAhraa5wyJy-bmRB2k2dV4EgVy2Z8,5602 +flask/json/__pycache__/__init__.cpython-312.pyc,, +flask/json/__pycache__/provider.cpython-312.pyc,, +flask/json/__pycache__/tag.cpython-312.pyc,, +flask/json/provider.py,sha256=5imEzY5HjV2HoUVrQbJLqXCzMNpZXfD0Y1XqdLV2XBA,7672 +flask/json/tag.py,sha256=DhaNwuIOhdt2R74oOC9Y4Z8ZprxFYiRb5dUP5byyINw,9281 +flask/logging.py,sha256=8sM3WMTubi1cBb2c_lPkWpN0J8dMAqrgKRYLLi1dCVI,2377 +flask/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0 +flask/sansio/README.md,sha256=-0X1tECnilmz1cogx-YhNw5d7guK7GKrq_DEV2OzlU0,228 +flask/sansio/__pycache__/app.cpython-312.pyc,, +flask/sansio/__pycache__/blueprints.cpython-312.pyc,, +flask/sansio/__pycache__/scaffold.cpython-312.pyc,, +flask/sansio/app.py,sha256=Wj9NVGtiR1jvkZ9gSFd91usUlM8H0g06aPVz2sMh4bw,38116 +flask/sansio/blueprints.py,sha256=Tqe-7EkZ-tbWchm8iDoCfD848f0_3nLv6NNjeIPvHwM,24637 +flask/sansio/scaffold.py,sha256=q6wM4Y4aYMGGN_Litsj3PYKpBS3Zvut0xhDmpBEHFdo,30387 +flask/sessions.py,sha256=pImSFQIDCPtV-XSI8ttAyTTbvtRMkhDeqJ8VPZZUaf0,15430 +flask/signals.py,sha256=V7lMUww7CqgJ2ThUBn1PiatZtQanOyt7OZpu2GZI-34,750 +flask/templating.py,sha256=2TcXLT85Asflm2W9WOSFxKCmYn5e49w_Jkg9-NaaJWo,7537 +flask/testing.py,sha256=5Dxg6VZ0ZPhjwG9ReUl4TrhvkjBYvgIzV949jkY0jIU,10100 +flask/typing.py,sha256=b7mMBIeAoOcAI_vFzzhfOm7KeZ_n868SIMw6xpX5KYQ,3166 +flask/views.py,sha256=xzJx6oJqGElThtEghZN7ZQGMw5TDFyuRxUkecwRuAoA,6962 +flask/wrappers.py,sha256=jUkv4mVek2Iq4hwxd4RvqrIMb69Bv0PElDgWLmd5ORo,9406 diff --git a/psets/9/finance/env/lib/python3.12/site-packages/flask-3.1.0.dist-info/WHEEL b/psets/9/finance/env/lib/python3.12/site-packages/flask-3.1.0.dist-info/WHEEL new file mode 100644 index 0000000..e3c6fee --- /dev/null +++ b/psets/9/finance/env/lib/python3.12/site-packages/flask-3.1.0.dist-info/WHEEL @@ -0,0 +1,4 @@ +Wheel-Version: 1.0 +Generator: flit 3.10.1 +Root-Is-Purelib: true +Tag: py3-none-any diff --git a/psets/9/finance/env/lib/python3.12/site-packages/flask-3.1.0.dist-info/entry_points.txt b/psets/9/finance/env/lib/python3.12/site-packages/flask-3.1.0.dist-info/entry_points.txt new file mode 100644 index 0000000..eec6733 --- /dev/null +++ b/psets/9/finance/env/lib/python3.12/site-packages/flask-3.1.0.dist-info/entry_points.txt @@ -0,0 +1,3 @@ +[console_scripts] +flask=flask.cli:main + diff --git a/psets/9/finance/env/lib/python3.12/site-packages/flask/__init__.py b/psets/9/finance/env/lib/python3.12/site-packages/flask/__init__.py new file mode 100644 index 0000000..e86eb43 --- /dev/null +++ b/psets/9/finance/env/lib/python3.12/site-packages/flask/__init__.py @@ -0,0 +1,60 @@ +from __future__ import annotations + +import typing as t + +from . import json as json +from .app import Flask as Flask +from .blueprints import Blueprint as Blueprint +from .config import Config as Config +from .ctx import after_this_request as after_this_request +from .ctx import copy_current_request_context as copy_current_request_context +from .ctx import has_app_context as has_app_context +from .ctx import has_request_context as has_request_context +from .globals import current_app as current_app +from .globals import g as g +from .globals import request as request +from .globals import session as session +from .helpers import abort as abort +from .helpers import flash as flash +from .helpers import get_flashed_messages as get_flashed_messages +from .helpers import get_template_attribute as get_template_attribute +from .helpers import make_response as make_response +from .helpers import redirect as redirect +from .helpers import send_file as send_file +from .helpers import send_from_directory as send_from_directory +from .helpers import stream_with_context as stream_with_context +from .helpers import url_for as url_for +from .json import jsonify as jsonify +from .signals import appcontext_popped as appcontext_popped +from .signals import appcontext_pushed as appcontext_pushed +from .signals import appcontext_tearing_down as appcontext_tearing_down +from .signals import before_render_template as before_render_template +from .signals import got_request_exception as got_request_exception +from .signals import message_flashed as message_flashed +from .signals import request_finished as request_finished +from .signals import request_started as request_started +from .signals import request_tearing_down as request_tearing_down +from .signals import template_rendered as template_rendered +from .templating import render_template as render_template +from .templating import render_template_string as render_template_string +from .templating import stream_template as stream_template +from .templating import stream_template_string as stream_template_string +from .wrappers import Request as Request +from .wrappers import Response as Response + + +def __getattr__(name: str) -> t.Any: + if name == "__version__": + import importlib.metadata + import warnings + + warnings.warn( + "The '__version__' attribute is deprecated and will be removed in" + " Flask 3.1. Use feature detection or" + " 'importlib.metadata.version(\"flask\")' instead.", + DeprecationWarning, + stacklevel=2, + ) + return importlib.metadata.version("flask") + + raise AttributeError(name) diff --git a/psets/9/finance/env/lib/python3.12/site-packages/flask/__main__.py b/psets/9/finance/env/lib/python3.12/site-packages/flask/__main__.py new file mode 100644 index 0000000..4e28416 --- /dev/null +++ b/psets/9/finance/env/lib/python3.12/site-packages/flask/__main__.py @@ -0,0 +1,3 @@ +from .cli import main + +main() diff --git a/psets/9/finance/env/lib/python3.12/site-packages/flask/__pycache__/__init__.cpython-312.pyc b/psets/9/finance/env/lib/python3.12/site-packages/flask/__pycache__/__init__.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..9d1ea3382f8510aed8bd9841c1fd89713af20c33 GIT binary patch literal 2479 zcmZXWNpBoQ6vwM)>sc}$d%Q2P+v|AjWIC}EAd3K#1h^!J1cXwTR(rZ;rtRLSuCe3D zkq`n2P8>KS9|07;2L~<*IV9?+C8WS1H%sw}6YrI$6U($(|M}Iws;gdAy(-Ng<#Lh0 z^ZWkY_6E=^EF@3r2$VO63Ly`PMJ&Z3u0jb;)zUD|AKjJn$-AmAn9ahMtkU=$v&Mv>|y3Sf{$=8t^%KPVzGFd3s)Q z-C1+j>AK_<;0yEu@EL3My9~X!m#UwAjVVx9qLS%(zA%ODd*Q9ukPc{OwnE>7-|VN3 z8Eyjk@aXqZ88%o;?i*TXTplym~E;X?(-RNoDxhAa#raB#Ecrq8kSYzso}01UO6Fl2#Q zh6@eNHVeTYL0>R8a7@7rQwVNvb_Ii)vTJTLh$0MNEzrnwX4#xIvEM?-Jj-a=4ps~v z6}ayjM-6ib`)SlC=S=KUw*f?b*FS zD~T5hlM5NgP-2}3Vjvl|7lv#M-=7R=i0?Feyh~gTT#g{b{NMDHVlq;^8KH`=rFBz z%&uu~GgPxf&4NS7nvl4bW_p&kYdem%$u!Pfe+N9<)8vWO)*I&=+Ls~ITFew(&fr4< zc?=_IKG$lt8^CFC?9GPDglU<=Z1e(Ip2H)vJy)+mXCZ8~)p(7O!HyIm6Pnu&+hNYp zDci2AQT6{_MfqKmd$6%#ltGHB*LzXJ@LwHOMfqglNbQXr^=%|)@doE`TGCO*GhG%H z-VVXnAd(QbL({Z>@9M56^y{z~p5F8=7*KD97tiTI$V8}L(jl2mugP@g?dUL7J=hZ+ z--DG|(?eUZvjNNo?*v`WST_tveqk7mU=KG2ZV6m@*qAFYUIPcd1M&@dp_YDl@TWTU zGC%t=Kl)d`|EKbg<%3kJ{IPPFBjuSFqhkjpQW!ZTxkB-vkMxf}ugpHJ%s#KwpH}L> z)Sgw=p5)j5E{;7KdRCl%l9_%3-I98Se*iyG8qz+>aR!^_-Oq}~hPPLLFDe>FtBd;x z;o$V6oY)Is!jU2(!ZC-VG+YuK^EN7OCU8Mv=G=5Ca3ihH~O#PRO|$K2(o zutIG+{-)`K9MhHep;S=%Wo3ss0i-G)K&y%}h%$sSj52~UiZX^WjxvEV2@KNM!daEe7Wxo=B z75Oqql)viwR@Y%4@|#e^qZxh=a*$ROB_?yPNcA5w5tEsiG-9$4lS?tV8I$#xT#1Pu zlgXIWbpLue20XR^Vyn7l8$0){> zHZ{;MC{8UY*0Rx&eo5Q2iX)KuUAlci^C>2KczG$)vkyGXcNdK#k@e`12ZEd<6Q>PhYT#OY(;E9 F5dgO?J7)j@ literal 0 HcmV?d00001 diff --git a/psets/9/finance/env/lib/python3.12/site-packages/flask/__pycache__/app.cpython-312.pyc b/psets/9/finance/env/lib/python3.12/site-packages/flask/__pycache__/app.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..f4cfbca1243eccf94177a3140b84ea598ad8b6f9 GIT binary patch literal 62417 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 literal 0 HcmV?d00001 diff --git a/psets/9/finance/env/lib/python3.12/site-packages/flask/__pycache__/cli.cpython-312.pyc b/psets/9/finance/env/lib/python3.12/site-packages/flask/__pycache__/cli.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..0bc184e2d973722c5f40486f1547c9414f91ccd4 GIT binary patch literal 43378 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 literal 0 HcmV?d00001 diff --git a/psets/9/finance/env/lib/python3.12/site-packages/flask/__pycache__/config.cpython-312.pyc b/psets/9/finance/env/lib/python3.12/site-packages/flask/__pycache__/config.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..54319d252c34672b58ce67615e3938775a06967e GIT binary patch literal 16208 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 literal 0 HcmV?d00001 diff --git a/psets/9/finance/env/lib/python3.12/site-packages/flask/__pycache__/helpers.cpython-312.pyc b/psets/9/finance/env/lib/python3.12/site-packages/flask/__pycache__/helpers.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..7cb20c38913f48bcf7c2c59810886df32ef837fe GIT binary patch literal 25435 zcmd6Pd2Ae4nqO5PWRuN9Jake=$vViEsHQGk9*%WimJdp?;geRo1Wbn zBY))geeb=hYLb@h>;l;qRsFi^)%ULN{=WDAdu?sChR=VUc%kpFUevU|rXT7P7X^Ls zyAe&hsacw(=e0q-Ti2-^$w#`Q{2l9#@prsC&fgW?mH3Y46N8EF1lNt_s|KsPtGOIU zIoX|*FlxGMQMV#rH(1}jitknCYX%#-8@ZgwHw`v-uSU7bs?M(&T-&{t%Sn{ib+6-c z4a)1g*K@fR+>52H+65)HM?@)F*Us4+o=HjM1Bj}YDWEstW|Hu zx(#cawcToXGv2)wZ=DKit5TIF{#iS$#y4Xh%G=%B9#DIy)fBGnLus{|(dss<&03A` z?N&toTk~#A)mi>+rL47YR&?*E(yU$OPp#e7I`qB4YPZ${UcI%)+JNt!R@&;YTJWS5 z@9YiUvG!RTaktIdZ*4-oRPcmK)`9ZhEB&$#TAKl3Nk8!J!`2o++-*H#8Tf9utF1%U z*3ca68H=PI{ac#9lwL}jg+kFYys_TMuI;+$5sLMLD4KnCrZ;c8{kD~r>&{;>T%($%FTR4pP0jP44S<4{eg-6ch3{MX zhtySku4!JSC~4Y+c2##k5fj=#mAV&vE6lSZBmUbLwN!NcCueQX811*ce%moD`|@y~ zF<7*0!|g8)=Pl#1ZP*3#a^AL#-lAimmVtR_H*y6lm&NR&#u(kLHt^}R3nL?@)7f+8 zspA))%$z!X;@Pu3cz-146bplxLjzB91TAe`0wl}sHHY(_k#mino-=0NwR?Kf45^e1 zfjENM(n|W?QlwBU#e1ngdfC%tF@g0Jx5P?sCV_nAcw{97ylm-{Iyw zd(V)Wy@KU*J7_(xboASKAe5UP8Y|VI;S5h3t#zNX3GKDuzq=ooN$rb-maM(LYkJr9 z^mO{xrn&0Y$&+`J^*5rwTy^wT^u4Ngs(zZB*?n|o-O;(^v6et{iU>u znBx(nH0mo>j&SS*^r(|re|VlXEWX^LkIj8=s;ZLrZ%R1 zpm%+MOKEkVU9cU~D>@nc^$r)Z%pDp3McJmOo zY6}(G#w}l?RcAY@J3HvIlim)RVTgQrlpYW(Vz9^bllpSN#NC(|{uqU~w6|h6AxAtP z|EIMNW%>ItD>fDD)vd^zHP<2$Z6czu^;$H<1EZ=w_+a!RX5RC8>UOLwM|)#wY_sGf?OKfqK!BgBCrr%ez5qzVuVytBZV=14h0?9BB{ zhnQngJObH_*p9%wOZ|9`KdV>(K7*&)y}h|?&MsuffV!p&QDm3}i!gc6ykZ+U&j2mC zMm~4N&V$z$!BDfsVJx4+WH4wC7M(HFF|W7=t*vp{v`}%>$$6kfdJ-Xr%<>Y!9+*ongKsAs$k*q)&3`7miZRfH2$Yx|&6dPtXOP!Pw z(YTBb3aZT&FvdX^)fmNcZDW!Mpg|1Qpq^Z@?ICVZPCU9ska^zn z#X_I$bao1EK=P;8DGnOUqK(|(5JbJ~e;LZRt4_8XO7aH~jzPGk(S&EWwRVWXx2AYr z2tLT(pAl#XLTzYEb@~;k(y z6mx-<@mPJyWw=NCnjLKO~C|(5MXb_$T_4nogRJFBMkOlPzCTT!RKYnGAS) zpe?_yPiPMVmZkks) z=36%3th-V7o2Cu74!mFaNmJW=^V*x|-ahw}C;z?$Ri`d4G;0l8e!s%=g{an?`ttAB zbFKg5oB!KG9o7&QM#MVv#pH{Rl<&w(kE zdiNsNzvwx}gwX{Z;w2(r7%5Jv>eASdSP7?s0L2Q>@UUD&%T5Pf9;Vw>!XUOXePV5h zhxCBVk1?4C`r8rQcVEEe_fX&-*Aww$`rW$5nWnb6y3|zkw~ftl|CFKPh;nDAMHrC))*>%=GEm|73e zFrNdaLQ}Tn6TC_0kU54b7mI`JXaI$<-CD3o?=hi(K{11MVSrudNb@%H&|*vrJUpN! zs9q=RtO*gyoSevu^gsi?3|LhocF1~B+J#ZPJODohY^h-(ho$reahmyIyaCmXfq{mh zBSB`6+LR(&Ng!mZpCJPleRu7AFRXYEtRagbK?ihl*()>(hK5o2-3O?g$66!W zP~3od3)l)cKKTZ61=qu9jbg7<9I0_K!vr*FY^2SN=JI)H3Yes2T^sGsf$>l!QZ_I{ zG#B6{@a3qENUiZ)ui#7hV(|)ECbbx|KrBqPV#3itZ(|ImQ2+}Q3lY{7NhyE}!@jyy z0h7}UhYyx6+^dqz*x@qL$P&RUqTzLWIT)CtnO#wI$2Ro zREQ{4!*Z3Kl>Q;$CRygdyfMRt9tv=M!{qF7{pFOC%Idl4qrQ(zK5mgQbk)R^1Fv8T zp|4>~VcW(u4(>f@*d%Tk5WG2dcz#uPA3Tj9x=b$_6Jk|U?F3n_DLJQ#7?s1Am^Fcp zz--1cp8$YyKr$FNS;9YC;=3eE)Lvnr%ji;IJs^?6(>t6O_8aj99-Oa8xnFCD^qz0| zx1|D{P?PeF@qv4Bj!aGPGcrDj&iom$io`cC^xh&&l~KZZ#(Y8iatt^ zX*p!NFd~@y1j|fxs`}~I=k_HSGM5z`(pVIfPNKKY9ya^Z%-+&uH~R$C!$62E@KUZY z!d!!K30y7Q09mFO0NBr0HAQ1pT>xtOL-AVxLQtItb}5)cs9N4I5MDC3mDK)67`#Iv z7>D#IxTR|FRjO0dmC1ssLvPR9g;H(V*rDQ+juCdx93?Px`2jtkILD;+*(J#9Rd?$* z+^J8^)~Dv`ch4kt->s~kI{3!ejpMJsGGE_x3FU=))&BS)G z?*2inRGESQw4YSK3@t~|LcxU_e$XyeWuS#H0{MKqyDdccH$V6|OHVj`8d>PZ3$tD)d32Ex=h~4HY2|1!)EMS$w)- zPXw9N2nvuOk?JrIlA{0y7!w==dGdHev@5;2okb2wK$n+DE_*0mkREpOU@}fy%6Ke{ zpz`(+_&qP$jC7tM=8XZ7R|wo74|$ShR?5xFzIFXP0m+(Q;x^D41HtB!BqM{xUn{nI2=1EA>E~= zAqY!$RpLe`HN}g9iG%Nqd|WKI$@{-e;7?DFT0Qi)9Eg~oFc38c?j?*Zk8-7w%G$L@uIQSgDZm^;ia zlZw&C;gA$C&j&5>lNuD26;z{*eC4UMaas}@EjIDGYw3arit;kOEH5^59$aLNWN2&>ch4(X>XBT1Vhl%}Do01()>0}X+t zsz6R>n7AOV6n&m8T!BJWfCF$$a9V*ePz3F{>RkN2cEj>MwU4j6ZzHQ)vF^aLW`{%xpgj)!6CIR`BM5_$I0`bFu zLFG1t*EayIW(LDfW9r~b&JYi~Je)CADoeI2=xrSl@`)D2L28+mPJ;jWPGWL zQbG}+a~u^MvZ z5z-@sm_6*Z88LHt3dFH8#Vm@54dxxsy%b3DWuY6XCVM19Y!`~|XpY|#Ok5eLouuk@ z_5fL~jN8L~>0vLIchf!u*-Odg$@@prQ3xa;DH@0h{;m97LIcMuME8W<3b0VBR$v`W zHSotih;gVvP^)i5*=ztOwtYzSsjeWyG}pLB!MtMekqh ze^LP#c7&8XIAn=5`7@y{e>$c^348)X^^8d<4A$IfUj@>>;$tm-!b$~Zy6ML+UAk~u z{p|7ajg=C{mJl}n189&`!hi_LBkEJIAVSVVu^q5X_U?QW8Vrqwp(xoVsqp@U<-gnx z0wIUX;IKi?-i$fR2G8K8bF`2-%#0V4P%pNWtdOX=qG=)_aVWdOH?Pb%vajW%d;N`p(`uJVt; zZA0N!5nBd#B_E!OIY^J9u)KXp>_16R#_epp1#Lk;CH+4RmGiAU6ir z6=jjAk!Fa0IzFp!xysy5iKT!As~UP5~CytLN%=7`OhF-r&JRjeyIZKXfO>B zPO4RX$WX^hRetj#ykv+l<(lx@!Q?s50ok__Rkoo3t#PMT)AZwS-)U-_ZECyI^zdxc z!ygUKHJ!TC^yF;QlYjZbT=Kb@*mKK?ku*{WPJQuzpb#d;6{C`RpC1pr7MX~wl+6bn zQS0?%v&dVC1Q~&rP7azNez+3Rs*nfrVBk*?p8-+?mVDqli4N2)xrv{wzeYZk3L+&yG)2y4RBWEYO3>`sH9`anhnWNNqsI=CQ7DcfO-|BUk^bldU@E{v zL`pbSk{u{`4e4a?vvaNieo+NzWKKI{3jIo_IihXr^4h> zeM9#`AM!OKU$r<0$2z40Ks2{XIIU1HiCI!|%@u?xnBv4dhzSgV5kZPt!!l5{$2v}DLKZ4*nO&LNSWmE}W%vpuHrI?F( zE+y@PJM7pQY5`tXq`qs;AJF4UvFz}<0-Q>dko+gk&zvmk9U^u^Z-L#kYxQfcUzxsg zYuEdi5kQ?hJ0DBF)%9A}jmK~G%{1-&B-T2=Ve6Y`r=FONt-V{l`c8FfwmLOey&L(W zv8Fq*b+fT`^NHmA+6^~fefw3iZ5!7AT~%CJvSD?>=TLuxmfu27NWf24;!(txCU;r7 z=c^DS$dn6|?g4_g*0IA$mM?L01f_NWM5e7lQUe49%Ar&bjQ8{P3Y`apJ8BDOJN2SOTG%5R; ziLezf0Fh5T50#!hZ4_wm#{`}+2pDaOPTEz6Qe?3TBURc!XL6Jg#+_a^t>_4aOTd6Q zeiC$*qRm52aU{q2!H5aSsCTFanHZ}13^X}30*^S{0%V|*vyBo8DG*D3zOwgtaIQ_R zGS6oH4ese;_KM1GTt08iqn0+tV0;H6F9bvpl9jWbR26p_%R!Mg=@fw-SRzb4;R=fp ztWVimVi}N)DVLd>G9bwyJKNOKu{#_ui5L(WW#pIhbK&LVr5M9NQUYDkzomnsBx%f~ z2+jFOW|23Q7mMR~SPkf9UX~-(7=-MeSTIQJU`P@NC{EFdctmGU#}E`Rc&SA;JOK~_ zNNVdUrt%=!y9~1fzh_tkuMEcbd9E=0mElNHzNFPo&e;eN6HO7PIzrmo2q2YB1c^@x zXUU{@%1I|O3#N{M<#U5@*oUc;aP&N~vgDL66VH4j1Vr*6refwbP&*X65J=!qmQL2^ zyZAwT70K-SVj~Ka7l@P>ojB;UK0>+ukuDA;at1dvYrVHrzhp#ZDO-uh^5)=W%RDl^ zb0u{vNc~gwu94&;W%GBF+HL*z)(>JI)z7vGPZ38lk^MxE9g{93o=ef8;!r6@qbyYj z3`Sy8{gU-^`qWD${i+bWJu3IUd8Mv71-$SA^`?jddh^8*4ROx8t+RDoA%iRHCSRT3 zbLh_w&F(qz8Ve*qi%daZe+-+R*rrl`i-qWirwm)t=~D5*g2nUob3Aj=TU7{E4!~h-duCM zBSz|g{~?LWvCsdF0SqDpb+wsPYCh~HiJl$ z3e}-CTk;7#CDm!k=V#FmeanJ&o}^-3(9z7R8EmI1)jfOhbmsZY#nWA<&YXMdG*m3w zYJrVguARA>Ar%aWU^|EDW_89XB4Y!*r$1FCc4JV7Y2Sm#RY`!@83npRZ2od;QAa?n z0Nd`(^$BQI0We*-acBjk2Dd(g*c`YB6hCx9z!gp`=PGKwLD*!XFsaQ~*1k3V+W3vs zT;;}@%I$YIw%*xzcy{CAsfwww*~I#LvFf*;e(mYItJdDEf4lzf+K29}P0g-N&Ft!& zUHfhRxo>vuzPnAEg%!F`rNtY+(4f>IT2a$D`LwV;{q;kWL@80C>q!(IWPPsW6tW_@ zkUcq}-5)zt%zYw0Q87`8D2LSMWb{31W*U$Zhe=}HKzUh+37WiBhZrC!C)qsqHy}*N zEbkI-^yVDsBuesvWwO6WzC>%xA$Nwchx4dpTm%kBuU~k~IsJlTsM1?GSOiGQ)j_hH z$g(q(FP$40Gz&mFp~V1I$ZFyK0D<6X@*ERd4=F_=#_y|()SEOrIyu_7tWONX&mG{c z6f|VQMhY|(5$G1))XUgphOi~=t`nI9cuIYik^o5089)?{%9I2sln+K~DogDP& z?8z0=C&rK^b?&?}c)NHD1*OJ_4p8TjD#L0RdI6QpWYb#gx8jK=UCVWmX24rcq%YWW zpruld4wC-G8*tCje!#3__EP>Hze=)F?E8=_M~*uyXJMxm&k9AekzZvz3uQxE>w==7 zif2S z3Xhl%b%r7iVpI-ttB2T2il(36LsUbZqSggx8fG>33|uBxSaalQ=;g`q)w6wg*$l4!y(;9<&%sS9hm*tI;fVB{rJIa3>n?!aR^0+UN4_( zEH2Grm`SWma%tmfWQF;iAiJI?j_H&$grLZyHP^N&tyJ_GIR;2mVA~06NugNL59Jp^ z=DUZSYcUf~pL_bWK|kqbUIlW?sCnT;8>CtIJy1j$gl;`>2fS(__MgQHc!9~vog}Ac zS@Wh#?oDKIQnn>hOXQYZf?*n$9hgsSw9(!!?1U2gd5gWAbRx2RX*ylbJN6k?5S)}g zIa(o=C?|(arUdVC6rSQsG&M3($sS|bH02TjJ3%4BmPJbd=8r#^m{a0q&K04%BC}60 zuw{b=t*8X+PUAFhO(yzL_t+QZP;v(lNo3T5a3K_EFP`7FHbMM_vVpz< zdivuKv;-DWHbqh;>m)BAcJl(CXpx0VpwN={?EAC=k_gr++%d3oa#NlJ&f9xV3Nsws zTv=Fpw4cI*K9vy# zphAPpn_1{0G*|>ueL`h@lF+&*$V~N3R-S&;4pa7Fxiel$DMcP62K}*NPH01K!P|2R zuJj@{t#c+uu8_|a&`^Ll{KkVvBiC&CIC#=Bgi_cfiN`_DLwyO&Bem@!L?(8N3rY%r z;}PK+Ike{W)IN#X#{VCE|2}Qd1UVv#336*BT5k> z)e-B)OE(HZqm&^T=cQf{f8&i1V!O#6f0w9I`0wW<+LzwvPm0jn1hK$f#T(g7!=I|6 zo4$bYKZUeEl}fQ}m_gtt3^-ULA6Q74R{Ldqg-r<*4td?b^P%vPaR$tvIxpOUv~3%) z8!#c5H^(oYJao%IZA5;rCIPc|r=2F)=Fl@{sWJff%f55icS7R%&%1 z%^3ZJOy#bOu>?Kf;<<7C{rr+0*^#G2&{d-8zf6Gz>thrJH?DH%(rR>-b0(dGm2rC?cREf{5>8LOmVLJDwGG{#+B zPP~dQQ+@_9(^OTdhSX4Hb_s7*Vo=&1rP?xOp;TL@h~V_1KsPSMXmU!mWg4S11W%Ii z10yL{CC!!Moaqst9)r9F-U{IcJTYBkN*k4zuAliW6&-1eDPQ&VxbdfWW^9e0~sZk~Vp{QT-o z^BWK)ZJl4YZN6bO6`EVVXsS+De-=gE1+8YKXefEC*w^|U6#id4W|SY%Tjn*hbd{Xw z??S0Yj@CsoyrnAt6^;rh@g$hbd?6s15dD#e*u$YLq?n3hhy?eg**nGws(d=dLmdd_ zQEpbpV}u-?L@P%g3buTK5g@}~+G#|TB892^s0taC5NllKlWFr&o7$xhH4R*X2ld6) zXD>W;{`jfPne$JbI{i%ROYNKu1)o-#)=F-QGARDuI-xzlwz1&~fN==94vJt82Fni_ ztHo3n^ALl7m4e%h zT!nO}7F!szQ_sl06ZXEn98iCYkIXK&L`1gVqQIY}j#{c+f zwF?0Hpe&gcGxz+11+F1!{k87~d3qD!lS7`tX=~vaj_kl|XFNY1w^F{|0L6Nid>-%y zf-y@!E4TfjoCo!NQNyWQ6e{M=K(i_Z-vbnxTk;8#i8+U;!ds^*yslRvKWBiBOIz}x zT%O71AQxzWPB>fgQ5lWcOXJ5gDFaAl3ptI*WZb&sCHxHaCsugO+ooy+_w@(lLQQCV zEQIdu@ZZHsA`%-Fzpuq6Vw3e=t9ok1CbXYMtoXn5&mDVRf5003by2(}P?{PP6+Wq;d_@bkjRbx%t;o_RB?b{k ze@N+6b1CYM;V4bfX;*~Sar%I{oyiDTnT+$#s6{%H5IN#W zd6(ObqKnAP1a#*|^iqP>kUHWLD<_1M0sLCBa{UOu^HV(SB*AeMY!8-3vxb8fcTexW z-Z9;AYxi9B&dHPaDyt`7efQA&2X0q?(sJPE(Lb;G&owiTUbtJ|aD8-o^!lsQufFTN zH~P-#d#}Fp>TUN=Cq9^%+w$04{o$F!;f0DseAC_fb=O~+e&tSm>ui1N?c`kj!Kv82 zWc}1*cN;g()NI57LN)6as#qNl4A}&0B69UC?6NHZ4Ts4VxCDm2@srWo;dXUsHGe(Db3}N2iazyZ^mI z?;LvX=sQPmKRVZPa4z}qOzh#`eQ{FPYS+EHVJ5l#b4`!0fwlGhiiIdjU%DhEexbLX z-m3k@)`rs$NB`oWj%zk7Scz$aVd{%{6ezu=PrrsE7bi3%mbOD6h3ldQeLTrvIf;c< zbIB)2h7l<#itVXyq|MWD0MV|Jo)(8BL`xO$qC(j#tGU!z!V^puvFhe*`W*Fb?Nw|N$uX64L82SC^Kcf_A-)kuUAi3<2b3?&40S( zgDpRAnoAx2xjCCUHrI6glf(%e>N)uYCvwQMoE#D{Dg6?%T}X!UPd?;HJc#jeO58-FxZ7l%kKJ5TB*7;-D#R*gNj z(o>v56@vSqKAe9rh;Q1pcACUT=yHfIWbdcyoU`}>W5e!}<0ySujgmYsOKdg%w^a8e zUAS}#rST-4AFOJTS0V)VkMT1V$)$n2lu-T@J*9ij6S$P3$aLVA$JbK;_(gKvtNp4k zDTvg)Qcd^~0MYB?jd&fk!jJge4$;1UGMG3DtlCR=6`x_ziX^&csSn%{@^6R|&jZZ} zj{l(Sb5x@*@$e7)689%YM~I~&XQT(nA(9m+*@x12y<9JN++M^KN=({HS$g~%z2-8X zVM2FctfLyvBx5Z;n85K>I4_#tAtb|rXD_8HyUui7y42N`YGhZ^cw5Mw?;mnTvnSTh zOP}Bbnseuc(}~xOJx@eX!u`be*ayY;$PqPOEmsv#oJqQ|iB1LQpy&i#(KPYBkWchY zbHP5V@dH%Eoicd+L>Y>uI^_)%8^76{D>eBy{oS4}?|5|1(~D&2I8V~s4Sq!# zA#!w}NP75g!2FTHT#bmrvar%yh4 zuInuPl;TWxm(SaF9-t^T!E^=qyA*IMJJ+NMvnmQS_qxcRBJ z|5NS2r`jX`Q!_rLzm4j;{a!To*3s9Gej0mdu_CS?*S}a*qjxN9)*{ijHoUfBArjHI z%(rwbMDcwuzW(z#z89lfq=uhBz6bSA>hmqfsNzZeUi>iCJc*MJW!01VLiH26zIwjp zxrHbd?!_-H#;LH_9ZBoE7y5OrWy}1A&Gffv>u0qG^on^Ll^DhMLWNehZlRJ&I6iUR zLKT&&sg$Hrjkc;~f$A^RY4yzu^;BA=Ra7lDP^qA6PwMCOh3IPin9dNnupa6U7t&`% z;a3k@&p7)@j6LX-;k(D67GFs^2di;D@ZdGkUQ z7fB;qNOBS9L#$q?tJ{{ n19MVIr36*2LTT}N{Sp0<1xME+m7hl{^m)Ep{> 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 p4$H^~e)!3=ICKyAEe_OFgZ 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 PlTgBI+i}a|a6|kT7ui<; literal 0 HcmV?d00001 diff --git a/psets/9/finance/env/lib/python3.12/site-packages/flask/__pycache__/views.cpython-312.pyc b/psets/9/finance/env/lib/python3.12/site-packages/flask/__pycache__/views.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..0518f78c664bae9e9217a00f796e9efa9f6fe206 GIT binary patch literal 7005 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

={Wm%a- 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 literal 0 HcmV?d00001 diff --git a/psets/9/finance/env/lib/python3.12/site-packages/flask/app.py b/psets/9/finance/env/lib/python3.12/site-packages/flask/app.py new file mode 100644 index 0000000..905b247 --- /dev/null +++ b/psets/9/finance/env/lib/python3.12/site-packages/flask/app.py @@ -0,0 +1,1536 @@ +from __future__ import annotations + +import collections.abc as cabc +import os +import sys +import typing as t +import weakref +from datetime import timedelta +from inspect import iscoroutinefunction +from itertools import chain +from types import TracebackType +from urllib.parse import quote as _url_quote + +import click +from werkzeug.datastructures import Headers +from werkzeug.datastructures import ImmutableDict +from werkzeug.exceptions import BadRequestKeyError +from werkzeug.exceptions import HTTPException +from werkzeug.exceptions import InternalServerError +from werkzeug.routing import BuildError +from werkzeug.routing import MapAdapter +from werkzeug.routing import RequestRedirect +from werkzeug.routing import RoutingException +from werkzeug.routing import Rule +from werkzeug.serving import is_running_from_reloader +from werkzeug.wrappers import Response as BaseResponse +from werkzeug.wsgi import get_host + +from . import cli +from . import typing as ft +from .ctx import AppContext +from .ctx import RequestContext +from .globals import _cv_app +from .globals import _cv_request +from .globals import current_app +from .globals import g +from .globals import request +from .globals import request_ctx +from .globals import session +from .helpers import get_debug_flag +from .helpers import get_flashed_messages +from .helpers import get_load_dotenv +from .helpers import send_from_directory +from .sansio.app import App +from .sansio.scaffold import _sentinel +from .sessions import SecureCookieSessionInterface +from .sessions import SessionInterface +from .signals import appcontext_tearing_down +from .signals import got_request_exception +from .signals import request_finished +from .signals import request_started +from .signals import request_tearing_down +from .templating import Environment +from .wrappers import Request +from .wrappers import Response + +if t.TYPE_CHECKING: # pragma: no cover + from _typeshed.wsgi import StartResponse + from _typeshed.wsgi import WSGIEnvironment + + from .testing import FlaskClient + from .testing import FlaskCliRunner + from .typing import HeadersValue + +T_shell_context_processor = t.TypeVar( + "T_shell_context_processor", bound=ft.ShellContextProcessorCallable +) +T_teardown = t.TypeVar("T_teardown", bound=ft.TeardownCallable) +T_template_filter = t.TypeVar("T_template_filter", bound=ft.TemplateFilterCallable) +T_template_global = t.TypeVar("T_template_global", bound=ft.TemplateGlobalCallable) +T_template_test = t.TypeVar("T_template_test", bound=ft.TemplateTestCallable) + + +def _make_timedelta(value: timedelta | int | None) -> timedelta | None: + if value is None or isinstance(value, timedelta): + return value + + return timedelta(seconds=value) + + +class Flask(App): + """The flask object implements a WSGI application and acts as the central + object. It is passed the name of the module or package of the + application. Once it is created it will act as a central registry for + the view functions, the URL rules, template configuration and much more. + + The name of the package is used to resolve resources from inside the + package or the folder the module is contained in depending on if the + package parameter resolves to an actual python package (a folder with + an :file:`__init__.py` file inside) or a standard module (just a ``.py`` file). + + For more information about resource loading, see :func:`open_resource`. + + Usually you create a :class:`Flask` instance in your main module or + in the :file:`__init__.py` file of your package like this:: + + from flask import Flask + app = Flask(__name__) + + .. admonition:: About the First Parameter + + The idea of the first parameter is to give Flask an idea of what + belongs to your application. This name is used to find resources + on the filesystem, can be used by extensions to improve debugging + information and a lot more. + + So it's important what you provide there. If you are using a single + module, `__name__` is always the correct value. If you however are + using a package, it's usually recommended to hardcode the name of + your package there. + + For example if your application is defined in :file:`yourapplication/app.py` + you should create it with one of the two versions below:: + + app = Flask('yourapplication') + app = Flask(__name__.split('.')[0]) + + Why is that? The application will work even with `__name__`, thanks + to how resources are looked up. However it will make debugging more + painful. Certain extensions can make assumptions based on the + import name of your application. For example the Flask-SQLAlchemy + extension will look for the code in your application that triggered + an SQL query in debug mode. If the import name is not properly set + up, that debugging information is lost. (For example it would only + pick up SQL queries in `yourapplication.app` and not + `yourapplication.views.frontend`) + + .. versionadded:: 0.7 + The `static_url_path`, `static_folder`, and `template_folder` + parameters were added. + + .. versionadded:: 0.8 + The `instance_path` and `instance_relative_config` parameters were + added. + + .. versionadded:: 0.11 + The `root_path` parameter was added. + + .. versionadded:: 1.0 + The ``host_matching`` and ``static_host`` parameters were added. + + .. versionadded:: 1.0 + The ``subdomain_matching`` parameter was added. Subdomain + matching needs to be enabled manually now. Setting + :data:`SERVER_NAME` does not implicitly enable it. + + :param import_name: the name of the application package + :param static_url_path: can be used to specify a different path for the + static files on the web. Defaults to the name + of the `static_folder` folder. + :param static_folder: The folder with static files that is served at + ``static_url_path``. Relative to the application ``root_path`` + or an absolute path. Defaults to ``'static'``. + :param static_host: the host to use when adding the static route. + Defaults to None. Required when using ``host_matching=True`` + with a ``static_folder`` configured. + :param host_matching: set ``url_map.host_matching`` attribute. + Defaults to False. + :param subdomain_matching: consider the subdomain relative to + :data:`SERVER_NAME` when matching routes. Defaults to False. + :param template_folder: the folder that contains the templates that should + be used by the application. Defaults to + ``'templates'`` folder in the root path of the + application. + :param instance_path: An alternative instance path for the application. + By default the folder ``'instance'`` next to the + package or module is assumed to be the instance + path. + :param instance_relative_config: if set to ``True`` relative filenames + for loading the config are assumed to + be relative to the instance path instead + of the application root. + :param root_path: The path to the root of the application files. + This should only be set manually when it can't be detected + automatically, such as for namespace packages. + """ + + default_config = ImmutableDict( + { + "DEBUG": None, + "TESTING": False, + "PROPAGATE_EXCEPTIONS": None, + "SECRET_KEY": None, + "SECRET_KEY_FALLBACKS": None, + "PERMANENT_SESSION_LIFETIME": timedelta(days=31), + "USE_X_SENDFILE": False, + "TRUSTED_HOSTS": None, + "SERVER_NAME": None, + "APPLICATION_ROOT": "/", + "SESSION_COOKIE_NAME": "session", + "SESSION_COOKIE_DOMAIN": None, + "SESSION_COOKIE_PATH": None, + "SESSION_COOKIE_HTTPONLY": True, + "SESSION_COOKIE_SECURE": False, + "SESSION_COOKIE_PARTITIONED": False, + "SESSION_COOKIE_SAMESITE": None, + "SESSION_REFRESH_EACH_REQUEST": True, + "MAX_CONTENT_LENGTH": None, + "MAX_FORM_MEMORY_SIZE": 500_000, + "MAX_FORM_PARTS": 1_000, + "SEND_FILE_MAX_AGE_DEFAULT": None, + "TRAP_BAD_REQUEST_ERRORS": None, + "TRAP_HTTP_EXCEPTIONS": False, + "EXPLAIN_TEMPLATE_LOADING": False, + "PREFERRED_URL_SCHEME": "http", + "TEMPLATES_AUTO_RELOAD": None, + "MAX_COOKIE_SIZE": 4093, + "PROVIDE_AUTOMATIC_OPTIONS": True, + } + ) + + #: The class that is used for request objects. See :class:`~flask.Request` + #: for more information. + request_class: type[Request] = Request + + #: The class that is used for response objects. See + #: :class:`~flask.Response` for more information. + response_class: type[Response] = Response + + #: the session interface to use. By default an instance of + #: :class:`~flask.sessions.SecureCookieSessionInterface` is used here. + #: + #: .. versionadded:: 0.8 + session_interface: SessionInterface = SecureCookieSessionInterface() + + def __init__( + self, + import_name: str, + static_url_path: str | None = None, + static_folder: str | os.PathLike[str] | None = "static", + static_host: str | None = None, + host_matching: bool = False, + subdomain_matching: bool = False, + template_folder: str | os.PathLike[str] | None = "templates", + instance_path: str | None = None, + instance_relative_config: bool = False, + root_path: str | None = None, + ): + super().__init__( + import_name=import_name, + static_url_path=static_url_path, + static_folder=static_folder, + static_host=static_host, + host_matching=host_matching, + subdomain_matching=subdomain_matching, + template_folder=template_folder, + instance_path=instance_path, + instance_relative_config=instance_relative_config, + root_path=root_path, + ) + + #: The Click command group for registering CLI commands for this + #: object. The commands are available from the ``flask`` command + #: once the application has been discovered and blueprints have + #: been registered. + self.cli = cli.AppGroup() + + # Set the name of the Click group in case someone wants to add + # the app's commands to another CLI tool. + self.cli.name = self.name + + # Add a static route using the provided static_url_path, static_host, + # and static_folder if there is a configured static_folder. + # Note we do this without checking if static_folder exists. + # For one, it might be created while the server is running (e.g. during + # development). Also, Google App Engine stores static files somewhere + if self.has_static_folder: + assert ( + bool(static_host) == host_matching + ), "Invalid static_host/host_matching combination" + # Use a weakref to avoid creating a reference cycle between the app + # and the view function (see #3761). + self_ref = weakref.ref(self) + self.add_url_rule( + f"{self.static_url_path}/", + endpoint="static", + host=static_host, + view_func=lambda **kw: self_ref().send_static_file(**kw), # type: ignore # noqa: B950 + ) + + def get_send_file_max_age(self, filename: str | None) -> int | None: + """Used by :func:`send_file` to determine the ``max_age`` cache + value for a given file path if it wasn't passed. + + By default, this returns :data:`SEND_FILE_MAX_AGE_DEFAULT` from + the configuration of :data:`~flask.current_app`. This defaults + to ``None``, which tells the browser to use conditional requests + instead of a timed cache, which is usually preferable. + + Note this is a duplicate of the same method in the Flask + class. + + .. versionchanged:: 2.0 + The default configuration is ``None`` instead of 12 hours. + + .. versionadded:: 0.9 + """ + value = current_app.config["SEND_FILE_MAX_AGE_DEFAULT"] + + if value is None: + return None + + if isinstance(value, timedelta): + return int(value.total_seconds()) + + return value # type: ignore[no-any-return] + + def send_static_file(self, filename: str) -> Response: + """The view function used to serve files from + :attr:`static_folder`. A route is automatically registered for + this view at :attr:`static_url_path` if :attr:`static_folder` is + set. + + Note this is a duplicate of the same method in the Flask + class. + + .. versionadded:: 0.5 + + """ + if not self.has_static_folder: + raise RuntimeError("'static_folder' must be set to serve static_files.") + + # send_file only knows to call get_send_file_max_age on the app, + # call it here so it works for blueprints too. + max_age = self.get_send_file_max_age(filename) + return send_from_directory( + t.cast(str, self.static_folder), filename, max_age=max_age + ) + + def open_resource( + self, resource: str, mode: str = "rb", encoding: str | None = None + ) -> t.IO[t.AnyStr]: + """Open a resource file relative to :attr:`root_path` for reading. + + For example, if the file ``schema.sql`` is next to the file + ``app.py`` where the ``Flask`` app is defined, it can be opened + with: + + .. code-block:: python + + with app.open_resource("schema.sql") as f: + conn.executescript(f.read()) + + :param resource: Path to the resource relative to :attr:`root_path`. + :param mode: Open the file in this mode. Only reading is supported, + valid values are ``"r"`` (or ``"rt"``) and ``"rb"``. + :param encoding: Open the file with this encoding when opening in text + mode. This is ignored when opening in binary mode. + + .. versionchanged:: 3.1 + Added the ``encoding`` parameter. + """ + if mode not in {"r", "rt", "rb"}: + raise ValueError("Resources can only be opened for reading.") + + path = os.path.join(self.root_path, resource) + + if mode == "rb": + return open(path, mode) # pyright: ignore + + return open(path, mode, encoding=encoding) + + def open_instance_resource( + self, resource: str, mode: str = "rb", encoding: str | None = "utf-8" + ) -> t.IO[t.AnyStr]: + """Open a resource file relative to the application's instance folder + :attr:`instance_path`. Unlike :meth:`open_resource`, files in the + instance folder can be opened for writing. + + :param resource: Path to the resource relative to :attr:`instance_path`. + :param mode: Open the file in this mode. + :param encoding: Open the file with this encoding when opening in text + mode. This is ignored when opening in binary mode. + + .. versionchanged:: 3.1 + Added the ``encoding`` parameter. + """ + path = os.path.join(self.instance_path, resource) + + if "b" in mode: + return open(path, mode) + + return open(path, mode, encoding=encoding) + + def create_jinja_environment(self) -> Environment: + """Create the Jinja environment based on :attr:`jinja_options` + and the various Jinja-related methods of the app. Changing + :attr:`jinja_options` after this will have no effect. Also adds + Flask-related globals and filters to the environment. + + .. versionchanged:: 0.11 + ``Environment.auto_reload`` set in accordance with + ``TEMPLATES_AUTO_RELOAD`` configuration option. + + .. versionadded:: 0.5 + """ + options = dict(self.jinja_options) + + if "autoescape" not in options: + options["autoescape"] = self.select_jinja_autoescape + + if "auto_reload" not in options: + auto_reload = self.config["TEMPLATES_AUTO_RELOAD"] + + if auto_reload is None: + auto_reload = self.debug + + options["auto_reload"] = auto_reload + + rv = self.jinja_environment(self, **options) + rv.globals.update( + url_for=self.url_for, + get_flashed_messages=get_flashed_messages, + config=self.config, + # request, session and g are normally added with the + # context processor for efficiency reasons but for imported + # templates we also want the proxies in there. + request=request, + session=session, + g=g, + ) + rv.policies["json.dumps_function"] = self.json.dumps + return rv + + def create_url_adapter(self, request: Request | None) -> MapAdapter | None: + """Creates a URL adapter for the given request. The URL adapter + is created at a point where the request context is not yet set + up so the request is passed explicitly. + + .. versionchanged:: 3.1 + If :data:`SERVER_NAME` is set, it does not restrict requests to + only that domain, for both ``subdomain_matching`` and + ``host_matching``. + + .. versionchanged:: 1.0 + :data:`SERVER_NAME` no longer implicitly enables subdomain + matching. Use :attr:`subdomain_matching` instead. + + .. versionchanged:: 0.9 + This can be called outside a request when the URL adapter is created + for an application context. + + .. versionadded:: 0.6 + """ + if request is not None: + if (trusted_hosts := self.config["TRUSTED_HOSTS"]) is not None: + request.trusted_hosts = trusted_hosts + + # Check trusted_hosts here until bind_to_environ does. + request.host = get_host(request.environ, request.trusted_hosts) # pyright: ignore + subdomain = None + server_name = self.config["SERVER_NAME"] + + if self.url_map.host_matching: + # Don't pass SERVER_NAME, otherwise it's used and the actual + # host is ignored, which breaks host matching. + server_name = None + elif not self.subdomain_matching: + # Werkzeug doesn't implement subdomain matching yet. Until then, + # disable it by forcing the current subdomain to the default, or + # the empty string. + subdomain = self.url_map.default_subdomain or "" + + return self.url_map.bind_to_environ( + request.environ, server_name=server_name, subdomain=subdomain + ) + + # Need at least SERVER_NAME to match/build outside a request. + if self.config["SERVER_NAME"] is not None: + return self.url_map.bind( + self.config["SERVER_NAME"], + script_name=self.config["APPLICATION_ROOT"], + url_scheme=self.config["PREFERRED_URL_SCHEME"], + ) + + return None + + def raise_routing_exception(self, request: Request) -> t.NoReturn: + """Intercept routing exceptions and possibly do something else. + + In debug mode, intercept a routing redirect and replace it with + an error if the body will be discarded. + + With modern Werkzeug this shouldn't occur, since it now uses a + 308 status which tells the browser to resend the method and + body. + + .. versionchanged:: 2.1 + Don't intercept 307 and 308 redirects. + + :meta private: + :internal: + """ + if ( + not self.debug + or not isinstance(request.routing_exception, RequestRedirect) + or request.routing_exception.code in {307, 308} + or request.method in {"GET", "HEAD", "OPTIONS"} + ): + raise request.routing_exception # type: ignore[misc] + + from .debughelpers import FormDataRoutingRedirect + + raise FormDataRoutingRedirect(request) + + def update_template_context(self, context: dict[str, t.Any]) -> None: + """Update the template context with some commonly used variables. + This injects request, session, config and g into the template + context as well as everything template context processors want + to inject. Note that the as of Flask 0.6, the original values + in the context will not be overridden if a context processor + decides to return a value with the same key. + + :param context: the context as a dictionary that is updated in place + to add extra variables. + """ + names: t.Iterable[str | None] = (None,) + + # A template may be rendered outside a request context. + if request: + names = chain(names, reversed(request.blueprints)) + + # The values passed to render_template take precedence. Keep a + # copy to re-apply after all context functions. + orig_ctx = context.copy() + + for name in names: + if name in self.template_context_processors: + for func in self.template_context_processors[name]: + context.update(self.ensure_sync(func)()) + + context.update(orig_ctx) + + def make_shell_context(self) -> dict[str, t.Any]: + """Returns the shell context for an interactive shell for this + application. This runs all the registered shell context + processors. + + .. versionadded:: 0.11 + """ + rv = {"app": self, "g": g} + for processor in self.shell_context_processors: + rv.update(processor()) + return rv + + def run( + self, + host: str | None = None, + port: int | None = None, + debug: bool | None = None, + load_dotenv: bool = True, + **options: t.Any, + ) -> None: + """Runs the application on a local development server. + + Do not use ``run()`` in a production setting. It is not intended to + meet security and performance requirements for a production server. + Instead, see :doc:`/deploying/index` for WSGI server recommendations. + + If the :attr:`debug` flag is set the server will automatically reload + for code changes and show a debugger in case an exception happened. + + If you want to run the application in debug mode, but disable the + code execution on the interactive debugger, you can pass + ``use_evalex=False`` as parameter. This will keep the debugger's + traceback screen active, but disable code execution. + + It is not recommended to use this function for development with + automatic reloading as this is badly supported. Instead you should + be using the :command:`flask` command line script's ``run`` support. + + .. admonition:: Keep in Mind + + Flask will suppress any server error with a generic error page + unless it is in debug mode. As such to enable just the + interactive debugger without the code reloading, you have to + invoke :meth:`run` with ``debug=True`` and ``use_reloader=False``. + Setting ``use_debugger`` to ``True`` without being in debug mode + won't catch any exceptions because there won't be any to + catch. + + :param host: the hostname to listen on. Set this to ``'0.0.0.0'`` to + have the server available externally as well. Defaults to + ``'127.0.0.1'`` or the host in the ``SERVER_NAME`` config variable + if present. + :param port: the port of the webserver. Defaults to ``5000`` or the + port defined in the ``SERVER_NAME`` config variable if present. + :param debug: if given, enable or disable debug mode. See + :attr:`debug`. + :param load_dotenv: Load the nearest :file:`.env` and :file:`.flaskenv` + files to set environment variables. Will also change the working + directory to the directory containing the first file found. + :param options: the options to be forwarded to the underlying Werkzeug + server. See :func:`werkzeug.serving.run_simple` for more + information. + + .. versionchanged:: 1.0 + If installed, python-dotenv will be used to load environment + variables from :file:`.env` and :file:`.flaskenv` files. + + The :envvar:`FLASK_DEBUG` environment variable will override :attr:`debug`. + + Threaded mode is enabled by default. + + .. versionchanged:: 0.10 + The default port is now picked from the ``SERVER_NAME`` + variable. + """ + # Ignore this call so that it doesn't start another server if + # the 'flask run' command is used. + if os.environ.get("FLASK_RUN_FROM_CLI") == "true": + if not is_running_from_reloader(): + click.secho( + " * Ignoring a call to 'app.run()' that would block" + " the current 'flask' CLI command.\n" + " Only call 'app.run()' in an 'if __name__ ==" + ' "__main__"\' guard.', + fg="red", + ) + + return + + if get_load_dotenv(load_dotenv): + cli.load_dotenv() + + # if set, env var overrides existing value + if "FLASK_DEBUG" in os.environ: + self.debug = get_debug_flag() + + # debug passed to method overrides all other sources + if debug is not None: + self.debug = bool(debug) + + server_name = self.config.get("SERVER_NAME") + sn_host = sn_port = None + + if server_name: + sn_host, _, sn_port = server_name.partition(":") + + if not host: + if sn_host: + host = sn_host + else: + host = "127.0.0.1" + + if port or port == 0: + port = int(port) + elif sn_port: + port = int(sn_port) + else: + port = 5000 + + options.setdefault("use_reloader", self.debug) + options.setdefault("use_debugger", self.debug) + options.setdefault("threaded", True) + + cli.show_server_banner(self.debug, self.name) + + from werkzeug.serving import run_simple + + try: + run_simple(t.cast(str, host), port, self, **options) + finally: + # reset the first request information if the development server + # reset normally. This makes it possible to restart the server + # without reloader and that stuff from an interactive shell. + self._got_first_request = False + + def test_client(self, use_cookies: bool = True, **kwargs: t.Any) -> FlaskClient: + """Creates a test client for this application. For information + about unit testing head over to :doc:`/testing`. + + Note that if you are testing for assertions or exceptions in your + application code, you must set ``app.testing = True`` in order for the + exceptions to propagate to the test client. Otherwise, the exception + will be handled by the application (not visible to the test client) and + the only indication of an AssertionError or other exception will be a + 500 status code response to the test client. See the :attr:`testing` + attribute. For example:: + + app.testing = True + client = app.test_client() + + The test client can be used in a ``with`` block to defer the closing down + of the context until the end of the ``with`` block. This is useful if + you want to access the context locals for testing:: + + with app.test_client() as c: + rv = c.get('/?vodka=42') + assert request.args['vodka'] == '42' + + Additionally, you may pass optional keyword arguments that will then + be passed to the application's :attr:`test_client_class` constructor. + For example:: + + from flask.testing import FlaskClient + + class CustomClient(FlaskClient): + def __init__(self, *args, **kwargs): + self._authentication = kwargs.pop("authentication") + super(CustomClient,self).__init__( *args, **kwargs) + + app.test_client_class = CustomClient + client = app.test_client(authentication='Basic ....') + + See :class:`~flask.testing.FlaskClient` for more information. + + .. versionchanged:: 0.4 + added support for ``with`` block usage for the client. + + .. versionadded:: 0.7 + The `use_cookies` parameter was added as well as the ability + to override the client to be used by setting the + :attr:`test_client_class` attribute. + + .. versionchanged:: 0.11 + Added `**kwargs` to support passing additional keyword arguments to + the constructor of :attr:`test_client_class`. + """ + cls = self.test_client_class + if cls is None: + from .testing import FlaskClient as cls + return cls( # type: ignore + self, self.response_class, use_cookies=use_cookies, **kwargs + ) + + def test_cli_runner(self, **kwargs: t.Any) -> FlaskCliRunner: + """Create a CLI runner for testing CLI commands. + See :ref:`testing-cli`. + + Returns an instance of :attr:`test_cli_runner_class`, by default + :class:`~flask.testing.FlaskCliRunner`. The Flask app object is + passed as the first argument. + + .. versionadded:: 1.0 + """ + cls = self.test_cli_runner_class + + if cls is None: + from .testing import FlaskCliRunner as cls + + return cls(self, **kwargs) # type: ignore + + def handle_http_exception( + self, e: HTTPException + ) -> HTTPException | ft.ResponseReturnValue: + """Handles an HTTP exception. By default this will invoke the + registered error handlers and fall back to returning the + exception as response. + + .. versionchanged:: 1.0.3 + ``RoutingException``, used internally for actions such as + slash redirects during routing, is not passed to error + handlers. + + .. versionchanged:: 1.0 + Exceptions are looked up by code *and* by MRO, so + ``HTTPException`` subclasses can be handled with a catch-all + handler for the base ``HTTPException``. + + .. versionadded:: 0.3 + """ + # Proxy exceptions don't have error codes. We want to always return + # those unchanged as errors + if e.code is None: + return e + + # RoutingExceptions are used internally to trigger routing + # actions, such as slash redirects raising RequestRedirect. They + # are not raised or handled in user code. + if isinstance(e, RoutingException): + return e + + handler = self._find_error_handler(e, request.blueprints) + if handler is None: + return e + return self.ensure_sync(handler)(e) # type: ignore[no-any-return] + + def handle_user_exception( + self, e: Exception + ) -> HTTPException | ft.ResponseReturnValue: + """This method is called whenever an exception occurs that + should be handled. A special case is :class:`~werkzeug + .exceptions.HTTPException` which is forwarded to the + :meth:`handle_http_exception` method. This function will either + return a response value or reraise the exception with the same + traceback. + + .. versionchanged:: 1.0 + Key errors raised from request data like ``form`` show the + bad key in debug mode rather than a generic bad request + message. + + .. versionadded:: 0.7 + """ + if isinstance(e, BadRequestKeyError) and ( + self.debug or self.config["TRAP_BAD_REQUEST_ERRORS"] + ): + e.show_exception = True + + if isinstance(e, HTTPException) and not self.trap_http_exception(e): + return self.handle_http_exception(e) + + handler = self._find_error_handler(e, request.blueprints) + + if handler is None: + raise + + return self.ensure_sync(handler)(e) # type: ignore[no-any-return] + + def handle_exception(self, e: Exception) -> Response: + """Handle an exception that did not have an error handler + associated with it, or that was raised from an error handler. + This always causes a 500 ``InternalServerError``. + + Always sends the :data:`got_request_exception` signal. + + If :data:`PROPAGATE_EXCEPTIONS` is ``True``, such as in debug + mode, the error will be re-raised so that the debugger can + display it. Otherwise, the original exception is logged, and + an :exc:`~werkzeug.exceptions.InternalServerError` is returned. + + If an error handler is registered for ``InternalServerError`` or + ``500``, it will be used. For consistency, the handler will + always receive the ``InternalServerError``. The original + unhandled exception is available as ``e.original_exception``. + + .. versionchanged:: 1.1.0 + Always passes the ``InternalServerError`` instance to the + handler, setting ``original_exception`` to the unhandled + error. + + .. versionchanged:: 1.1.0 + ``after_request`` functions and other finalization is done + even for the default 500 response when there is no handler. + + .. versionadded:: 0.3 + """ + exc_info = sys.exc_info() + got_request_exception.send(self, _async_wrapper=self.ensure_sync, exception=e) + propagate = self.config["PROPAGATE_EXCEPTIONS"] + + if propagate is None: + propagate = self.testing or self.debug + + if propagate: + # Re-raise if called with an active exception, otherwise + # raise the passed in exception. + if exc_info[1] is e: + raise + + raise e + + self.log_exception(exc_info) + server_error: InternalServerError | ft.ResponseReturnValue + server_error = InternalServerError(original_exception=e) + handler = self._find_error_handler(server_error, request.blueprints) + + if handler is not None: + server_error = self.ensure_sync(handler)(server_error) + + return self.finalize_request(server_error, from_error_handler=True) + + def log_exception( + self, + exc_info: (tuple[type, BaseException, TracebackType] | tuple[None, None, None]), + ) -> None: + """Logs an exception. This is called by :meth:`handle_exception` + if debugging is disabled and right before the handler is called. + The default implementation logs the exception as error on the + :attr:`logger`. + + .. versionadded:: 0.8 + """ + self.logger.error( + f"Exception on {request.path} [{request.method}]", exc_info=exc_info + ) + + def dispatch_request(self) -> ft.ResponseReturnValue: + """Does the request dispatching. Matches the URL and returns the + return value of the view or error handler. This does not have to + be a response object. In order to convert the return value to a + proper response object, call :func:`make_response`. + + .. versionchanged:: 0.7 + This no longer does the exception handling, this code was + moved to the new :meth:`full_dispatch_request`. + """ + req = request_ctx.request + if req.routing_exception is not None: + self.raise_routing_exception(req) + rule: Rule = req.url_rule # type: ignore[assignment] + # if we provide automatic options for this URL and the + # request came with the OPTIONS method, reply automatically + if ( + getattr(rule, "provide_automatic_options", False) + and req.method == "OPTIONS" + ): + return self.make_default_options_response() + # otherwise dispatch to the handler for that endpoint + view_args: dict[str, t.Any] = req.view_args # type: ignore[assignment] + return self.ensure_sync(self.view_functions[rule.endpoint])(**view_args) # type: ignore[no-any-return] + + def full_dispatch_request(self) -> Response: + """Dispatches the request and on top of that performs request + pre and postprocessing as well as HTTP exception catching and + error handling. + + .. versionadded:: 0.7 + """ + self._got_first_request = True + + try: + request_started.send(self, _async_wrapper=self.ensure_sync) + rv = self.preprocess_request() + if rv is None: + rv = self.dispatch_request() + except Exception as e: + rv = self.handle_user_exception(e) + return self.finalize_request(rv) + + def finalize_request( + self, + rv: ft.ResponseReturnValue | HTTPException, + from_error_handler: bool = False, + ) -> Response: + """Given the return value from a view function this finalizes + the request by converting it into a response and invoking the + postprocessing functions. This is invoked for both normal + request dispatching as well as error handlers. + + Because this means that it might be called as a result of a + failure a special safe mode is available which can be enabled + with the `from_error_handler` flag. If enabled, failures in + response processing will be logged and otherwise ignored. + + :internal: + """ + response = self.make_response(rv) + try: + response = self.process_response(response) + request_finished.send( + self, _async_wrapper=self.ensure_sync, response=response + ) + except Exception: + if not from_error_handler: + raise + self.logger.exception( + "Request finalizing failed with an error while handling an error" + ) + return response + + def make_default_options_response(self) -> Response: + """This method is called to create the default ``OPTIONS`` response. + This can be changed through subclassing to change the default + behavior of ``OPTIONS`` responses. + + .. versionadded:: 0.7 + """ + adapter = request_ctx.url_adapter + methods = adapter.allowed_methods() # type: ignore[union-attr] + rv = self.response_class() + rv.allow.update(methods) + return rv + + def ensure_sync(self, func: t.Callable[..., t.Any]) -> t.Callable[..., t.Any]: + """Ensure that the function is synchronous for WSGI workers. + Plain ``def`` functions are returned as-is. ``async def`` + functions are wrapped to run and wait for the response. + + Override this method to change how the app runs async views. + + .. versionadded:: 2.0 + """ + if iscoroutinefunction(func): + return self.async_to_sync(func) + + return func + + def async_to_sync( + self, func: t.Callable[..., t.Coroutine[t.Any, t.Any, t.Any]] + ) -> t.Callable[..., t.Any]: + """Return a sync function that will run the coroutine function. + + .. code-block:: python + + result = app.async_to_sync(func)(*args, **kwargs) + + Override this method to change how the app converts async code + to be synchronously callable. + + .. versionadded:: 2.0 + """ + try: + from asgiref.sync import async_to_sync as asgiref_async_to_sync + except ImportError: + raise RuntimeError( + "Install Flask with the 'async' extra in order to use async views." + ) from None + + return asgiref_async_to_sync(func) + + def url_for( + self, + /, + endpoint: str, + *, + _anchor: str | None = None, + _method: str | None = None, + _scheme: str | None = None, + _external: bool | None = None, + **values: t.Any, + ) -> str: + """Generate a URL to the given endpoint with the given values. + + This is called by :func:`flask.url_for`, and can be called + directly as well. + + An *endpoint* is the name of a URL rule, usually added with + :meth:`@app.route() `, and usually the same name as the + view function. A route defined in a :class:`~flask.Blueprint` + will prepend the blueprint's name separated by a ``.`` to the + endpoint. + + In some cases, such as email messages, you want URLs to include + the scheme and domain, like ``https://example.com/hello``. When + not in an active request, URLs will be external by default, but + this requires setting :data:`SERVER_NAME` so Flask knows what + domain to use. :data:`APPLICATION_ROOT` and + :data:`PREFERRED_URL_SCHEME` should also be configured as + needed. This config is only used when not in an active request. + + Functions can be decorated with :meth:`url_defaults` to modify + keyword arguments before the URL is built. + + If building fails for some reason, such as an unknown endpoint + or incorrect values, the app's :meth:`handle_url_build_error` + method is called. If that returns a string, that is returned, + otherwise a :exc:`~werkzeug.routing.BuildError` is raised. + + :param endpoint: The endpoint name associated with the URL to + generate. If this starts with a ``.``, the current blueprint + name (if any) will be used. + :param _anchor: If given, append this as ``#anchor`` to the URL. + :param _method: If given, generate the URL associated with this + method for the endpoint. + :param _scheme: If given, the URL will have this scheme if it + is external. + :param _external: If given, prefer the URL to be internal + (False) or require it to be external (True). External URLs + include the scheme and domain. When not in an active + request, URLs are external by default. + :param values: Values to use for the variable parts of the URL + rule. Unknown keys are appended as query string arguments, + like ``?a=b&c=d``. + + .. versionadded:: 2.2 + Moved from ``flask.url_for``, which calls this method. + """ + req_ctx = _cv_request.get(None) + + if req_ctx is not None: + url_adapter = req_ctx.url_adapter + blueprint_name = req_ctx.request.blueprint + + # If the endpoint starts with "." and the request matches a + # blueprint, the endpoint is relative to the blueprint. + if endpoint[:1] == ".": + if blueprint_name is not None: + endpoint = f"{blueprint_name}{endpoint}" + else: + endpoint = endpoint[1:] + + # When in a request, generate a URL without scheme and + # domain by default, unless a scheme is given. + if _external is None: + _external = _scheme is not None + else: + app_ctx = _cv_app.get(None) + + # If called by helpers.url_for, an app context is active, + # use its url_adapter. Otherwise, app.url_for was called + # directly, build an adapter. + if app_ctx is not None: + url_adapter = app_ctx.url_adapter + else: + url_adapter = self.create_url_adapter(None) + + if url_adapter is None: + raise RuntimeError( + "Unable to build URLs outside an active request" + " without 'SERVER_NAME' configured. Also configure" + " 'APPLICATION_ROOT' and 'PREFERRED_URL_SCHEME' as" + " needed." + ) + + # When outside a request, generate a URL with scheme and + # domain by default. + if _external is None: + _external = True + + # It is an error to set _scheme when _external=False, in order + # to avoid accidental insecure URLs. + if _scheme is not None and not _external: + raise ValueError("When specifying '_scheme', '_external' must be True.") + + self.inject_url_defaults(endpoint, values) + + try: + rv = url_adapter.build( # type: ignore[union-attr] + endpoint, + values, + method=_method, + url_scheme=_scheme, + force_external=_external, + ) + except BuildError as error: + values.update( + _anchor=_anchor, _method=_method, _scheme=_scheme, _external=_external + ) + return self.handle_url_build_error(error, endpoint, values) + + if _anchor is not None: + _anchor = _url_quote(_anchor, safe="%!#$&'()*+,/:;=?@") + rv = f"{rv}#{_anchor}" + + return rv + + def make_response(self, rv: ft.ResponseReturnValue) -> Response: + """Convert the return value from a view function to an instance of + :attr:`response_class`. + + :param rv: the return value from the view function. The view function + must return a response. Returning ``None``, or the view ending + without returning, is not allowed. The following types are allowed + for ``view_rv``: + + ``str`` + A response object is created with the string encoded to UTF-8 + as the body. + + ``bytes`` + A response object is created with the bytes as the body. + + ``dict`` + A dictionary that will be jsonify'd before being returned. + + ``list`` + A list that will be jsonify'd before being returned. + + ``generator`` or ``iterator`` + A generator that returns ``str`` or ``bytes`` to be + streamed as the response. + + ``tuple`` + Either ``(body, status, headers)``, ``(body, status)``, or + ``(body, headers)``, where ``body`` is any of the other types + allowed here, ``status`` is a string or an integer, and + ``headers`` is a dictionary or a list of ``(key, value)`` + tuples. If ``body`` is a :attr:`response_class` instance, + ``status`` overwrites the exiting value and ``headers`` are + extended. + + :attr:`response_class` + The object is returned unchanged. + + other :class:`~werkzeug.wrappers.Response` class + The object is coerced to :attr:`response_class`. + + :func:`callable` + The function is called as a WSGI application. The result is + used to create a response object. + + .. versionchanged:: 2.2 + A generator will be converted to a streaming response. + A list will be converted to a JSON response. + + .. versionchanged:: 1.1 + A dict will be converted to a JSON response. + + .. versionchanged:: 0.9 + Previously a tuple was interpreted as the arguments for the + response object. + """ + + status: int | None = None + headers: HeadersValue | None = None + + # unpack tuple returns + if isinstance(rv, tuple): + len_rv = len(rv) + + # a 3-tuple is unpacked directly + if len_rv == 3: + rv, status, headers = rv # type: ignore[misc] + # decide if a 2-tuple has status or headers + elif len_rv == 2: + if isinstance(rv[1], (Headers, dict, tuple, list)): + rv, headers = rv # pyright: ignore + else: + rv, status = rv # type: ignore[assignment,misc] + # other sized tuples are not allowed + else: + raise TypeError( + "The view function did not return a valid response tuple." + " The tuple must have the form (body, status, headers)," + " (body, status), or (body, headers)." + ) + + # the body must not be None + if rv is None: + raise TypeError( + f"The view function for {request.endpoint!r} did not" + " return a valid response. The function either returned" + " None or ended without a return statement." + ) + + # make sure the body is an instance of the response class + if not isinstance(rv, self.response_class): + if isinstance(rv, (str, bytes, bytearray)) or isinstance(rv, cabc.Iterator): + # let the response class set the status and headers instead of + # waiting to do it manually, so that the class can handle any + # special logic + rv = self.response_class( + rv, + status=status, + headers=headers, # type: ignore[arg-type] + ) + status = headers = None + elif isinstance(rv, (dict, list)): + rv = self.json.response(rv) + elif isinstance(rv, BaseResponse) or callable(rv): + # evaluate a WSGI callable, or coerce a different response + # class to the correct type + try: + rv = self.response_class.force_type( + rv, # type: ignore[arg-type] + request.environ, + ) + except TypeError as e: + raise TypeError( + f"{e}\nThe view function did not return a valid" + " response. The return type must be a string," + " dict, list, tuple with headers or status," + " Response instance, or WSGI callable, but it" + f" was a {type(rv).__name__}." + ).with_traceback(sys.exc_info()[2]) from None + else: + raise TypeError( + "The view function did not return a valid" + " response. The return type must be a string," + " dict, list, tuple with headers or status," + " Response instance, or WSGI callable, but it was a" + f" {type(rv).__name__}." + ) + + rv = t.cast(Response, rv) + # prefer the status if it was provided + if status is not None: + if isinstance(status, (str, bytes, bytearray)): + rv.status = status + else: + rv.status_code = status + + # extend existing headers with provided headers + if headers: + rv.headers.update(headers) + + return rv + + def preprocess_request(self) -> ft.ResponseReturnValue | None: + """Called before the request is dispatched. Calls + :attr:`url_value_preprocessors` registered with the app and the + current blueprint (if any). Then calls :attr:`before_request_funcs` + registered with the app and the blueprint. + + If any :meth:`before_request` handler returns a non-None value, the + value is handled as if it was the return value from the view, and + further request handling is stopped. + """ + names = (None, *reversed(request.blueprints)) + + for name in names: + if name in self.url_value_preprocessors: + for url_func in self.url_value_preprocessors[name]: + url_func(request.endpoint, request.view_args) + + for name in names: + if name in self.before_request_funcs: + for before_func in self.before_request_funcs[name]: + rv = self.ensure_sync(before_func)() + + if rv is not None: + return rv # type: ignore[no-any-return] + + return None + + def process_response(self, response: Response) -> Response: + """Can be overridden in order to modify the response object + before it's sent to the WSGI server. By default this will + call all the :meth:`after_request` decorated functions. + + .. versionchanged:: 0.5 + As of Flask 0.5 the functions registered for after request + execution are called in reverse order of registration. + + :param response: a :attr:`response_class` object. + :return: a new response object or the same, has to be an + instance of :attr:`response_class`. + """ + ctx = request_ctx._get_current_object() # type: ignore[attr-defined] + + for func in ctx._after_request_functions: + response = self.ensure_sync(func)(response) + + for name in chain(request.blueprints, (None,)): + if name in self.after_request_funcs: + for func in reversed(self.after_request_funcs[name]): + response = self.ensure_sync(func)(response) + + if not self.session_interface.is_null_session(ctx.session): + self.session_interface.save_session(self, ctx.session, response) + + return response + + def do_teardown_request( + self, + exc: BaseException | None = _sentinel, # type: ignore[assignment] + ) -> None: + """Called after the request is dispatched and the response is + returned, right before the request context is popped. + + This calls all functions decorated with + :meth:`teardown_request`, and :meth:`Blueprint.teardown_request` + if a blueprint handled the request. Finally, the + :data:`request_tearing_down` signal is sent. + + This is called by + :meth:`RequestContext.pop() `, + which may be delayed during testing to maintain access to + resources. + + :param exc: An unhandled exception raised while dispatching the + request. Detected from the current exception information if + not passed. Passed to each teardown function. + + .. versionchanged:: 0.9 + Added the ``exc`` argument. + """ + if exc is _sentinel: + exc = sys.exc_info()[1] + + for name in chain(request.blueprints, (None,)): + if name in self.teardown_request_funcs: + for func in reversed(self.teardown_request_funcs[name]): + self.ensure_sync(func)(exc) + + request_tearing_down.send(self, _async_wrapper=self.ensure_sync, exc=exc) + + def do_teardown_appcontext( + self, + exc: BaseException | None = _sentinel, # type: ignore[assignment] + ) -> None: + """Called right before the application context is popped. + + When handling a request, the application context is popped + after the request context. See :meth:`do_teardown_request`. + + This calls all functions decorated with + :meth:`teardown_appcontext`. Then the + :data:`appcontext_tearing_down` signal is sent. + + This is called by + :meth:`AppContext.pop() `. + + .. versionadded:: 0.9 + """ + if exc is _sentinel: + exc = sys.exc_info()[1] + + for func in reversed(self.teardown_appcontext_funcs): + self.ensure_sync(func)(exc) + + appcontext_tearing_down.send(self, _async_wrapper=self.ensure_sync, exc=exc) + + def app_context(self) -> AppContext: + """Create an :class:`~flask.ctx.AppContext`. Use as a ``with`` + block to push the context, which will make :data:`current_app` + point at this application. + + An application context is automatically pushed by + :meth:`RequestContext.push() ` + when handling a request, and when running a CLI command. Use + this to manually create a context outside of these situations. + + :: + + with app.app_context(): + init_db() + + See :doc:`/appcontext`. + + .. versionadded:: 0.9 + """ + return AppContext(self) + + def request_context(self, environ: WSGIEnvironment) -> RequestContext: + """Create a :class:`~flask.ctx.RequestContext` representing a + WSGI environment. Use a ``with`` block to push the context, + which will make :data:`request` point at this request. + + See :doc:`/reqcontext`. + + Typically you should not call this from your own code. A request + context is automatically pushed by the :meth:`wsgi_app` when + handling a request. Use :meth:`test_request_context` to create + an environment and context instead of this method. + + :param environ: a WSGI environment + """ + return RequestContext(self, environ) + + def test_request_context(self, *args: t.Any, **kwargs: t.Any) -> RequestContext: + """Create a :class:`~flask.ctx.RequestContext` for a WSGI + environment created from the given values. This is mostly useful + during testing, where you may want to run a function that uses + request data without dispatching a full request. + + See :doc:`/reqcontext`. + + Use a ``with`` block to push the context, which will make + :data:`request` point at the request for the created + environment. :: + + with app.test_request_context(...): + generate_report() + + When using the shell, it may be easier to push and pop the + context manually to avoid indentation. :: + + ctx = app.test_request_context(...) + ctx.push() + ... + ctx.pop() + + Takes the same arguments as Werkzeug's + :class:`~werkzeug.test.EnvironBuilder`, with some defaults from + the application. See the linked Werkzeug docs for most of the + available arguments. Flask-specific behavior is listed here. + + :param path: URL path being requested. + :param base_url: Base URL where the app is being served, which + ``path`` is relative to. If not given, built from + :data:`PREFERRED_URL_SCHEME`, ``subdomain``, + :data:`SERVER_NAME`, and :data:`APPLICATION_ROOT`. + :param subdomain: Subdomain name to append to + :data:`SERVER_NAME`. + :param url_scheme: Scheme to use instead of + :data:`PREFERRED_URL_SCHEME`. + :param data: The request body, either as a string or a dict of + form keys and values. + :param json: If given, this is serialized as JSON and passed as + ``data``. Also defaults ``content_type`` to + ``application/json``. + :param args: other positional arguments passed to + :class:`~werkzeug.test.EnvironBuilder`. + :param kwargs: other keyword arguments passed to + :class:`~werkzeug.test.EnvironBuilder`. + """ + from .testing import EnvironBuilder + + builder = EnvironBuilder(self, *args, **kwargs) + + try: + return self.request_context(builder.get_environ()) + finally: + builder.close() + + def wsgi_app( + self, environ: WSGIEnvironment, start_response: StartResponse + ) -> cabc.Iterable[bytes]: + """The actual WSGI application. This is not implemented in + :meth:`__call__` so that middlewares can be applied without + losing a reference to the app object. Instead of doing this:: + + app = MyMiddleware(app) + + It's a better idea to do this instead:: + + app.wsgi_app = MyMiddleware(app.wsgi_app) + + Then you still have the original application object around and + can continue to call methods on it. + + .. versionchanged:: 0.7 + Teardown events for the request and app contexts are called + even if an unhandled error occurs. Other events may not be + called depending on when an error occurs during dispatch. + See :ref:`callbacks-and-errors`. + + :param environ: A WSGI environment. + :param start_response: A callable accepting a status code, + a list of headers, and an optional exception context to + start the response. + """ + ctx = self.request_context(environ) + error: BaseException | None = None + try: + try: + ctx.push() + response = self.full_dispatch_request() + except Exception as e: + error = e + response = self.handle_exception(e) + except: # noqa: B001 + error = sys.exc_info()[1] + raise + return response(environ, start_response) + finally: + if "werkzeug.debug.preserve_context" in environ: + environ["werkzeug.debug.preserve_context"](_cv_app.get()) + environ["werkzeug.debug.preserve_context"](_cv_request.get()) + + if error is not None and self.should_ignore_error(error): + error = None + + ctx.pop(error) + + def __call__( + self, environ: WSGIEnvironment, start_response: StartResponse + ) -> cabc.Iterable[bytes]: + """The WSGI server calls the Flask application object as the + WSGI application. This calls :meth:`wsgi_app`, which can be + wrapped to apply middleware. + """ + return self.wsgi_app(environ, start_response) diff --git a/psets/9/finance/env/lib/python3.12/site-packages/flask/blueprints.py b/psets/9/finance/env/lib/python3.12/site-packages/flask/blueprints.py new file mode 100644 index 0000000..b6d4e43 --- /dev/null +++ b/psets/9/finance/env/lib/python3.12/site-packages/flask/blueprints.py @@ -0,0 +1,128 @@ +from __future__ import annotations + +import os +import typing as t +from datetime import timedelta + +from .cli import AppGroup +from .globals import current_app +from .helpers import send_from_directory +from .sansio.blueprints import Blueprint as SansioBlueprint +from .sansio.blueprints import BlueprintSetupState as BlueprintSetupState # noqa +from .sansio.scaffold import _sentinel + +if t.TYPE_CHECKING: # pragma: no cover + from .wrappers import Response + + +class Blueprint(SansioBlueprint): + def __init__( + self, + name: str, + import_name: str, + static_folder: str | os.PathLike[str] | None = None, + static_url_path: str | None = None, + template_folder: str | os.PathLike[str] | None = None, + url_prefix: str | None = None, + subdomain: str | None = None, + url_defaults: dict[str, t.Any] | None = None, + root_path: str | None = None, + cli_group: str | None = _sentinel, # type: ignore + ) -> None: + super().__init__( + name, + import_name, + static_folder, + static_url_path, + template_folder, + url_prefix, + subdomain, + url_defaults, + root_path, + cli_group, + ) + + #: The Click command group for registering CLI commands for this + #: object. The commands are available from the ``flask`` command + #: once the application has been discovered and blueprints have + #: been registered. + self.cli = AppGroup() + + # Set the name of the Click group in case someone wants to add + # the app's commands to another CLI tool. + self.cli.name = self.name + + def get_send_file_max_age(self, filename: str | None) -> int | None: + """Used by :func:`send_file` to determine the ``max_age`` cache + value for a given file path if it wasn't passed. + + By default, this returns :data:`SEND_FILE_MAX_AGE_DEFAULT` from + the configuration of :data:`~flask.current_app`. This defaults + to ``None``, which tells the browser to use conditional requests + instead of a timed cache, which is usually preferable. + + Note this is a duplicate of the same method in the Flask + class. + + .. versionchanged:: 2.0 + The default configuration is ``None`` instead of 12 hours. + + .. versionadded:: 0.9 + """ + value = current_app.config["SEND_FILE_MAX_AGE_DEFAULT"] + + if value is None: + return None + + if isinstance(value, timedelta): + return int(value.total_seconds()) + + return value # type: ignore[no-any-return] + + def send_static_file(self, filename: str) -> Response: + """The view function used to serve files from + :attr:`static_folder`. A route is automatically registered for + this view at :attr:`static_url_path` if :attr:`static_folder` is + set. + + Note this is a duplicate of the same method in the Flask + class. + + .. versionadded:: 0.5 + + """ + if not self.has_static_folder: + raise RuntimeError("'static_folder' must be set to serve static_files.") + + # send_file only knows to call get_send_file_max_age on the app, + # call it here so it works for blueprints too. + max_age = self.get_send_file_max_age(filename) + return send_from_directory( + t.cast(str, self.static_folder), filename, max_age=max_age + ) + + def open_resource( + self, resource: str, mode: str = "rb", encoding: str | None = "utf-8" + ) -> t.IO[t.AnyStr]: + """Open a resource file relative to :attr:`root_path` for reading. The + blueprint-relative equivalent of the app's :meth:`~.Flask.open_resource` + method. + + :param resource: Path to the resource relative to :attr:`root_path`. + :param mode: Open the file in this mode. Only reading is supported, + valid values are ``"r"`` (or ``"rt"``) and ``"rb"``. + :param encoding: Open the file with this encoding when opening in text + mode. This is ignored when opening in binary mode. + + .. versionchanged:: 3.1 + Added the ``encoding`` parameter. + """ + if mode not in {"r", "rt", "rb"}: + raise ValueError("Resources can only be opened for reading.") + + path = os.path.join(self.root_path, resource) + + if mode == "rb": + return open(path, mode) # pyright: ignore + + return open(path, mode, encoding=encoding) diff --git a/psets/9/finance/env/lib/python3.12/site-packages/flask/cli.py b/psets/9/finance/env/lib/python3.12/site-packages/flask/cli.py new file mode 100644 index 0000000..dd03f3c --- /dev/null +++ b/psets/9/finance/env/lib/python3.12/site-packages/flask/cli.py @@ -0,0 +1,1133 @@ +from __future__ import annotations + +import ast +import collections.abc as cabc +import importlib.metadata +import inspect +import os +import platform +import re +import sys +import traceback +import typing as t +from functools import update_wrapper +from operator import itemgetter +from types import ModuleType + +import click +from click.core import ParameterSource +from werkzeug import run_simple +from werkzeug.serving import is_running_from_reloader +from werkzeug.utils import import_string + +from .globals import current_app +from .helpers import get_debug_flag +from .helpers import get_load_dotenv + +if t.TYPE_CHECKING: + import ssl + + from _typeshed.wsgi import StartResponse + from _typeshed.wsgi import WSGIApplication + from _typeshed.wsgi import WSGIEnvironment + + from .app import Flask + + +class NoAppException(click.UsageError): + """Raised if an application cannot be found or loaded.""" + + +def find_best_app(module: ModuleType) -> Flask: + """Given a module instance this tries to find the best possible + application in the module or raises an exception. + """ + from . import Flask + + # Search for the most common names first. + for attr_name in ("app", "application"): + app = getattr(module, attr_name, None) + + if isinstance(app, Flask): + return app + + # Otherwise find the only object that is a Flask instance. + matches = [v for v in module.__dict__.values() if isinstance(v, Flask)] + + if len(matches) == 1: + return matches[0] + elif len(matches) > 1: + raise NoAppException( + "Detected multiple Flask applications in module" + f" '{module.__name__}'. Use '{module.__name__}:name'" + " to specify the correct one." + ) + + # Search for app factory functions. + for attr_name in ("create_app", "make_app"): + app_factory = getattr(module, attr_name, None) + + if inspect.isfunction(app_factory): + try: + app = app_factory() + + if isinstance(app, Flask): + return app + except TypeError as e: + if not _called_with_wrong_args(app_factory): + raise + + raise NoAppException( + f"Detected factory '{attr_name}' in module '{module.__name__}'," + " but could not call it without arguments. Use" + f" '{module.__name__}:{attr_name}(args)'" + " to specify arguments." + ) from e + + raise NoAppException( + "Failed to find Flask application or factory in module" + f" '{module.__name__}'. Use '{module.__name__}:name'" + " to specify one." + ) + + +def _called_with_wrong_args(f: t.Callable[..., Flask]) -> bool: + """Check whether calling a function raised a ``TypeError`` because + the call failed or because something in the factory raised the + error. + + :param f: The function that was called. + :return: ``True`` if the call failed. + """ + tb = sys.exc_info()[2] + + try: + while tb is not None: + if tb.tb_frame.f_code is f.__code__: + # In the function, it was called successfully. + return False + + tb = tb.tb_next + + # Didn't reach the function. + return True + finally: + # Delete tb to break a circular reference. + # https://docs.python.org/2/library/sys.html#sys.exc_info + del tb + + +def find_app_by_string(module: ModuleType, app_name: str) -> Flask: + """Check if the given string is a variable name or a function. Call + a function to get the app instance, or return the variable directly. + """ + from . import Flask + + # Parse app_name as a single expression to determine if it's a valid + # attribute name or function call. + try: + expr = ast.parse(app_name.strip(), mode="eval").body + except SyntaxError: + raise NoAppException( + f"Failed to parse {app_name!r} as an attribute name or function call." + ) from None + + if isinstance(expr, ast.Name): + name = expr.id + args = [] + kwargs = {} + elif isinstance(expr, ast.Call): + # Ensure the function name is an attribute name only. + if not isinstance(expr.func, ast.Name): + raise NoAppException( + f"Function reference must be a simple name: {app_name!r}." + ) + + name = expr.func.id + + # Parse the positional and keyword arguments as literals. + try: + args = [ast.literal_eval(arg) for arg in expr.args] + kwargs = { + kw.arg: ast.literal_eval(kw.value) + for kw in expr.keywords + if kw.arg is not None + } + except ValueError: + # literal_eval gives cryptic error messages, show a generic + # message with the full expression instead. + raise NoAppException( + f"Failed to parse arguments as literal values: {app_name!r}." + ) from None + else: + raise NoAppException( + f"Failed to parse {app_name!r} as an attribute name or function call." + ) + + try: + attr = getattr(module, name) + except AttributeError as e: + raise NoAppException( + f"Failed to find attribute {name!r} in {module.__name__!r}." + ) from e + + # If the attribute is a function, call it with any args and kwargs + # to get the real application. + if inspect.isfunction(attr): + try: + app = attr(*args, **kwargs) + except TypeError as e: + if not _called_with_wrong_args(attr): + raise + + raise NoAppException( + f"The factory {app_name!r} in module" + f" {module.__name__!r} could not be called with the" + " specified arguments." + ) from e + else: + app = attr + + if isinstance(app, Flask): + return app + + raise NoAppException( + "A valid Flask application was not obtained from" + f" '{module.__name__}:{app_name}'." + ) + + +def prepare_import(path: str) -> str: + """Given a filename this will try to calculate the python path, add it + to the search path and return the actual module name that is expected. + """ + path = os.path.realpath(path) + + fname, ext = os.path.splitext(path) + if ext == ".py": + path = fname + + if os.path.basename(path) == "__init__": + path = os.path.dirname(path) + + module_name = [] + + # move up until outside package structure (no __init__.py) + while True: + path, name = os.path.split(path) + module_name.append(name) + + if not os.path.exists(os.path.join(path, "__init__.py")): + break + + if sys.path[0] != path: + sys.path.insert(0, path) + + return ".".join(module_name[::-1]) + + +@t.overload +def locate_app( + module_name: str, app_name: str | None, raise_if_not_found: t.Literal[True] = True +) -> Flask: ... + + +@t.overload +def locate_app( + module_name: str, app_name: str | None, raise_if_not_found: t.Literal[False] = ... +) -> Flask | None: ... + + +def locate_app( + module_name: str, app_name: str | None, raise_if_not_found: bool = True +) -> Flask | None: + try: + __import__(module_name) + except ImportError: + # Reraise the ImportError if it occurred within the imported module. + # Determine this by checking whether the trace has a depth > 1. + if sys.exc_info()[2].tb_next: # type: ignore[union-attr] + raise NoAppException( + f"While importing {module_name!r}, an ImportError was" + f" raised:\n\n{traceback.format_exc()}" + ) from None + elif raise_if_not_found: + raise NoAppException(f"Could not import {module_name!r}.") from None + else: + return None + + module = sys.modules[module_name] + + if app_name is None: + return find_best_app(module) + else: + return find_app_by_string(module, app_name) + + +def get_version(ctx: click.Context, param: click.Parameter, value: t.Any) -> None: + if not value or ctx.resilient_parsing: + return + + flask_version = importlib.metadata.version("flask") + werkzeug_version = importlib.metadata.version("werkzeug") + + click.echo( + f"Python {platform.python_version()}\n" + f"Flask {flask_version}\n" + f"Werkzeug {werkzeug_version}", + color=ctx.color, + ) + ctx.exit() + + +version_option = click.Option( + ["--version"], + help="Show the Flask version.", + expose_value=False, + callback=get_version, + is_flag=True, + is_eager=True, +) + + +class ScriptInfo: + """Helper object to deal with Flask applications. This is usually not + necessary to interface with as it's used internally in the dispatching + to click. In future versions of Flask this object will most likely play + a bigger role. Typically it's created automatically by the + :class:`FlaskGroup` but you can also manually create it and pass it + onwards as click object. + + .. versionchanged:: 3.1 + Added the ``load_dotenv_defaults`` parameter and attribute. + """ + + def __init__( + self, + app_import_path: str | None = None, + create_app: t.Callable[..., Flask] | None = None, + set_debug_flag: bool = True, + load_dotenv_defaults: bool = True, + ) -> None: + #: Optionally the import path for the Flask application. + self.app_import_path = app_import_path + #: Optionally a function that is passed the script info to create + #: the instance of the application. + self.create_app = create_app + #: A dictionary with arbitrary data that can be associated with + #: this script info. + self.data: dict[t.Any, t.Any] = {} + self.set_debug_flag = set_debug_flag + + self.load_dotenv_defaults = get_load_dotenv(load_dotenv_defaults) + """Whether default ``.flaskenv`` and ``.env`` files should be loaded. + + ``ScriptInfo`` doesn't load anything, this is for reference when doing + the load elsewhere during processing. + + .. versionadded:: 3.1 + """ + + self._loaded_app: Flask | None = None + + def load_app(self) -> Flask: + """Loads the Flask app (if not yet loaded) and returns it. Calling + this multiple times will just result in the already loaded app to + be returned. + """ + if self._loaded_app is not None: + return self._loaded_app + app: Flask | None = None + if self.create_app is not None: + app = self.create_app() + else: + if self.app_import_path: + path, name = ( + re.split(r":(?![\\/])", self.app_import_path, maxsplit=1) + [None] + )[:2] + import_name = prepare_import(path) + app = locate_app(import_name, name) + else: + for path in ("wsgi.py", "app.py"): + import_name = prepare_import(path) + app = locate_app(import_name, None, raise_if_not_found=False) + + if app is not None: + break + + if app is None: + raise NoAppException( + "Could not locate a Flask application. Use the" + " 'flask --app' option, 'FLASK_APP' environment" + " variable, or a 'wsgi.py' or 'app.py' file in the" + " current directory." + ) + + if self.set_debug_flag: + # Update the app's debug flag through the descriptor so that + # other values repopulate as well. + app.debug = get_debug_flag() + + self._loaded_app = app + return app + + +pass_script_info = click.make_pass_decorator(ScriptInfo, ensure=True) + +F = t.TypeVar("F", bound=t.Callable[..., t.Any]) + + +def with_appcontext(f: F) -> F: + """Wraps a callback so that it's guaranteed to be executed with the + script's application context. + + Custom commands (and their options) registered under ``app.cli`` or + ``blueprint.cli`` will always have an app context available, this + decorator is not required in that case. + + .. versionchanged:: 2.2 + The app context is active for subcommands as well as the + decorated callback. The app context is always available to + ``app.cli`` command and parameter callbacks. + """ + + @click.pass_context + def decorator(ctx: click.Context, /, *args: t.Any, **kwargs: t.Any) -> t.Any: + if not current_app: + app = ctx.ensure_object(ScriptInfo).load_app() + ctx.with_resource(app.app_context()) + + return ctx.invoke(f, *args, **kwargs) + + return update_wrapper(decorator, f) # type: ignore[return-value] + + +class AppGroup(click.Group): + """This works similar to a regular click :class:`~click.Group` but it + changes the behavior of the :meth:`command` decorator so that it + automatically wraps the functions in :func:`with_appcontext`. + + Not to be confused with :class:`FlaskGroup`. + """ + + def command( # type: ignore[override] + self, *args: t.Any, **kwargs: t.Any + ) -> t.Callable[[t.Callable[..., t.Any]], click.Command]: + """This works exactly like the method of the same name on a regular + :class:`click.Group` but it wraps callbacks in :func:`with_appcontext` + unless it's disabled by passing ``with_appcontext=False``. + """ + wrap_for_ctx = kwargs.pop("with_appcontext", True) + + def decorator(f: t.Callable[..., t.Any]) -> click.Command: + if wrap_for_ctx: + f = with_appcontext(f) + return super(AppGroup, self).command(*args, **kwargs)(f) # type: ignore[no-any-return] + + return decorator + + def group( # type: ignore[override] + self, *args: t.Any, **kwargs: t.Any + ) -> t.Callable[[t.Callable[..., t.Any]], click.Group]: + """This works exactly like the method of the same name on a regular + :class:`click.Group` but it defaults the group class to + :class:`AppGroup`. + """ + kwargs.setdefault("cls", AppGroup) + return super().group(*args, **kwargs) # type: ignore[no-any-return] + + +def _set_app(ctx: click.Context, param: click.Option, value: str | None) -> str | None: + if value is None: + return None + + info = ctx.ensure_object(ScriptInfo) + info.app_import_path = value + return value + + +# This option is eager so the app will be available if --help is given. +# --help is also eager, so --app must be before it in the param list. +# no_args_is_help bypasses eager processing, so this option must be +# processed manually in that case to ensure FLASK_APP gets picked up. +_app_option = click.Option( + ["-A", "--app"], + metavar="IMPORT", + help=( + "The Flask application or factory function to load, in the form 'module:name'." + " Module can be a dotted import or file path. Name is not required if it is" + " 'app', 'application', 'create_app', or 'make_app', and can be 'name(args)' to" + " pass arguments." + ), + is_eager=True, + expose_value=False, + callback=_set_app, +) + + +def _set_debug(ctx: click.Context, param: click.Option, value: bool) -> bool | None: + # If the flag isn't provided, it will default to False. Don't use + # that, let debug be set by env in that case. + source = ctx.get_parameter_source(param.name) # type: ignore[arg-type] + + if source is not None and source in ( + ParameterSource.DEFAULT, + ParameterSource.DEFAULT_MAP, + ): + return None + + # Set with env var instead of ScriptInfo.load so that it can be + # accessed early during a factory function. + os.environ["FLASK_DEBUG"] = "1" if value else "0" + return value + + +_debug_option = click.Option( + ["--debug/--no-debug"], + help="Set debug mode.", + expose_value=False, + callback=_set_debug, +) + + +def _env_file_callback( + ctx: click.Context, param: click.Option, value: str | None +) -> str | None: + try: + import dotenv # noqa: F401 + except ImportError: + # Only show an error if a value was passed, otherwise we still want to + # call load_dotenv and show a message without exiting. + if value is not None: + raise click.BadParameter( + "python-dotenv must be installed to load an env file.", + ctx=ctx, + param=param, + ) from None + + # Load if a value was passed, or we want to load default files, or both. + if value is not None or ctx.obj.load_dotenv_defaults: + load_dotenv(value, load_defaults=ctx.obj.load_dotenv_defaults) + + return value + + +# This option is eager so env vars are loaded as early as possible to be +# used by other options. +_env_file_option = click.Option( + ["-e", "--env-file"], + type=click.Path(exists=True, dir_okay=False), + help=( + "Load environment variables from this file, taking precedence over" + " those set by '.env' and '.flaskenv'. Variables set directly in the" + " environment take highest precedence. python-dotenv must be installed." + ), + is_eager=True, + expose_value=False, + callback=_env_file_callback, +) + + +class FlaskGroup(AppGroup): + """Special subclass of the :class:`AppGroup` group that supports + loading more commands from the configured Flask app. Normally a + developer does not have to interface with this class but there are + some very advanced use cases for which it makes sense to create an + instance of this. see :ref:`custom-scripts`. + + :param add_default_commands: if this is True then the default run and + shell commands will be added. + :param add_version_option: adds the ``--version`` option. + :param create_app: an optional callback that is passed the script info and + returns the loaded app. + :param load_dotenv: Load the nearest :file:`.env` and :file:`.flaskenv` + files to set environment variables. Will also change the working + directory to the directory containing the first file found. + :param set_debug_flag: Set the app's debug flag. + + .. versionchanged:: 3.1 + ``-e path`` takes precedence over default ``.env`` and ``.flaskenv`` files. + + .. versionchanged:: 2.2 + Added the ``-A/--app``, ``--debug/--no-debug``, ``-e/--env-file`` options. + + .. versionchanged:: 2.2 + An app context is pushed when running ``app.cli`` commands, so + ``@with_appcontext`` is no longer required for those commands. + + .. versionchanged:: 1.0 + If installed, python-dotenv will be used to load environment variables + from :file:`.env` and :file:`.flaskenv` files. + """ + + def __init__( + self, + add_default_commands: bool = True, + create_app: t.Callable[..., Flask] | None = None, + add_version_option: bool = True, + load_dotenv: bool = True, + set_debug_flag: bool = True, + **extra: t.Any, + ) -> None: + params: list[click.Parameter] = list(extra.pop("params", None) or ()) + # Processing is done with option callbacks instead of a group + # callback. This allows users to make a custom group callback + # without losing the behavior. --env-file must come first so + # that it is eagerly evaluated before --app. + params.extend((_env_file_option, _app_option, _debug_option)) + + if add_version_option: + params.append(version_option) + + if "context_settings" not in extra: + extra["context_settings"] = {} + + extra["context_settings"].setdefault("auto_envvar_prefix", "FLASK") + + super().__init__(params=params, **extra) + + self.create_app = create_app + self.load_dotenv = load_dotenv + self.set_debug_flag = set_debug_flag + + if add_default_commands: + self.add_command(run_command) + self.add_command(shell_command) + self.add_command(routes_command) + + self._loaded_plugin_commands = False + + def _load_plugin_commands(self) -> None: + if self._loaded_plugin_commands: + return + + if sys.version_info >= (3, 10): + from importlib import metadata + else: + # Use a backport on Python < 3.10. We technically have + # importlib.metadata on 3.8+, but the API changed in 3.10, + # so use the backport for consistency. + import importlib_metadata as metadata # pyright: ignore + + for ep in metadata.entry_points(group="flask.commands"): + self.add_command(ep.load(), ep.name) + + self._loaded_plugin_commands = True + + def get_command(self, ctx: click.Context, name: str) -> click.Command | None: + self._load_plugin_commands() + # Look up built-in and plugin commands, which should be + # available even if the app fails to load. + rv = super().get_command(ctx, name) + + if rv is not None: + return rv + + info = ctx.ensure_object(ScriptInfo) + + # Look up commands provided by the app, showing an error and + # continuing if the app couldn't be loaded. + try: + app = info.load_app() + except NoAppException as e: + click.secho(f"Error: {e.format_message()}\n", err=True, fg="red") + return None + + # Push an app context for the loaded app unless it is already + # active somehow. This makes the context available to parameter + # and command callbacks without needing @with_appcontext. + if not current_app or current_app._get_current_object() is not app: # type: ignore[attr-defined] + ctx.with_resource(app.app_context()) + + return app.cli.get_command(ctx, name) + + def list_commands(self, ctx: click.Context) -> list[str]: + self._load_plugin_commands() + # Start with the built-in and plugin commands. + rv = set(super().list_commands(ctx)) + info = ctx.ensure_object(ScriptInfo) + + # Add commands provided by the app, showing an error and + # continuing if the app couldn't be loaded. + try: + rv.update(info.load_app().cli.list_commands(ctx)) + except NoAppException as e: + # When an app couldn't be loaded, show the error message + # without the traceback. + click.secho(f"Error: {e.format_message()}\n", err=True, fg="red") + except Exception: + # When any other errors occurred during loading, show the + # full traceback. + click.secho(f"{traceback.format_exc()}\n", err=True, fg="red") + + return sorted(rv) + + def make_context( + self, + info_name: str | None, + args: list[str], + parent: click.Context | None = None, + **extra: t.Any, + ) -> click.Context: + # Set a flag to tell app.run to become a no-op. If app.run was + # not in a __name__ == __main__ guard, it would start the server + # when importing, blocking whatever command is being called. + os.environ["FLASK_RUN_FROM_CLI"] = "true" + + if "obj" not in extra and "obj" not in self.context_settings: + extra["obj"] = ScriptInfo( + create_app=self.create_app, + set_debug_flag=self.set_debug_flag, + load_dotenv_defaults=self.load_dotenv, + ) + + return super().make_context(info_name, args, parent=parent, **extra) + + def parse_args(self, ctx: click.Context, args: list[str]) -> list[str]: + if not args and self.no_args_is_help: + # Attempt to load --env-file and --app early in case they + # were given as env vars. Otherwise no_args_is_help will not + # see commands from app.cli. + _env_file_option.handle_parse_result(ctx, {}, []) + _app_option.handle_parse_result(ctx, {}, []) + + return super().parse_args(ctx, args) + + +def _path_is_ancestor(path: str, other: str) -> bool: + """Take ``other`` and remove the length of ``path`` from it. Then join it + to ``path``. If it is the original value, ``path`` is an ancestor of + ``other``.""" + return os.path.join(path, other[len(path) :].lstrip(os.sep)) == other + + +def load_dotenv( + path: str | os.PathLike[str] | None = None, load_defaults: bool = True +) -> bool: + """Load "dotenv" files to set environment variables. A given path takes + precedence over ``.env``, which takes precedence over ``.flaskenv``. After + loading and combining these files, values are only set if the key is not + already set in ``os.environ``. + + This is a no-op if `python-dotenv`_ is not installed. + + .. _python-dotenv: https://github.com/theskumar/python-dotenv#readme + + :param path: Load the file at this location. + :param load_defaults: Search for and load the default ``.flaskenv`` and + ``.env`` files. + :return: ``True`` if at least one env var was loaded. + + .. versionchanged:: 3.1 + Added the ``load_defaults`` parameter. A given path takes precedence + over default files. + + .. versionchanged:: 2.0 + The current directory is not changed to the location of the + loaded file. + + .. versionchanged:: 2.0 + When loading the env files, set the default encoding to UTF-8. + + .. versionchanged:: 1.1.0 + Returns ``False`` when python-dotenv is not installed, or when + the given path isn't a file. + + .. versionadded:: 1.0 + """ + try: + import dotenv + except ImportError: + if path or os.path.isfile(".env") or os.path.isfile(".flaskenv"): + click.secho( + " * Tip: There are .env files present. Install python-dotenv" + " to use them.", + fg="yellow", + err=True, + ) + + return False + + data: dict[str, str | None] = {} + + if load_defaults: + for default_name in (".flaskenv", ".env"): + if not (default_path := dotenv.find_dotenv(default_name, usecwd=True)): + continue + + data |= dotenv.dotenv_values(default_path, encoding="utf-8") + + if path is not None and os.path.isfile(path): + data |= dotenv.dotenv_values(path, encoding="utf-8") + + for key, value in data.items(): + if key in os.environ or value is None: + continue + + os.environ[key] = value + + return bool(data) # True if at least one env var was loaded. + + +def show_server_banner(debug: bool, app_import_path: str | None) -> None: + """Show extra startup messages the first time the server is run, + ignoring the reloader. + """ + if is_running_from_reloader(): + return + + if app_import_path is not None: + click.echo(f" * Serving Flask app '{app_import_path}'") + + if debug is not None: + click.echo(f" * Debug mode: {'on' if debug else 'off'}") + + +class CertParamType(click.ParamType): + """Click option type for the ``--cert`` option. Allows either an + existing file, the string ``'adhoc'``, or an import for a + :class:`~ssl.SSLContext` object. + """ + + name = "path" + + def __init__(self) -> None: + self.path_type = click.Path(exists=True, dir_okay=False, resolve_path=True) + + def convert( + self, value: t.Any, param: click.Parameter | None, ctx: click.Context | None + ) -> t.Any: + try: + import ssl + except ImportError: + raise click.BadParameter( + 'Using "--cert" requires Python to be compiled with SSL support.', + ctx, + param, + ) from None + + try: + return self.path_type(value, param, ctx) + except click.BadParameter: + value = click.STRING(value, param, ctx).lower() + + if value == "adhoc": + try: + import cryptography # noqa: F401 + except ImportError: + raise click.BadParameter( + "Using ad-hoc certificates requires the cryptography library.", + ctx, + param, + ) from None + + return value + + obj = import_string(value, silent=True) + + if isinstance(obj, ssl.SSLContext): + return obj + + raise + + +def _validate_key(ctx: click.Context, param: click.Parameter, value: t.Any) -> t.Any: + """The ``--key`` option must be specified when ``--cert`` is a file. + Modifies the ``cert`` param to be a ``(cert, key)`` pair if needed. + """ + cert = ctx.params.get("cert") + is_adhoc = cert == "adhoc" + + try: + import ssl + except ImportError: + is_context = False + else: + is_context = isinstance(cert, ssl.SSLContext) + + if value is not None: + if is_adhoc: + raise click.BadParameter( + 'When "--cert" is "adhoc", "--key" is not used.', ctx, param + ) + + if is_context: + raise click.BadParameter( + 'When "--cert" is an SSLContext object, "--key" is not used.', + ctx, + param, + ) + + if not cert: + raise click.BadParameter('"--cert" must also be specified.', ctx, param) + + ctx.params["cert"] = cert, value + + else: + if cert and not (is_adhoc or is_context): + raise click.BadParameter('Required when using "--cert".', ctx, param) + + return value + + +class SeparatedPathType(click.Path): + """Click option type that accepts a list of values separated by the + OS's path separator (``:``, ``;`` on Windows). Each value is + validated as a :class:`click.Path` type. + """ + + def convert( + self, value: t.Any, param: click.Parameter | None, ctx: click.Context | None + ) -> t.Any: + items = self.split_envvar_value(value) + # can't call no-arg super() inside list comprehension until Python 3.12 + super_convert = super().convert + return [super_convert(item, param, ctx) for item in items] + + +@click.command("run", short_help="Run a development server.") +@click.option("--host", "-h", default="127.0.0.1", help="The interface to bind to.") +@click.option("--port", "-p", default=5000, help="The port to bind to.") +@click.option( + "--cert", + type=CertParamType(), + help="Specify a certificate file to use HTTPS.", + is_eager=True, +) +@click.option( + "--key", + type=click.Path(exists=True, dir_okay=False, resolve_path=True), + callback=_validate_key, + expose_value=False, + help="The key file to use when specifying a certificate.", +) +@click.option( + "--reload/--no-reload", + default=None, + help="Enable or disable the reloader. By default the reloader " + "is active if debug is enabled.", +) +@click.option( + "--debugger/--no-debugger", + default=None, + help="Enable or disable the debugger. By default the debugger " + "is active if debug is enabled.", +) +@click.option( + "--with-threads/--without-threads", + default=True, + help="Enable or disable multithreading.", +) +@click.option( + "--extra-files", + default=None, + type=SeparatedPathType(), + help=( + "Extra files that trigger a reload on change. Multiple paths" + f" are separated by {os.path.pathsep!r}." + ), +) +@click.option( + "--exclude-patterns", + default=None, + type=SeparatedPathType(), + help=( + "Files matching these fnmatch patterns will not trigger a reload" + " on change. Multiple patterns are separated by" + f" {os.path.pathsep!r}." + ), +) +@pass_script_info +def run_command( + info: ScriptInfo, + host: str, + port: int, + reload: bool, + debugger: bool, + with_threads: bool, + cert: ssl.SSLContext | tuple[str, str | None] | t.Literal["adhoc"] | None, + extra_files: list[str] | None, + exclude_patterns: list[str] | None, +) -> None: + """Run a local development server. + + This server is for development purposes only. It does not provide + the stability, security, or performance of production WSGI servers. + + The reloader and debugger are enabled by default with the '--debug' + option. + """ + try: + app: WSGIApplication = info.load_app() # pyright: ignore + except Exception as e: + if is_running_from_reloader(): + # When reloading, print out the error immediately, but raise + # it later so the debugger or server can handle it. + traceback.print_exc() + err = e + + def app( + environ: WSGIEnvironment, start_response: StartResponse + ) -> cabc.Iterable[bytes]: + raise err from None + + else: + # When not reloading, raise the error immediately so the + # command fails. + raise e from None + + debug = get_debug_flag() + + if reload is None: + reload = debug + + if debugger is None: + debugger = debug + + show_server_banner(debug, info.app_import_path) + + run_simple( + host, + port, + app, + use_reloader=reload, + use_debugger=debugger, + threaded=with_threads, + ssl_context=cert, + extra_files=extra_files, + exclude_patterns=exclude_patterns, + ) + + +run_command.params.insert(0, _debug_option) + + +@click.command("shell", short_help="Run a shell in the app context.") +@with_appcontext +def shell_command() -> None: + """Run an interactive Python shell in the context of a given + Flask application. The application will populate the default + namespace of this shell according to its configuration. + + This is useful for executing small snippets of management code + without having to manually configure the application. + """ + import code + + banner = ( + f"Python {sys.version} on {sys.platform}\n" + f"App: {current_app.import_name}\n" + f"Instance: {current_app.instance_path}" + ) + ctx: dict[str, t.Any] = {} + + # Support the regular Python interpreter startup script if someone + # is using it. + startup = os.environ.get("PYTHONSTARTUP") + if startup and os.path.isfile(startup): + with open(startup) as f: + eval(compile(f.read(), startup, "exec"), ctx) + + ctx.update(current_app.make_shell_context()) + + # Site, customize, or startup script can set a hook to call when + # entering interactive mode. The default one sets up readline with + # tab and history completion. + interactive_hook = getattr(sys, "__interactivehook__", None) + + if interactive_hook is not None: + try: + import readline + from rlcompleter import Completer + except ImportError: + pass + else: + # rlcompleter uses __main__.__dict__ by default, which is + # flask.__main__. Use the shell context instead. + readline.set_completer(Completer(ctx).complete) + + interactive_hook() + + code.interact(banner=banner, local=ctx) + + +@click.command("routes", short_help="Show the routes for the app.") +@click.option( + "--sort", + "-s", + type=click.Choice(("endpoint", "methods", "domain", "rule", "match")), + default="endpoint", + help=( + "Method to sort routes by. 'match' is the order that Flask will match routes" + " when dispatching a request." + ), +) +@click.option("--all-methods", is_flag=True, help="Show HEAD and OPTIONS methods.") +@with_appcontext +def routes_command(sort: str, all_methods: bool) -> None: + """Show all registered routes with endpoints and methods.""" + rules = list(current_app.url_map.iter_rules()) + + if not rules: + click.echo("No routes were registered.") + return + + ignored_methods = set() if all_methods else {"HEAD", "OPTIONS"} + host_matching = current_app.url_map.host_matching + has_domain = any(rule.host if host_matching else rule.subdomain for rule in rules) + rows = [] + + for rule in rules: + row = [ + rule.endpoint, + ", ".join(sorted((rule.methods or set()) - ignored_methods)), + ] + + if has_domain: + row.append((rule.host if host_matching else rule.subdomain) or "") + + row.append(rule.rule) + rows.append(row) + + headers = ["Endpoint", "Methods"] + sorts = ["endpoint", "methods"] + + if has_domain: + headers.append("Host" if host_matching else "Subdomain") + sorts.append("domain") + + headers.append("Rule") + sorts.append("rule") + + try: + rows.sort(key=itemgetter(sorts.index(sort))) + except ValueError: + pass + + rows.insert(0, headers) + widths = [max(len(row[i]) for row in rows) for i in range(len(headers))] + rows.insert(1, ["-" * w for w in widths]) + template = " ".join(f"{{{i}:<{w}}}" for i, w in enumerate(widths)) + + for row in rows: + click.echo(template.format(*row)) + + +cli = FlaskGroup( + name="flask", + help="""\ +A general utility script for Flask applications. + +An application to load must be given with the '--app' option, +'FLASK_APP' environment variable, or with a 'wsgi.py' or 'app.py' file +in the current directory. +""", +) + + +def main() -> None: + cli.main() + + +if __name__ == "__main__": + main() diff --git a/psets/9/finance/env/lib/python3.12/site-packages/flask/config.py b/psets/9/finance/env/lib/python3.12/site-packages/flask/config.py new file mode 100644 index 0000000..34ef1a5 --- /dev/null +++ b/psets/9/finance/env/lib/python3.12/site-packages/flask/config.py @@ -0,0 +1,367 @@ +from __future__ import annotations + +import errno +import json +import os +import types +import typing as t + +from werkzeug.utils import import_string + +if t.TYPE_CHECKING: + import typing_extensions as te + + from .sansio.app import App + + +T = t.TypeVar("T") + + +class ConfigAttribute(t.Generic[T]): + """Makes an attribute forward to the config""" + + def __init__( + self, name: str, get_converter: t.Callable[[t.Any], T] | None = None + ) -> None: + self.__name__ = name + self.get_converter = get_converter + + @t.overload + def __get__(self, obj: None, owner: None) -> te.Self: ... + + @t.overload + def __get__(self, obj: App, owner: type[App]) -> T: ... + + def __get__(self, obj: App | None, owner: type[App] | None = None) -> T | te.Self: + if obj is None: + return self + + rv = obj.config[self.__name__] + + if self.get_converter is not None: + rv = self.get_converter(rv) + + return rv # type: ignore[no-any-return] + + def __set__(self, obj: App, value: t.Any) -> None: + obj.config[self.__name__] = value + + +class Config(dict): # type: ignore[type-arg] + """Works exactly like a dict but provides ways to fill it from files + or special dictionaries. There are two common patterns to populate the + config. + + Either you can fill the config from a config file:: + + app.config.from_pyfile('yourconfig.cfg') + + Or alternatively you can define the configuration options in the + module that calls :meth:`from_object` or provide an import path to + a module that should be loaded. It is also possible to tell it to + use the same module and with that provide the configuration values + just before the call:: + + DEBUG = True + SECRET_KEY = 'development key' + app.config.from_object(__name__) + + In both cases (loading from any Python file or loading from modules), + only uppercase keys are added to the config. This makes it possible to use + lowercase values in the config file for temporary values that are not added + to the config or to define the config keys in the same file that implements + the application. + + Probably the most interesting way to load configurations is from an + environment variable pointing to a file:: + + app.config.from_envvar('YOURAPPLICATION_SETTINGS') + + In this case before launching the application you have to set this + environment variable to the file you want to use. On Linux and OS X + use the export statement:: + + export YOURAPPLICATION_SETTINGS='/path/to/config/file' + + On windows use `set` instead. + + :param root_path: path to which files are read relative from. When the + config object is created by the application, this is + the application's :attr:`~flask.Flask.root_path`. + :param defaults: an optional dictionary of default values + """ + + def __init__( + self, + root_path: str | os.PathLike[str], + defaults: dict[str, t.Any] | None = None, + ) -> None: + super().__init__(defaults or {}) + self.root_path = root_path + + def from_envvar(self, variable_name: str, silent: bool = False) -> bool: + """Loads a configuration from an environment variable pointing to + a configuration file. This is basically just a shortcut with nicer + error messages for this line of code:: + + app.config.from_pyfile(os.environ['YOURAPPLICATION_SETTINGS']) + + :param variable_name: name of the environment variable + :param silent: set to ``True`` if you want silent failure for missing + files. + :return: ``True`` if the file was loaded successfully. + """ + rv = os.environ.get(variable_name) + if not rv: + if silent: + return False + raise RuntimeError( + f"The environment variable {variable_name!r} is not set" + " and as such configuration could not be loaded. Set" + " this variable and make it point to a configuration" + " file" + ) + return self.from_pyfile(rv, silent=silent) + + def from_prefixed_env( + self, prefix: str = "FLASK", *, loads: t.Callable[[str], t.Any] = json.loads + ) -> bool: + """Load any environment variables that start with ``FLASK_``, + dropping the prefix from the env key for the config key. Values + are passed through a loading function to attempt to convert them + to more specific types than strings. + + Keys are loaded in :func:`sorted` order. + + The default loading function attempts to parse values as any + valid JSON type, including dicts and lists. + + Specific items in nested dicts can be set by separating the + keys with double underscores (``__``). If an intermediate key + doesn't exist, it will be initialized to an empty dict. + + :param prefix: Load env vars that start with this prefix, + separated with an underscore (``_``). + :param loads: Pass each string value to this function and use + the returned value as the config value. If any error is + raised it is ignored and the value remains a string. The + default is :func:`json.loads`. + + .. versionadded:: 2.1 + """ + prefix = f"{prefix}_" + + for key in sorted(os.environ): + if not key.startswith(prefix): + continue + + value = os.environ[key] + key = key.removeprefix(prefix) + + try: + value = loads(value) + except Exception: + # Keep the value as a string if loading failed. + pass + + if "__" not in key: + # A non-nested key, set directly. + self[key] = value + continue + + # Traverse nested dictionaries with keys separated by "__". + current = self + *parts, tail = key.split("__") + + for part in parts: + # If an intermediate dict does not exist, create it. + if part not in current: + current[part] = {} + + current = current[part] + + current[tail] = value + + return True + + def from_pyfile( + self, filename: str | os.PathLike[str], silent: bool = False + ) -> bool: + """Updates the values in the config from a Python file. This function + behaves as if the file was imported as module with the + :meth:`from_object` function. + + :param filename: the filename of the config. This can either be an + absolute filename or a filename relative to the + root path. + :param silent: set to ``True`` if you want silent failure for missing + files. + :return: ``True`` if the file was loaded successfully. + + .. versionadded:: 0.7 + `silent` parameter. + """ + filename = os.path.join(self.root_path, filename) + d = types.ModuleType("config") + d.__file__ = filename + try: + with open(filename, mode="rb") as config_file: + exec(compile(config_file.read(), filename, "exec"), d.__dict__) + except OSError as e: + if silent and e.errno in (errno.ENOENT, errno.EISDIR, errno.ENOTDIR): + return False + e.strerror = f"Unable to load configuration file ({e.strerror})" + raise + self.from_object(d) + return True + + def from_object(self, obj: object | str) -> None: + """Updates the values from the given object. An object can be of one + of the following two types: + + - a string: in this case the object with that name will be imported + - an actual object reference: that object is used directly + + Objects are usually either modules or classes. :meth:`from_object` + loads only the uppercase attributes of the module/class. A ``dict`` + object will not work with :meth:`from_object` because the keys of a + ``dict`` are not attributes of the ``dict`` class. + + Example of module-based configuration:: + + app.config.from_object('yourapplication.default_config') + from yourapplication import default_config + app.config.from_object(default_config) + + Nothing is done to the object before loading. If the object is a + class and has ``@property`` attributes, it needs to be + instantiated before being passed to this method. + + You should not use this function to load the actual configuration but + rather configuration defaults. The actual config should be loaded + with :meth:`from_pyfile` and ideally from a location not within the + package because the package might be installed system wide. + + See :ref:`config-dev-prod` for an example of class-based configuration + using :meth:`from_object`. + + :param obj: an import name or object + """ + if isinstance(obj, str): + obj = import_string(obj) + for key in dir(obj): + if key.isupper(): + self[key] = getattr(obj, key) + + def from_file( + self, + filename: str | os.PathLike[str], + load: t.Callable[[t.IO[t.Any]], t.Mapping[str, t.Any]], + silent: bool = False, + text: bool = True, + ) -> bool: + """Update the values in the config from a file that is loaded + using the ``load`` parameter. The loaded data is passed to the + :meth:`from_mapping` method. + + .. code-block:: python + + import json + app.config.from_file("config.json", load=json.load) + + import tomllib + app.config.from_file("config.toml", load=tomllib.load, text=False) + + :param filename: The path to the data file. This can be an + absolute path or relative to the config root path. + :param load: A callable that takes a file handle and returns a + mapping of loaded data from the file. + :type load: ``Callable[[Reader], Mapping]`` where ``Reader`` + implements a ``read`` method. + :param silent: Ignore the file if it doesn't exist. + :param text: Open the file in text or binary mode. + :return: ``True`` if the file was loaded successfully. + + .. versionchanged:: 2.3 + The ``text`` parameter was added. + + .. versionadded:: 2.0 + """ + filename = os.path.join(self.root_path, filename) + + try: + with open(filename, "r" if text else "rb") as f: + obj = load(f) + except OSError as e: + if silent and e.errno in (errno.ENOENT, errno.EISDIR): + return False + + e.strerror = f"Unable to load configuration file ({e.strerror})" + raise + + return self.from_mapping(obj) + + def from_mapping( + self, mapping: t.Mapping[str, t.Any] | None = None, **kwargs: t.Any + ) -> bool: + """Updates the config like :meth:`update` ignoring items with + non-upper keys. + + :return: Always returns ``True``. + + .. versionadded:: 0.11 + """ + mappings: dict[str, t.Any] = {} + if mapping is not None: + mappings.update(mapping) + mappings.update(kwargs) + for key, value in mappings.items(): + if key.isupper(): + self[key] = value + return True + + def get_namespace( + self, namespace: str, lowercase: bool = True, trim_namespace: bool = True + ) -> dict[str, t.Any]: + """Returns a dictionary containing a subset of configuration options + that match the specified namespace/prefix. Example usage:: + + app.config['IMAGE_STORE_TYPE'] = 'fs' + app.config['IMAGE_STORE_PATH'] = '/var/app/images' + app.config['IMAGE_STORE_BASE_URL'] = 'http://img.website.com' + image_store_config = app.config.get_namespace('IMAGE_STORE_') + + The resulting dictionary `image_store_config` would look like:: + + { + 'type': 'fs', + 'path': '/var/app/images', + 'base_url': 'http://img.website.com' + } + + This is often useful when configuration options map directly to + keyword arguments in functions or class constructors. + + :param namespace: a configuration namespace + :param lowercase: a flag indicating if the keys of the resulting + dictionary should be lowercase + :param trim_namespace: a flag indicating if the keys of the resulting + dictionary should not include the namespace + + .. versionadded:: 0.11 + """ + rv = {} + for k, v in self.items(): + if not k.startswith(namespace): + continue + if trim_namespace: + key = k[len(namespace) :] + else: + key = k + if lowercase: + key = key.lower() + rv[key] = v + return rv + + def __repr__(self) -> str: + return f"<{type(self).__name__} {dict.__repr__(self)}>" diff --git a/psets/9/finance/env/lib/python3.12/site-packages/flask/ctx.py b/psets/9/finance/env/lib/python3.12/site-packages/flask/ctx.py new file mode 100644 index 0000000..9b164d3 --- /dev/null +++ b/psets/9/finance/env/lib/python3.12/site-packages/flask/ctx.py @@ -0,0 +1,449 @@ +from __future__ import annotations + +import contextvars +import sys +import typing as t +from functools import update_wrapper +from types import TracebackType + +from werkzeug.exceptions import HTTPException + +from . import typing as ft +from .globals import _cv_app +from .globals import _cv_request +from .signals import appcontext_popped +from .signals import appcontext_pushed + +if t.TYPE_CHECKING: # pragma: no cover + from _typeshed.wsgi import WSGIEnvironment + + from .app import Flask + from .sessions import SessionMixin + from .wrappers import Request + + +# a singleton sentinel value for parameter defaults +_sentinel = object() + + +class _AppCtxGlobals: + """A plain object. Used as a namespace for storing data during an + application context. + + Creating an app context automatically creates this object, which is + made available as the :data:`g` proxy. + + .. describe:: 'key' in g + + Check whether an attribute is present. + + .. versionadded:: 0.10 + + .. describe:: iter(g) + + Return an iterator over the attribute names. + + .. versionadded:: 0.10 + """ + + # Define attr methods to let mypy know this is a namespace object + # that has arbitrary attributes. + + def __getattr__(self, name: str) -> t.Any: + try: + return self.__dict__[name] + except KeyError: + raise AttributeError(name) from None + + def __setattr__(self, name: str, value: t.Any) -> None: + self.__dict__[name] = value + + def __delattr__(self, name: str) -> None: + try: + del self.__dict__[name] + except KeyError: + raise AttributeError(name) from None + + def get(self, name: str, default: t.Any | None = None) -> t.Any: + """Get an attribute by name, or a default value. Like + :meth:`dict.get`. + + :param name: Name of attribute to get. + :param default: Value to return if the attribute is not present. + + .. versionadded:: 0.10 + """ + return self.__dict__.get(name, default) + + def pop(self, name: str, default: t.Any = _sentinel) -> t.Any: + """Get and remove an attribute by name. Like :meth:`dict.pop`. + + :param name: Name of attribute to pop. + :param default: Value to return if the attribute is not present, + instead of raising a ``KeyError``. + + .. versionadded:: 0.11 + """ + if default is _sentinel: + return self.__dict__.pop(name) + else: + return self.__dict__.pop(name, default) + + def setdefault(self, name: str, default: t.Any = None) -> t.Any: + """Get the value of an attribute if it is present, otherwise + set and return a default value. Like :meth:`dict.setdefault`. + + :param name: Name of attribute to get. + :param default: Value to set and return if the attribute is not + present. + + .. versionadded:: 0.11 + """ + return self.__dict__.setdefault(name, default) + + def __contains__(self, item: str) -> bool: + return item in self.__dict__ + + def __iter__(self) -> t.Iterator[str]: + return iter(self.__dict__) + + def __repr__(self) -> str: + ctx = _cv_app.get(None) + if ctx is not None: + return f"" + return object.__repr__(self) + + +def after_this_request( + f: ft.AfterRequestCallable[t.Any], +) -> ft.AfterRequestCallable[t.Any]: + """Executes a function after this request. This is useful to modify + response objects. The function is passed the response object and has + to return the same or a new one. + + Example:: + + @app.route('/') + def index(): + @after_this_request + def add_header(response): + response.headers['X-Foo'] = 'Parachute' + return response + return 'Hello World!' + + This is more useful if a function other than the view function wants to + modify a response. For instance think of a decorator that wants to add + some headers without converting the return value into a response object. + + .. versionadded:: 0.9 + """ + ctx = _cv_request.get(None) + + if ctx is None: + raise RuntimeError( + "'after_this_request' can only be used when a request" + " context is active, such as in a view function." + ) + + ctx._after_request_functions.append(f) + return f + + +F = t.TypeVar("F", bound=t.Callable[..., t.Any]) + + +def copy_current_request_context(f: F) -> F: + """A helper function that decorates a function to retain the current + request context. This is useful when working with greenlets. The moment + the function is decorated a copy of the request context is created and + then pushed when the function is called. The current session is also + included in the copied request context. + + Example:: + + import gevent + from flask import copy_current_request_context + + @app.route('/') + def index(): + @copy_current_request_context + def do_some_work(): + # do some work here, it can access flask.request or + # flask.session like you would otherwise in the view function. + ... + gevent.spawn(do_some_work) + return 'Regular response' + + .. versionadded:: 0.10 + """ + ctx = _cv_request.get(None) + + if ctx is None: + raise RuntimeError( + "'copy_current_request_context' can only be used when a" + " request context is active, such as in a view function." + ) + + ctx = ctx.copy() + + def wrapper(*args: t.Any, **kwargs: t.Any) -> t.Any: + with ctx: # type: ignore[union-attr] + return ctx.app.ensure_sync(f)(*args, **kwargs) # type: ignore[union-attr] + + return update_wrapper(wrapper, f) # type: ignore[return-value] + + +def has_request_context() -> bool: + """If you have code that wants to test if a request context is there or + not this function can be used. For instance, you may want to take advantage + of request information if the request object is available, but fail + silently if it is unavailable. + + :: + + class User(db.Model): + + def __init__(self, username, remote_addr=None): + self.username = username + if remote_addr is None and has_request_context(): + remote_addr = request.remote_addr + self.remote_addr = remote_addr + + Alternatively you can also just test any of the context bound objects + (such as :class:`request` or :class:`g`) for truthness:: + + class User(db.Model): + + def __init__(self, username, remote_addr=None): + self.username = username + if remote_addr is None and request: + remote_addr = request.remote_addr + self.remote_addr = remote_addr + + .. versionadded:: 0.7 + """ + return _cv_request.get(None) is not None + + +def has_app_context() -> bool: + """Works like :func:`has_request_context` but for the application + context. You can also just do a boolean check on the + :data:`current_app` object instead. + + .. versionadded:: 0.9 + """ + return _cv_app.get(None) is not None + + +class AppContext: + """The app context contains application-specific information. An app + context is created and pushed at the beginning of each request if + one is not already active. An app context is also pushed when + running CLI commands. + """ + + def __init__(self, app: Flask) -> None: + self.app = app + self.url_adapter = app.create_url_adapter(None) + self.g: _AppCtxGlobals = app.app_ctx_globals_class() + self._cv_tokens: list[contextvars.Token[AppContext]] = [] + + def push(self) -> None: + """Binds the app context to the current context.""" + self._cv_tokens.append(_cv_app.set(self)) + appcontext_pushed.send(self.app, _async_wrapper=self.app.ensure_sync) + + def pop(self, exc: BaseException | None = _sentinel) -> None: # type: ignore + """Pops the app context.""" + try: + if len(self._cv_tokens) == 1: + if exc is _sentinel: + exc = sys.exc_info()[1] + self.app.do_teardown_appcontext(exc) + finally: + ctx = _cv_app.get() + _cv_app.reset(self._cv_tokens.pop()) + + if ctx is not self: + raise AssertionError( + f"Popped wrong app context. ({ctx!r} instead of {self!r})" + ) + + appcontext_popped.send(self.app, _async_wrapper=self.app.ensure_sync) + + def __enter__(self) -> AppContext: + self.push() + return self + + def __exit__( + self, + exc_type: type | None, + exc_value: BaseException | None, + tb: TracebackType | None, + ) -> None: + self.pop(exc_value) + + +class RequestContext: + """The request context contains per-request information. The Flask + app creates and pushes it at the beginning of the request, then pops + it at the end of the request. It will create the URL adapter and + request object for the WSGI environment provided. + + Do not attempt to use this class directly, instead use + :meth:`~flask.Flask.test_request_context` and + :meth:`~flask.Flask.request_context` to create this object. + + When the request context is popped, it will evaluate all the + functions registered on the application for teardown execution + (:meth:`~flask.Flask.teardown_request`). + + The request context is automatically popped at the end of the + request. When using the interactive debugger, the context will be + restored so ``request`` is still accessible. Similarly, the test + client can preserve the context after the request ends. However, + teardown functions may already have closed some resources such as + database connections. + """ + + def __init__( + self, + app: Flask, + environ: WSGIEnvironment, + request: Request | None = None, + session: SessionMixin | None = None, + ) -> None: + self.app = app + if request is None: + request = app.request_class(environ) + request.json_module = app.json + self.request: Request = request + self.url_adapter = None + try: + self.url_adapter = app.create_url_adapter(self.request) + except HTTPException as e: + self.request.routing_exception = e + self.flashes: list[tuple[str, str]] | None = None + self.session: SessionMixin | None = session + # Functions that should be executed after the request on the response + # object. These will be called before the regular "after_request" + # functions. + self._after_request_functions: list[ft.AfterRequestCallable[t.Any]] = [] + + self._cv_tokens: list[ + tuple[contextvars.Token[RequestContext], AppContext | None] + ] = [] + + def copy(self) -> RequestContext: + """Creates a copy of this request context with the same request object. + This can be used to move a request context to a different greenlet. + Because the actual request object is the same this cannot be used to + move a request context to a different thread unless access to the + request object is locked. + + .. versionadded:: 0.10 + + .. versionchanged:: 1.1 + The current session object is used instead of reloading the original + data. This prevents `flask.session` pointing to an out-of-date object. + """ + return self.__class__( + self.app, + environ=self.request.environ, + request=self.request, + session=self.session, + ) + + def match_request(self) -> None: + """Can be overridden by a subclass to hook into the matching + of the request. + """ + try: + result = self.url_adapter.match(return_rule=True) # type: ignore + self.request.url_rule, self.request.view_args = result # type: ignore + except HTTPException as e: + self.request.routing_exception = e + + def push(self) -> None: + # Before we push the request context we have to ensure that there + # is an application context. + app_ctx = _cv_app.get(None) + + if app_ctx is None or app_ctx.app is not self.app: + app_ctx = self.app.app_context() + app_ctx.push() + else: + app_ctx = None + + self._cv_tokens.append((_cv_request.set(self), app_ctx)) + + # Open the session at the moment that the request context is available. + # This allows a custom open_session method to use the request context. + # Only open a new session if this is the first time the request was + # pushed, otherwise stream_with_context loses the session. + if self.session is None: + session_interface = self.app.session_interface + self.session = session_interface.open_session(self.app, self.request) + + if self.session is None: + self.session = session_interface.make_null_session(self.app) + + # Match the request URL after loading the session, so that the + # session is available in custom URL converters. + if self.url_adapter is not None: + self.match_request() + + def pop(self, exc: BaseException | None = _sentinel) -> None: # type: ignore + """Pops the request context and unbinds it by doing that. This will + also trigger the execution of functions registered by the + :meth:`~flask.Flask.teardown_request` decorator. + + .. versionchanged:: 0.9 + Added the `exc` argument. + """ + clear_request = len(self._cv_tokens) == 1 + + try: + if clear_request: + if exc is _sentinel: + exc = sys.exc_info()[1] + self.app.do_teardown_request(exc) + + request_close = getattr(self.request, "close", None) + if request_close is not None: + request_close() + finally: + ctx = _cv_request.get() + token, app_ctx = self._cv_tokens.pop() + _cv_request.reset(token) + + # get rid of circular dependencies at the end of the request + # so that we don't require the GC to be active. + if clear_request: + ctx.request.environ["werkzeug.request"] = None + + if app_ctx is not None: + app_ctx.pop(exc) + + if ctx is not self: + raise AssertionError( + f"Popped wrong request context. ({ctx!r} instead of {self!r})" + ) + + def __enter__(self) -> RequestContext: + self.push() + return self + + def __exit__( + self, + exc_type: type | None, + exc_value: BaseException | None, + tb: TracebackType | None, + ) -> None: + self.pop(exc_value) + + def __repr__(self) -> str: + return ( + f"<{type(self).__name__} {self.request.url!r}" + f" [{self.request.method}] of {self.app.name}>" + ) diff --git a/psets/9/finance/env/lib/python3.12/site-packages/flask/debughelpers.py b/psets/9/finance/env/lib/python3.12/site-packages/flask/debughelpers.py new file mode 100644 index 0000000..2c8c4c4 --- /dev/null +++ b/psets/9/finance/env/lib/python3.12/site-packages/flask/debughelpers.py @@ -0,0 +1,178 @@ +from __future__ import annotations + +import typing as t + +from jinja2.loaders import BaseLoader +from werkzeug.routing import RequestRedirect + +from .blueprints import Blueprint +from .globals import request_ctx +from .sansio.app import App + +if t.TYPE_CHECKING: + from .sansio.scaffold import Scaffold + from .wrappers import Request + + +class UnexpectedUnicodeError(AssertionError, UnicodeError): + """Raised in places where we want some better error reporting for + unexpected unicode or binary data. + """ + + +class DebugFilesKeyError(KeyError, AssertionError): + """Raised from request.files during debugging. The idea is that it can + provide a better error message than just a generic KeyError/BadRequest. + """ + + def __init__(self, request: Request, key: str) -> None: + form_matches = request.form.getlist(key) + buf = [ + f"You tried to access the file {key!r} in the request.files" + " dictionary but it does not exist. The mimetype for the" + f" request is {request.mimetype!r} instead of" + " 'multipart/form-data' which means that no file contents" + " were transmitted. To fix this error you should provide" + ' enctype="multipart/form-data" in your form.' + ] + if form_matches: + names = ", ".join(repr(x) for x in form_matches) + buf.append( + "\n\nThe browser instead transmitted some file names. " + f"This was submitted: {names}" + ) + self.msg = "".join(buf) + + def __str__(self) -> str: + return self.msg + + +class FormDataRoutingRedirect(AssertionError): + """This exception is raised in debug mode if a routing redirect + would cause the browser to drop the method or body. This happens + when method is not GET, HEAD or OPTIONS and the status code is not + 307 or 308. + """ + + def __init__(self, request: Request) -> None: + exc = request.routing_exception + assert isinstance(exc, RequestRedirect) + buf = [ + f"A request was sent to '{request.url}', but routing issued" + f" a redirect to the canonical URL '{exc.new_url}'." + ] + + if f"{request.base_url}/" == exc.new_url.partition("?")[0]: + buf.append( + " The URL was defined with a trailing slash. Flask" + " will redirect to the URL with a trailing slash if it" + " was accessed without one." + ) + + buf.append( + " Send requests to the canonical URL, or use 307 or 308 for" + " routing redirects. Otherwise, browsers will drop form" + " data.\n\n" + "This exception is only raised in debug mode." + ) + super().__init__("".join(buf)) + + +def attach_enctype_error_multidict(request: Request) -> None: + """Patch ``request.files.__getitem__`` to raise a descriptive error + about ``enctype=multipart/form-data``. + + :param request: The request to patch. + :meta private: + """ + oldcls = request.files.__class__ + + class newcls(oldcls): # type: ignore[valid-type, misc] + def __getitem__(self, key: str) -> t.Any: + try: + return super().__getitem__(key) + except KeyError as e: + if key not in request.form: + raise + + raise DebugFilesKeyError(request, key).with_traceback( + e.__traceback__ + ) from None + + newcls.__name__ = oldcls.__name__ + newcls.__module__ = oldcls.__module__ + request.files.__class__ = newcls + + +def _dump_loader_info(loader: BaseLoader) -> t.Iterator[str]: + yield f"class: {type(loader).__module__}.{type(loader).__name__}" + for key, value in sorted(loader.__dict__.items()): + if key.startswith("_"): + continue + if isinstance(value, (tuple, list)): + if not all(isinstance(x, str) for x in value): + continue + yield f"{key}:" + for item in value: + yield f" - {item}" + continue + elif not isinstance(value, (str, int, float, bool)): + continue + yield f"{key}: {value!r}" + + +def explain_template_loading_attempts( + app: App, + template: str, + attempts: list[ + tuple[ + BaseLoader, + Scaffold, + tuple[str, str | None, t.Callable[[], bool] | None] | None, + ] + ], +) -> None: + """This should help developers understand what failed""" + info = [f"Locating template {template!r}:"] + total_found = 0 + blueprint = None + if request_ctx and request_ctx.request.blueprint is not None: + blueprint = request_ctx.request.blueprint + + for idx, (loader, srcobj, triple) in enumerate(attempts): + if isinstance(srcobj, App): + src_info = f"application {srcobj.import_name!r}" + elif isinstance(srcobj, Blueprint): + src_info = f"blueprint {srcobj.name!r} ({srcobj.import_name})" + else: + src_info = repr(srcobj) + + info.append(f"{idx + 1:5}: trying loader of {src_info}") + + for line in _dump_loader_info(loader): + info.append(f" {line}") + + if triple is None: + detail = "no match" + else: + detail = f"found ({triple[1] or ''!r})" + total_found += 1 + info.append(f" -> {detail}") + + seems_fishy = False + if total_found == 0: + info.append("Error: the template could not be found.") + seems_fishy = True + elif total_found > 1: + info.append("Warning: multiple loaders returned a match for the template.") + seems_fishy = True + + if blueprint is not None and seems_fishy: + info.append( + " The template was looked up from an endpoint that belongs" + f" to the blueprint {blueprint!r}." + ) + info.append(" Maybe you did not place a template in the right folder?") + info.append(" See https://flask.palletsprojects.com/blueprints/#templates") + + app.logger.info("\n".join(info)) diff --git a/psets/9/finance/env/lib/python3.12/site-packages/flask/globals.py b/psets/9/finance/env/lib/python3.12/site-packages/flask/globals.py new file mode 100644 index 0000000..e2c410c --- /dev/null +++ b/psets/9/finance/env/lib/python3.12/site-packages/flask/globals.py @@ -0,0 +1,51 @@ +from __future__ import annotations + +import typing as t +from contextvars import ContextVar + +from werkzeug.local import LocalProxy + +if t.TYPE_CHECKING: # pragma: no cover + from .app import Flask + from .ctx import _AppCtxGlobals + from .ctx import AppContext + from .ctx import RequestContext + from .sessions import SessionMixin + from .wrappers import Request + + +_no_app_msg = """\ +Working outside of application context. + +This typically means that you attempted to use functionality that needed +the current application. To solve this, set up an application context +with app.app_context(). See the documentation for more information.\ +""" +_cv_app: ContextVar[AppContext] = ContextVar("flask.app_ctx") +app_ctx: AppContext = LocalProxy( # type: ignore[assignment] + _cv_app, unbound_message=_no_app_msg +) +current_app: Flask = LocalProxy( # type: ignore[assignment] + _cv_app, "app", unbound_message=_no_app_msg +) +g: _AppCtxGlobals = LocalProxy( # type: ignore[assignment] + _cv_app, "g", unbound_message=_no_app_msg +) + +_no_req_msg = """\ +Working outside of request context. + +This typically means that you attempted to use functionality that needed +an active HTTP request. Consult the documentation on testing for +information about how to avoid this problem.\ +""" +_cv_request: ContextVar[RequestContext] = ContextVar("flask.request_ctx") +request_ctx: RequestContext = LocalProxy( # type: ignore[assignment] + _cv_request, unbound_message=_no_req_msg +) +request: Request = LocalProxy( # type: ignore[assignment] + _cv_request, "request", unbound_message=_no_req_msg +) +session: SessionMixin = LocalProxy( # type: ignore[assignment] + _cv_request, "session", unbound_message=_no_req_msg +) diff --git a/psets/9/finance/env/lib/python3.12/site-packages/flask/helpers.py b/psets/9/finance/env/lib/python3.12/site-packages/flask/helpers.py new file mode 100644 index 0000000..a6b7e15 --- /dev/null +++ b/psets/9/finance/env/lib/python3.12/site-packages/flask/helpers.py @@ -0,0 +1,634 @@ +from __future__ import annotations + +import importlib.util +import os +import sys +import typing as t +from datetime import datetime +from functools import cache +from functools import update_wrapper + +import werkzeug.utils +from werkzeug.exceptions import abort as _wz_abort +from werkzeug.utils import redirect as _wz_redirect +from werkzeug.wrappers import Response as BaseResponse + +from .globals import _cv_request +from .globals import current_app +from .globals import request +from .globals import request_ctx +from .globals import session +from .signals import message_flashed + +if t.TYPE_CHECKING: # pragma: no cover + from .wrappers import Response + + +def get_debug_flag() -> bool: + """Get whether debug mode should be enabled for the app, indicated by the + :envvar:`FLASK_DEBUG` environment variable. The default is ``False``. + """ + val = os.environ.get("FLASK_DEBUG") + return bool(val and val.lower() not in {"0", "false", "no"}) + + +def get_load_dotenv(default: bool = True) -> bool: + """Get whether the user has disabled loading default dotenv files by + setting :envvar:`FLASK_SKIP_DOTENV`. The default is ``True``, load + the files. + + :param default: What to return if the env var isn't set. + """ + val = os.environ.get("FLASK_SKIP_DOTENV") + + if not val: + return default + + return val.lower() in ("0", "false", "no") + + +@t.overload +def stream_with_context( + generator_or_function: t.Iterator[t.AnyStr], +) -> t.Iterator[t.AnyStr]: ... + + +@t.overload +def stream_with_context( + generator_or_function: t.Callable[..., t.Iterator[t.AnyStr]], +) -> t.Callable[[t.Iterator[t.AnyStr]], t.Iterator[t.AnyStr]]: ... + + +def stream_with_context( + generator_or_function: t.Iterator[t.AnyStr] | t.Callable[..., t.Iterator[t.AnyStr]], +) -> t.Iterator[t.AnyStr] | t.Callable[[t.Iterator[t.AnyStr]], t.Iterator[t.AnyStr]]: + """Request contexts disappear when the response is started on the server. + This is done for efficiency reasons and to make it less likely to encounter + memory leaks with badly written WSGI middlewares. The downside is that if + you are using streamed responses, the generator cannot access request bound + information any more. + + This function however can help you keep the context around for longer:: + + from flask import stream_with_context, request, Response + + @app.route('/stream') + def streamed_response(): + @stream_with_context + def generate(): + yield 'Hello ' + yield request.args['name'] + yield '!' + return Response(generate()) + + Alternatively it can also be used around a specific generator:: + + from flask import stream_with_context, request, Response + + @app.route('/stream') + def streamed_response(): + def generate(): + yield 'Hello ' + yield request.args['name'] + yield '!' + return Response(stream_with_context(generate())) + + .. versionadded:: 0.9 + """ + try: + gen = iter(generator_or_function) # type: ignore[arg-type] + except TypeError: + + def decorator(*args: t.Any, **kwargs: t.Any) -> t.Any: + gen = generator_or_function(*args, **kwargs) # type: ignore[operator] + return stream_with_context(gen) + + return update_wrapper(decorator, generator_or_function) # type: ignore[arg-type] + + def generator() -> t.Iterator[t.AnyStr | None]: + ctx = _cv_request.get(None) + if ctx is None: + raise RuntimeError( + "'stream_with_context' can only be used when a request" + " context is active, such as in a view function." + ) + with ctx: + # Dummy sentinel. Has to be inside the context block or we're + # not actually keeping the context around. + yield None + + # The try/finally is here so that if someone passes a WSGI level + # iterator in we're still running the cleanup logic. Generators + # don't need that because they are closed on their destruction + # automatically. + try: + yield from gen + finally: + if hasattr(gen, "close"): + gen.close() + + # The trick is to start the generator. Then the code execution runs until + # the first dummy None is yielded at which point the context was already + # pushed. This item is discarded. Then when the iteration continues the + # real generator is executed. + wrapped_g = generator() + next(wrapped_g) + return wrapped_g # type: ignore[return-value] + + +def make_response(*args: t.Any) -> Response: + """Sometimes it is necessary to set additional headers in a view. Because + views do not have to return response objects but can return a value that + is converted into a response object by Flask itself, it becomes tricky to + add headers to it. This function can be called instead of using a return + and you will get a response object which you can use to attach headers. + + If view looked like this and you want to add a new header:: + + def index(): + return render_template('index.html', foo=42) + + You can now do something like this:: + + def index(): + response = make_response(render_template('index.html', foo=42)) + response.headers['X-Parachutes'] = 'parachutes are cool' + return response + + This function accepts the very same arguments you can return from a + view function. This for example creates a response with a 404 error + code:: + + response = make_response(render_template('not_found.html'), 404) + + The other use case of this function is to force the return value of a + view function into a response which is helpful with view + decorators:: + + response = make_response(view_function()) + response.headers['X-Parachutes'] = 'parachutes are cool' + + Internally this function does the following things: + + - if no arguments are passed, it creates a new response argument + - if one argument is passed, :meth:`flask.Flask.make_response` + is invoked with it. + - if more than one argument is passed, the arguments are passed + to the :meth:`flask.Flask.make_response` function as tuple. + + .. versionadded:: 0.6 + """ + if not args: + return current_app.response_class() + if len(args) == 1: + args = args[0] + return current_app.make_response(args) + + +def url_for( + endpoint: str, + *, + _anchor: str | None = None, + _method: str | None = None, + _scheme: str | None = None, + _external: bool | None = None, + **values: t.Any, +) -> str: + """Generate a URL to the given endpoint with the given values. + + This requires an active request or application context, and calls + :meth:`current_app.url_for() `. See that method + for full documentation. + + :param endpoint: The endpoint name associated with the URL to + generate. If this starts with a ``.``, the current blueprint + name (if any) will be used. + :param _anchor: If given, append this as ``#anchor`` to the URL. + :param _method: If given, generate the URL associated with this + method for the endpoint. + :param _scheme: If given, the URL will have this scheme if it is + external. + :param _external: If given, prefer the URL to be internal (False) or + require it to be external (True). External URLs include the + scheme and domain. When not in an active request, URLs are + external by default. + :param values: Values to use for the variable parts of the URL rule. + Unknown keys are appended as query string arguments, like + ``?a=b&c=d``. + + .. versionchanged:: 2.2 + Calls ``current_app.url_for``, allowing an app to override the + behavior. + + .. versionchanged:: 0.10 + The ``_scheme`` parameter was added. + + .. versionchanged:: 0.9 + The ``_anchor`` and ``_method`` parameters were added. + + .. versionchanged:: 0.9 + Calls ``app.handle_url_build_error`` on build errors. + """ + return current_app.url_for( + endpoint, + _anchor=_anchor, + _method=_method, + _scheme=_scheme, + _external=_external, + **values, + ) + + +def redirect( + location: str, code: int = 302, Response: type[BaseResponse] | None = None +) -> BaseResponse: + """Create a redirect response object. + + If :data:`~flask.current_app` is available, it will use its + :meth:`~flask.Flask.redirect` method, otherwise it will use + :func:`werkzeug.utils.redirect`. + + :param location: The URL to redirect to. + :param code: The status code for the redirect. + :param Response: The response class to use. Not used when + ``current_app`` is active, which uses ``app.response_class``. + + .. versionadded:: 2.2 + Calls ``current_app.redirect`` if available instead of always + using Werkzeug's default ``redirect``. + """ + if current_app: + return current_app.redirect(location, code=code) + + return _wz_redirect(location, code=code, Response=Response) + + +def abort(code: int | BaseResponse, *args: t.Any, **kwargs: t.Any) -> t.NoReturn: + """Raise an :exc:`~werkzeug.exceptions.HTTPException` for the given + status code. + + If :data:`~flask.current_app` is available, it will call its + :attr:`~flask.Flask.aborter` object, otherwise it will use + :func:`werkzeug.exceptions.abort`. + + :param code: The status code for the exception, which must be + registered in ``app.aborter``. + :param args: Passed to the exception. + :param kwargs: Passed to the exception. + + .. versionadded:: 2.2 + Calls ``current_app.aborter`` if available instead of always + using Werkzeug's default ``abort``. + """ + if current_app: + current_app.aborter(code, *args, **kwargs) + + _wz_abort(code, *args, **kwargs) + + +def get_template_attribute(template_name: str, attribute: str) -> t.Any: + """Loads a macro (or variable) a template exports. This can be used to + invoke a macro from within Python code. If you for example have a + template named :file:`_cider.html` with the following contents: + + .. sourcecode:: html+jinja + + {% macro hello(name) %}Hello {{ name }}!{% endmacro %} + + You can access this from Python code like this:: + + hello = get_template_attribute('_cider.html', 'hello') + return hello('World') + + .. versionadded:: 0.2 + + :param template_name: the name of the template + :param attribute: the name of the variable of macro to access + """ + return getattr(current_app.jinja_env.get_template(template_name).module, attribute) + + +def flash(message: str, category: str = "message") -> None: + """Flashes a message to the next request. In order to remove the + flashed message from the session and to display it to the user, + the template has to call :func:`get_flashed_messages`. + + .. versionchanged:: 0.3 + `category` parameter added. + + :param message: the message to be flashed. + :param category: the category for the message. The following values + are recommended: ``'message'`` for any kind of message, + ``'error'`` for errors, ``'info'`` for information + messages and ``'warning'`` for warnings. However any + kind of string can be used as category. + """ + # Original implementation: + # + # session.setdefault('_flashes', []).append((category, message)) + # + # This assumed that changes made to mutable structures in the session are + # always in sync with the session object, which is not true for session + # implementations that use external storage for keeping their keys/values. + flashes = session.get("_flashes", []) + flashes.append((category, message)) + session["_flashes"] = flashes + app = current_app._get_current_object() # type: ignore + message_flashed.send( + app, + _async_wrapper=app.ensure_sync, + message=message, + category=category, + ) + + +def get_flashed_messages( + with_categories: bool = False, category_filter: t.Iterable[str] = () +) -> list[str] | list[tuple[str, str]]: + """Pulls all flashed messages from the session and returns them. + Further calls in the same request to the function will return + the same messages. By default just the messages are returned, + but when `with_categories` is set to ``True``, the return value will + be a list of tuples in the form ``(category, message)`` instead. + + Filter the flashed messages to one or more categories by providing those + categories in `category_filter`. This allows rendering categories in + separate html blocks. The `with_categories` and `category_filter` + arguments are distinct: + + * `with_categories` controls whether categories are returned with message + text (``True`` gives a tuple, where ``False`` gives just the message text). + * `category_filter` filters the messages down to only those matching the + provided categories. + + See :doc:`/patterns/flashing` for examples. + + .. versionchanged:: 0.3 + `with_categories` parameter added. + + .. versionchanged:: 0.9 + `category_filter` parameter added. + + :param with_categories: set to ``True`` to also receive categories. + :param category_filter: filter of categories to limit return values. Only + categories in the list will be returned. + """ + flashes = request_ctx.flashes + if flashes is None: + flashes = session.pop("_flashes") if "_flashes" in session else [] + request_ctx.flashes = flashes + if category_filter: + flashes = list(filter(lambda f: f[0] in category_filter, flashes)) + if not with_categories: + return [x[1] for x in flashes] + return flashes + + +def _prepare_send_file_kwargs(**kwargs: t.Any) -> dict[str, t.Any]: + if kwargs.get("max_age") is None: + kwargs["max_age"] = current_app.get_send_file_max_age + + kwargs.update( + environ=request.environ, + use_x_sendfile=current_app.config["USE_X_SENDFILE"], + response_class=current_app.response_class, + _root_path=current_app.root_path, # type: ignore + ) + return kwargs + + +def send_file( + path_or_file: os.PathLike[t.AnyStr] | str | t.BinaryIO, + mimetype: str | None = None, + as_attachment: bool = False, + download_name: str | None = None, + conditional: bool = True, + etag: bool | str = True, + last_modified: datetime | int | float | None = None, + max_age: None | (int | t.Callable[[str | None], int | None]) = None, +) -> Response: + """Send the contents of a file to the client. + + The first argument can be a file path or a file-like object. Paths + are preferred in most cases because Werkzeug can manage the file and + get extra information from the path. Passing a file-like object + requires that the file is opened in binary mode, and is mostly + useful when building a file in memory with :class:`io.BytesIO`. + + Never pass file paths provided by a user. The path is assumed to be + trusted, so a user could craft a path to access a file you didn't + intend. Use :func:`send_from_directory` to safely serve + user-requested paths from within a directory. + + If the WSGI server sets a ``file_wrapper`` in ``environ``, it is + used, otherwise Werkzeug's built-in wrapper is used. Alternatively, + if the HTTP server supports ``X-Sendfile``, configuring Flask with + ``USE_X_SENDFILE = True`` will tell the server to send the given + path, which is much more efficient than reading it in Python. + + :param path_or_file: The path to the file to send, relative to the + current working directory if a relative path is given. + Alternatively, a file-like object opened in binary mode. Make + sure the file pointer is seeked to the start of the data. + :param mimetype: The MIME type to send for the file. If not + provided, it will try to detect it from the file name. + :param as_attachment: Indicate to a browser that it should offer to + save the file instead of displaying it. + :param download_name: The default name browsers will use when saving + the file. Defaults to the passed file name. + :param conditional: Enable conditional and range responses based on + request headers. Requires passing a file path and ``environ``. + :param etag: Calculate an ETag for the file, which requires passing + a file path. Can also be a string to use instead. + :param last_modified: The last modified time to send for the file, + in seconds. If not provided, it will try to detect it from the + file path. + :param max_age: How long the client should cache the file, in + seconds. If set, ``Cache-Control`` will be ``public``, otherwise + it will be ``no-cache`` to prefer conditional caching. + + .. versionchanged:: 2.0 + ``download_name`` replaces the ``attachment_filename`` + parameter. If ``as_attachment=False``, it is passed with + ``Content-Disposition: inline`` instead. + + .. versionchanged:: 2.0 + ``max_age`` replaces the ``cache_timeout`` parameter. + ``conditional`` is enabled and ``max_age`` is not set by + default. + + .. versionchanged:: 2.0 + ``etag`` replaces the ``add_etags`` parameter. It can be a + string to use instead of generating one. + + .. versionchanged:: 2.0 + Passing a file-like object that inherits from + :class:`~io.TextIOBase` will raise a :exc:`ValueError` rather + than sending an empty file. + + .. versionadded:: 2.0 + Moved the implementation to Werkzeug. This is now a wrapper to + pass some Flask-specific arguments. + + .. versionchanged:: 1.1 + ``filename`` may be a :class:`~os.PathLike` object. + + .. versionchanged:: 1.1 + Passing a :class:`~io.BytesIO` object supports range requests. + + .. versionchanged:: 1.0.3 + Filenames are encoded with ASCII instead of Latin-1 for broader + compatibility with WSGI servers. + + .. versionchanged:: 1.0 + UTF-8 filenames as specified in :rfc:`2231` are supported. + + .. versionchanged:: 0.12 + The filename is no longer automatically inferred from file + objects. If you want to use automatic MIME and etag support, + pass a filename via ``filename_or_fp`` or + ``attachment_filename``. + + .. versionchanged:: 0.12 + ``attachment_filename`` is preferred over ``filename`` for MIME + detection. + + .. versionchanged:: 0.9 + ``cache_timeout`` defaults to + :meth:`Flask.get_send_file_max_age`. + + .. versionchanged:: 0.7 + MIME guessing and etag support for file-like objects was + removed because it was unreliable. Pass a filename if you are + able to, otherwise attach an etag yourself. + + .. versionchanged:: 0.5 + The ``add_etags``, ``cache_timeout`` and ``conditional`` + parameters were added. The default behavior is to add etags. + + .. versionadded:: 0.2 + """ + return werkzeug.utils.send_file( # type: ignore[return-value] + **_prepare_send_file_kwargs( + path_or_file=path_or_file, + environ=request.environ, + mimetype=mimetype, + as_attachment=as_attachment, + download_name=download_name, + conditional=conditional, + etag=etag, + last_modified=last_modified, + max_age=max_age, + ) + ) + + +def send_from_directory( + directory: os.PathLike[str] | str, + path: os.PathLike[str] | str, + **kwargs: t.Any, +) -> Response: + """Send a file from within a directory using :func:`send_file`. + + .. code-block:: python + + @app.route("/uploads/") + def download_file(name): + return send_from_directory( + app.config['UPLOAD_FOLDER'], name, as_attachment=True + ) + + This is a secure way to serve files from a folder, such as static + files or uploads. Uses :func:`~werkzeug.security.safe_join` to + ensure the path coming from the client is not maliciously crafted to + point outside the specified directory. + + If the final path does not point to an existing regular file, + raises a 404 :exc:`~werkzeug.exceptions.NotFound` error. + + :param directory: The directory that ``path`` must be located under, + relative to the current application's root path. This *must not* + be a value provided by the client, otherwise it becomes insecure. + :param path: The path to the file to send, relative to + ``directory``. + :param kwargs: Arguments to pass to :func:`send_file`. + + .. versionchanged:: 2.0 + ``path`` replaces the ``filename`` parameter. + + .. versionadded:: 2.0 + Moved the implementation to Werkzeug. This is now a wrapper to + pass some Flask-specific arguments. + + .. versionadded:: 0.5 + """ + return werkzeug.utils.send_from_directory( # type: ignore[return-value] + directory, path, **_prepare_send_file_kwargs(**kwargs) + ) + + +def get_root_path(import_name: str) -> str: + """Find the root path of a package, or the path that contains a + module. If it cannot be found, returns the current working + directory. + + Not to be confused with the value returned by :func:`find_package`. + + :meta private: + """ + # Module already imported and has a file attribute. Use that first. + mod = sys.modules.get(import_name) + + if mod is not None and hasattr(mod, "__file__") and mod.__file__ is not None: + return os.path.dirname(os.path.abspath(mod.__file__)) + + # Next attempt: check the loader. + try: + spec = importlib.util.find_spec(import_name) + + if spec is None: + raise ValueError + except (ImportError, ValueError): + loader = None + else: + loader = spec.loader + + # Loader does not exist or we're referring to an unloaded main + # module or a main module without path (interactive sessions), go + # with the current working directory. + if loader is None: + return os.getcwd() + + if hasattr(loader, "get_filename"): + filepath = loader.get_filename(import_name) # pyright: ignore + else: + # Fall back to imports. + __import__(import_name) + mod = sys.modules[import_name] + filepath = getattr(mod, "__file__", None) + + # If we don't have a file path it might be because it is a + # namespace package. In this case pick the root path from the + # first module that is contained in the package. + if filepath is None: + raise RuntimeError( + "No root path can be found for the provided module" + f" {import_name!r}. This can happen because the module" + " came from an import hook that does not provide file" + " name information or because it's a namespace package." + " In this case the root path needs to be explicitly" + " provided." + ) + + # filepath is import_name.py for a module, or __init__.py for a package. + return os.path.dirname(os.path.abspath(filepath)) # type: ignore[no-any-return] + + +@cache +def _split_blueprint_path(name: str) -> list[str]: + out: list[str] = [name] + + if "." in name: + out.extend(_split_blueprint_path(name.rpartition(".")[0])) + + return out diff --git a/psets/9/finance/env/lib/python3.12/site-packages/flask/json/__init__.py b/psets/9/finance/env/lib/python3.12/site-packages/flask/json/__init__.py new file mode 100644 index 0000000..c0941d0 --- /dev/null +++ b/psets/9/finance/env/lib/python3.12/site-packages/flask/json/__init__.py @@ -0,0 +1,170 @@ +from __future__ import annotations + +import json as _json +import typing as t + +from ..globals import current_app +from .provider import _default + +if t.TYPE_CHECKING: # pragma: no cover + from ..wrappers import Response + + +def dumps(obj: t.Any, **kwargs: t.Any) -> str: + """Serialize data as JSON. + + If :data:`~flask.current_app` is available, it will use its + :meth:`app.json.dumps() ` + method, otherwise it will use :func:`json.dumps`. + + :param obj: The data to serialize. + :param kwargs: Arguments passed to the ``dumps`` implementation. + + .. versionchanged:: 2.3 + The ``app`` parameter was removed. + + .. versionchanged:: 2.2 + Calls ``current_app.json.dumps``, allowing an app to override + the behavior. + + .. versionchanged:: 2.0.2 + :class:`decimal.Decimal` is supported by converting to a string. + + .. versionchanged:: 2.0 + ``encoding`` will be removed in Flask 2.1. + + .. versionchanged:: 1.0.3 + ``app`` can be passed directly, rather than requiring an app + context for configuration. + """ + if current_app: + return current_app.json.dumps(obj, **kwargs) + + kwargs.setdefault("default", _default) + return _json.dumps(obj, **kwargs) + + +def dump(obj: t.Any, fp: t.IO[str], **kwargs: t.Any) -> None: + """Serialize data as JSON and write to a file. + + If :data:`~flask.current_app` is available, it will use its + :meth:`app.json.dump() ` + method, otherwise it will use :func:`json.dump`. + + :param obj: The data to serialize. + :param fp: A file opened for writing text. Should use the UTF-8 + encoding to be valid JSON. + :param kwargs: Arguments passed to the ``dump`` implementation. + + .. versionchanged:: 2.3 + The ``app`` parameter was removed. + + .. versionchanged:: 2.2 + Calls ``current_app.json.dump``, allowing an app to override + the behavior. + + .. versionchanged:: 2.0 + Writing to a binary file, and the ``encoding`` argument, will be + removed in Flask 2.1. + """ + if current_app: + current_app.json.dump(obj, fp, **kwargs) + else: + kwargs.setdefault("default", _default) + _json.dump(obj, fp, **kwargs) + + +def loads(s: str | bytes, **kwargs: t.Any) -> t.Any: + """Deserialize data as JSON. + + If :data:`~flask.current_app` is available, it will use its + :meth:`app.json.loads() ` + method, otherwise it will use :func:`json.loads`. + + :param s: Text or UTF-8 bytes. + :param kwargs: Arguments passed to the ``loads`` implementation. + + .. versionchanged:: 2.3 + The ``app`` parameter was removed. + + .. versionchanged:: 2.2 + Calls ``current_app.json.loads``, allowing an app to override + the behavior. + + .. versionchanged:: 2.0 + ``encoding`` will be removed in Flask 2.1. The data must be a + string or UTF-8 bytes. + + .. versionchanged:: 1.0.3 + ``app`` can be passed directly, rather than requiring an app + context for configuration. + """ + if current_app: + return current_app.json.loads(s, **kwargs) + + return _json.loads(s, **kwargs) + + +def load(fp: t.IO[t.AnyStr], **kwargs: t.Any) -> t.Any: + """Deserialize data as JSON read from a file. + + If :data:`~flask.current_app` is available, it will use its + :meth:`app.json.load() ` + method, otherwise it will use :func:`json.load`. + + :param fp: A file opened for reading text or UTF-8 bytes. + :param kwargs: Arguments passed to the ``load`` implementation. + + .. versionchanged:: 2.3 + The ``app`` parameter was removed. + + .. versionchanged:: 2.2 + Calls ``current_app.json.load``, allowing an app to override + the behavior. + + .. versionchanged:: 2.2 + The ``app`` parameter will be removed in Flask 2.3. + + .. versionchanged:: 2.0 + ``encoding`` will be removed in Flask 2.1. The file must be text + mode, or binary mode with UTF-8 bytes. + """ + if current_app: + return current_app.json.load(fp, **kwargs) + + return _json.load(fp, **kwargs) + + +def jsonify(*args: t.Any, **kwargs: t.Any) -> Response: + """Serialize the given arguments as JSON, and return a + :class:`~flask.Response` object with the ``application/json`` + mimetype. A dict or list returned from a view will be converted to a + JSON response automatically without needing to call this. + + This requires an active request or application context, and calls + :meth:`app.json.response() `. + + In debug mode, the output is formatted with indentation to make it + easier to read. This may also be controlled by the provider. + + Either positional or keyword arguments can be given, not both. + If no arguments are given, ``None`` is serialized. + + :param args: A single value to serialize, or multiple values to + treat as a list to serialize. + :param kwargs: Treat as a dict to serialize. + + .. versionchanged:: 2.2 + Calls ``current_app.json.response``, allowing an app to override + the behavior. + + .. versionchanged:: 2.0.2 + :class:`decimal.Decimal` is supported by converting to a string. + + .. versionchanged:: 0.11 + Added support for serializing top-level arrays. This was a + security risk in ancient browsers. See :ref:`security-json`. + + .. versionadded:: 0.2 + """ + return current_app.json.response(*args, **kwargs) # type: ignore[return-value] diff --git a/psets/9/finance/env/lib/python3.12/site-packages/flask/json/__pycache__/__init__.cpython-312.pyc b/psets/9/finance/env/lib/python3.12/site-packages/flask/json/__pycache__/__init__.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..f757ece63636363a133f607958a6dd56326f15da GIT binary patch literal 6692 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 KKO}l`-u*YDoivsJ literal 0 HcmV?d00001 diff --git a/psets/9/finance/env/lib/python3.12/site-packages/flask/json/__pycache__/tag.cpython-312.pyc b/psets/9/finance/env/lib/python3.12/site-packages/flask/json/__pycache__/tag.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..f7cb56fb88a6d8a37af2bc2fc3b64abfa27f591c GIT binary patch literal 13954 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 N%X0XAiApXj{|6k9Fn<65 literal 0 HcmV?d00001 diff --git a/psets/9/finance/env/lib/python3.12/site-packages/flask/json/provider.py b/psets/9/finance/env/lib/python3.12/site-packages/flask/json/provider.py new file mode 100644 index 0000000..ea7e475 --- /dev/null +++ b/psets/9/finance/env/lib/python3.12/site-packages/flask/json/provider.py @@ -0,0 +1,215 @@ +from __future__ import annotations + +import dataclasses +import decimal +import json +import typing as t +import uuid +import weakref +from datetime import date + +from werkzeug.http import http_date + +if t.TYPE_CHECKING: # pragma: no cover + from werkzeug.sansio.response import Response + + from ..sansio.app import App + + +class JSONProvider: + """A standard set of JSON operations for an application. Subclasses + of this can be used to customize JSON behavior or use different + JSON libraries. + + To implement a provider for a specific library, subclass this base + class and implement at least :meth:`dumps` and :meth:`loads`. All + other methods have default implementations. + + To use a different provider, either subclass ``Flask`` and set + :attr:`~flask.Flask.json_provider_class` to a provider class, or set + :attr:`app.json ` to an instance of the class. + + :param app: An application instance. This will be stored as a + :class:`weakref.proxy` on the :attr:`_app` attribute. + + .. versionadded:: 2.2 + """ + + def __init__(self, app: App) -> None: + self._app: App = weakref.proxy(app) + + def dumps(self, obj: t.Any, **kwargs: t.Any) -> str: + """Serialize data as JSON. + + :param obj: The data to serialize. + :param kwargs: May be passed to the underlying JSON library. + """ + raise NotImplementedError + + def dump(self, obj: t.Any, fp: t.IO[str], **kwargs: t.Any) -> None: + """Serialize data as JSON and write to a file. + + :param obj: The data to serialize. + :param fp: A file opened for writing text. Should use the UTF-8 + encoding to be valid JSON. + :param kwargs: May be passed to the underlying JSON library. + """ + fp.write(self.dumps(obj, **kwargs)) + + def loads(self, s: str | bytes, **kwargs: t.Any) -> t.Any: + """Deserialize data as JSON. + + :param s: Text or UTF-8 bytes. + :param kwargs: May be passed to the underlying JSON library. + """ + raise NotImplementedError + + def load(self, fp: t.IO[t.AnyStr], **kwargs: t.Any) -> t.Any: + """Deserialize data as JSON read from a file. + + :param fp: A file opened for reading text or UTF-8 bytes. + :param kwargs: May be passed to the underlying JSON library. + """ + return self.loads(fp.read(), **kwargs) + + def _prepare_response_obj( + self, args: tuple[t.Any, ...], kwargs: dict[str, t.Any] + ) -> t.Any: + if args and kwargs: + raise TypeError("app.json.response() takes either args or kwargs, not both") + + if not args and not kwargs: + return None + + if len(args) == 1: + return args[0] + + return args or kwargs + + def response(self, *args: t.Any, **kwargs: t.Any) -> Response: + """Serialize the given arguments as JSON, and return a + :class:`~flask.Response` object with the ``application/json`` + mimetype. + + The :func:`~flask.json.jsonify` function calls this method for + the current application. + + Either positional or keyword arguments can be given, not both. + If no arguments are given, ``None`` is serialized. + + :param args: A single value to serialize, or multiple values to + treat as a list to serialize. + :param kwargs: Treat as a dict to serialize. + """ + obj = self._prepare_response_obj(args, kwargs) + return self._app.response_class(self.dumps(obj), mimetype="application/json") + + +def _default(o: t.Any) -> t.Any: + if isinstance(o, date): + return http_date(o) + + if isinstance(o, (decimal.Decimal, uuid.UUID)): + return str(o) + + if dataclasses and dataclasses.is_dataclass(o): + return dataclasses.asdict(o) # type: ignore[arg-type] + + if hasattr(o, "__html__"): + return str(o.__html__()) + + raise TypeError(f"Object of type {type(o).__name__} is not JSON serializable") + + +class DefaultJSONProvider(JSONProvider): + """Provide JSON operations using Python's built-in :mod:`json` + library. Serializes the following additional data types: + + - :class:`datetime.datetime` and :class:`datetime.date` are + serialized to :rfc:`822` strings. This is the same as the HTTP + date format. + - :class:`uuid.UUID` is serialized to a string. + - :class:`dataclasses.dataclass` is passed to + :func:`dataclasses.asdict`. + - :class:`~markupsafe.Markup` (or any object with a ``__html__`` + method) will call the ``__html__`` method to get a string. + """ + + default: t.Callable[[t.Any], t.Any] = staticmethod(_default) # type: ignore[assignment] + """Apply this function to any object that :meth:`json.dumps` does + not know how to serialize. It should return a valid JSON type or + raise a ``TypeError``. + """ + + ensure_ascii = True + """Replace non-ASCII characters with escape sequences. This may be + more compatible with some clients, but can be disabled for better + performance and size. + """ + + sort_keys = True + """Sort the keys in any serialized dicts. This may be useful for + some caching situations, but can be disabled for better performance. + When enabled, keys must all be strings, they are not converted + before sorting. + """ + + compact: bool | None = None + """If ``True``, or ``None`` out of debug mode, the :meth:`response` + output will not add indentation, newlines, or spaces. If ``False``, + or ``None`` in debug mode, it will use a non-compact representation. + """ + + mimetype = "application/json" + """The mimetype set in :meth:`response`.""" + + def dumps(self, obj: t.Any, **kwargs: t.Any) -> str: + """Serialize data as JSON to a string. + + Keyword arguments are passed to :func:`json.dumps`. Sets some + parameter defaults from the :attr:`default`, + :attr:`ensure_ascii`, and :attr:`sort_keys` attributes. + + :param obj: The data to serialize. + :param kwargs: Passed to :func:`json.dumps`. + """ + kwargs.setdefault("default", self.default) + kwargs.setdefault("ensure_ascii", self.ensure_ascii) + kwargs.setdefault("sort_keys", self.sort_keys) + return json.dumps(obj, **kwargs) + + def loads(self, s: str | bytes, **kwargs: t.Any) -> t.Any: + """Deserialize data as JSON from a string or bytes. + + :param s: Text or UTF-8 bytes. + :param kwargs: Passed to :func:`json.loads`. + """ + return json.loads(s, **kwargs) + + def response(self, *args: t.Any, **kwargs: t.Any) -> Response: + """Serialize the given arguments as JSON, and return a + :class:`~flask.Response` object with it. The response mimetype + will be "application/json" and can be changed with + :attr:`mimetype`. + + If :attr:`compact` is ``False`` or debug mode is enabled, the + output will be formatted to be easier to read. + + Either positional or keyword arguments can be given, not both. + If no arguments are given, ``None`` is serialized. + + :param args: A single value to serialize, or multiple values to + treat as a list to serialize. + :param kwargs: Treat as a dict to serialize. + """ + obj = self._prepare_response_obj(args, kwargs) + dump_args: dict[str, t.Any] = {} + + if (self.compact is None and self._app.debug) or self.compact is False: + dump_args.setdefault("indent", 2) + else: + dump_args.setdefault("separators", (",", ":")) + + return self._app.response_class( + f"{self.dumps(obj, **dump_args)}\n", mimetype=self.mimetype + ) diff --git a/psets/9/finance/env/lib/python3.12/site-packages/flask/json/tag.py b/psets/9/finance/env/lib/python3.12/site-packages/flask/json/tag.py new file mode 100644 index 0000000..8dc3629 --- /dev/null +++ b/psets/9/finance/env/lib/python3.12/site-packages/flask/json/tag.py @@ -0,0 +1,327 @@ +""" +Tagged JSON +~~~~~~~~~~~ + +A compact representation for lossless serialization of non-standard JSON +types. :class:`~flask.sessions.SecureCookieSessionInterface` uses this +to serialize the session data, but it may be useful in other places. It +can be extended to support other types. + +.. autoclass:: TaggedJSONSerializer + :members: + +.. autoclass:: JSONTag + :members: + +Let's see an example that adds support for +:class:`~collections.OrderedDict`. Dicts don't have an order in JSON, so +to handle this we will dump the items as a list of ``[key, value]`` +pairs. Subclass :class:`JSONTag` and give it the new key ``' od'`` to +identify the type. The session serializer processes dicts first, so +insert the new tag at the front of the order since ``OrderedDict`` must +be processed before ``dict``. + +.. code-block:: python + + from flask.json.tag import JSONTag + + class TagOrderedDict(JSONTag): + __slots__ = ('serializer',) + key = ' od' + + def check(self, value): + return isinstance(value, OrderedDict) + + def to_json(self, value): + return [[k, self.serializer.tag(v)] for k, v in iteritems(value)] + + def to_python(self, value): + return OrderedDict(value) + + app.session_interface.serializer.register(TagOrderedDict, index=0) +""" + +from __future__ import annotations + +import typing as t +from base64 import b64decode +from base64 import b64encode +from datetime import datetime +from uuid import UUID + +from markupsafe import Markup +from werkzeug.http import http_date +from werkzeug.http import parse_date + +from ..json import dumps +from ..json import loads + + +class JSONTag: + """Base class for defining type tags for :class:`TaggedJSONSerializer`.""" + + __slots__ = ("serializer",) + + #: The tag to mark the serialized object with. If empty, this tag is + #: only used as an intermediate step during tagging. + key: str = "" + + def __init__(self, serializer: TaggedJSONSerializer) -> None: + """Create a tagger for the given serializer.""" + self.serializer = serializer + + def check(self, value: t.Any) -> bool: + """Check if the given value should be tagged by this tag.""" + raise NotImplementedError + + def to_json(self, value: t.Any) -> t.Any: + """Convert the Python object to an object that is a valid JSON type. + The tag will be added later.""" + raise NotImplementedError + + def to_python(self, value: t.Any) -> t.Any: + """Convert the JSON representation back to the correct type. The tag + will already be removed.""" + raise NotImplementedError + + def tag(self, value: t.Any) -> dict[str, t.Any]: + """Convert the value to a valid JSON type and add the tag structure + around it.""" + return {self.key: self.to_json(value)} + + +class TagDict(JSONTag): + """Tag for 1-item dicts whose only key matches a registered tag. + + Internally, the dict key is suffixed with `__`, and the suffix is removed + when deserializing. + """ + + __slots__ = () + key = " di" + + def check(self, value: t.Any) -> bool: + return ( + isinstance(value, dict) + and len(value) == 1 + and next(iter(value)) in self.serializer.tags + ) + + def to_json(self, value: t.Any) -> t.Any: + key = next(iter(value)) + return {f"{key}__": self.serializer.tag(value[key])} + + def to_python(self, value: t.Any) -> t.Any: + key = next(iter(value)) + return {key[:-2]: value[key]} + + +class PassDict(JSONTag): + __slots__ = () + + def check(self, value: t.Any) -> bool: + return isinstance(value, dict) + + def to_json(self, value: t.Any) -> t.Any: + # JSON objects may only have string keys, so don't bother tagging the + # key here. + return {k: self.serializer.tag(v) for k, v in value.items()} + + tag = to_json + + +class TagTuple(JSONTag): + __slots__ = () + key = " t" + + def check(self, value: t.Any) -> bool: + return isinstance(value, tuple) + + def to_json(self, value: t.Any) -> t.Any: + return [self.serializer.tag(item) for item in value] + + def to_python(self, value: t.Any) -> t.Any: + return tuple(value) + + +class PassList(JSONTag): + __slots__ = () + + def check(self, value: t.Any) -> bool: + return isinstance(value, list) + + def to_json(self, value: t.Any) -> t.Any: + return [self.serializer.tag(item) for item in value] + + tag = to_json + + +class TagBytes(JSONTag): + __slots__ = () + key = " b" + + def check(self, value: t.Any) -> bool: + return isinstance(value, bytes) + + def to_json(self, value: t.Any) -> t.Any: + return b64encode(value).decode("ascii") + + def to_python(self, value: t.Any) -> t.Any: + return b64decode(value) + + +class TagMarkup(JSONTag): + """Serialize anything matching the :class:`~markupsafe.Markup` API by + having a ``__html__`` method to the result of that method. Always + deserializes to an instance of :class:`~markupsafe.Markup`.""" + + __slots__ = () + key = " m" + + def check(self, value: t.Any) -> bool: + return callable(getattr(value, "__html__", None)) + + def to_json(self, value: t.Any) -> t.Any: + return str(value.__html__()) + + def to_python(self, value: t.Any) -> t.Any: + return Markup(value) + + +class TagUUID(JSONTag): + __slots__ = () + key = " u" + + def check(self, value: t.Any) -> bool: + return isinstance(value, UUID) + + def to_json(self, value: t.Any) -> t.Any: + return value.hex + + def to_python(self, value: t.Any) -> t.Any: + return UUID(value) + + +class TagDateTime(JSONTag): + __slots__ = () + key = " d" + + def check(self, value: t.Any) -> bool: + return isinstance(value, datetime) + + def to_json(self, value: t.Any) -> t.Any: + return http_date(value) + + def to_python(self, value: t.Any) -> t.Any: + return parse_date(value) + + +class TaggedJSONSerializer: + """Serializer that uses a tag system to compactly represent objects that + are not JSON types. Passed as the intermediate serializer to + :class:`itsdangerous.Serializer`. + + The following extra types are supported: + + * :class:`dict` + * :class:`tuple` + * :class:`bytes` + * :class:`~markupsafe.Markup` + * :class:`~uuid.UUID` + * :class:`~datetime.datetime` + """ + + __slots__ = ("tags", "order") + + #: Tag classes to bind when creating the serializer. Other tags can be + #: added later using :meth:`~register`. + default_tags = [ + TagDict, + PassDict, + TagTuple, + PassList, + TagBytes, + TagMarkup, + TagUUID, + TagDateTime, + ] + + def __init__(self) -> None: + self.tags: dict[str, JSONTag] = {} + self.order: list[JSONTag] = [] + + for cls in self.default_tags: + self.register(cls) + + def register( + self, + tag_class: type[JSONTag], + force: bool = False, + index: int | None = None, + ) -> None: + """Register a new tag with this serializer. + + :param tag_class: tag class to register. Will be instantiated with this + serializer instance. + :param force: overwrite an existing tag. If false (default), a + :exc:`KeyError` is raised. + :param index: index to insert the new tag in the tag order. Useful when + the new tag is a special case of an existing tag. If ``None`` + (default), the tag is appended to the end of the order. + + :raise KeyError: if the tag key is already registered and ``force`` is + not true. + """ + tag = tag_class(self) + key = tag.key + + if key: + if not force and key in self.tags: + raise KeyError(f"Tag '{key}' is already registered.") + + self.tags[key] = tag + + if index is None: + self.order.append(tag) + else: + self.order.insert(index, tag) + + def tag(self, value: t.Any) -> t.Any: + """Convert a value to a tagged representation if necessary.""" + for tag in self.order: + if tag.check(value): + return tag.tag(value) + + return value + + def untag(self, value: dict[str, t.Any]) -> t.Any: + """Convert a tagged representation back to the original type.""" + if len(value) != 1: + return value + + key = next(iter(value)) + + if key not in self.tags: + return value + + return self.tags[key].to_python(value[key]) + + def _untag_scan(self, value: t.Any) -> t.Any: + if isinstance(value, dict): + # untag each item recursively + value = {k: self._untag_scan(v) for k, v in value.items()} + # untag the dict itself + value = self.untag(value) + elif isinstance(value, list): + # untag each item recursively + value = [self._untag_scan(item) for item in value] + + return value + + def dumps(self, value: t.Any) -> str: + """Tag the value and dump it to a compact JSON string.""" + return dumps(self.tag(value), separators=(",", ":")) + + def loads(self, value: str) -> t.Any: + """Load data from a JSON string and deserialized any tagged objects.""" + return self._untag_scan(loads(value)) diff --git a/psets/9/finance/env/lib/python3.12/site-packages/flask/logging.py b/psets/9/finance/env/lib/python3.12/site-packages/flask/logging.py new file mode 100644 index 0000000..0cb8f43 --- /dev/null +++ b/psets/9/finance/env/lib/python3.12/site-packages/flask/logging.py @@ -0,0 +1,79 @@ +from __future__ import annotations + +import logging +import sys +import typing as t + +from werkzeug.local import LocalProxy + +from .globals import request + +if t.TYPE_CHECKING: # pragma: no cover + from .sansio.app import App + + +@LocalProxy +def wsgi_errors_stream() -> t.TextIO: + """Find the most appropriate error stream for the application. If a request + is active, log to ``wsgi.errors``, otherwise use ``sys.stderr``. + + If you configure your own :class:`logging.StreamHandler`, you may want to + use this for the stream. If you are using file or dict configuration and + can't import this directly, you can refer to it as + ``ext://flask.logging.wsgi_errors_stream``. + """ + if request: + return request.environ["wsgi.errors"] # type: ignore[no-any-return] + + return sys.stderr + + +def has_level_handler(logger: logging.Logger) -> bool: + """Check if there is a handler in the logging chain that will handle the + given logger's :meth:`effective level <~logging.Logger.getEffectiveLevel>`. + """ + level = logger.getEffectiveLevel() + current = logger + + while current: + if any(handler.level <= level for handler in current.handlers): + return True + + if not current.propagate: + break + + current = current.parent # type: ignore + + return False + + +#: Log messages to :func:`~flask.logging.wsgi_errors_stream` with the format +#: ``[%(asctime)s] %(levelname)s in %(module)s: %(message)s``. +default_handler = logging.StreamHandler(wsgi_errors_stream) # type: ignore +default_handler.setFormatter( + logging.Formatter("[%(asctime)s] %(levelname)s in %(module)s: %(message)s") +) + + +def create_logger(app: App) -> logging.Logger: + """Get the Flask app's logger and configure it if needed. + + The logger name will be the same as + :attr:`app.import_name `. + + When :attr:`~flask.Flask.debug` is enabled, set the logger level to + :data:`logging.DEBUG` if it is not set. + + If there is no handler for the logger's effective level, add a + :class:`~logging.StreamHandler` for + :func:`~flask.logging.wsgi_errors_stream` with a basic format. + """ + logger = logging.getLogger(app.name) + + if app.debug and not logger.level: + logger.setLevel(logging.DEBUG) + + if not has_level_handler(logger): + logger.addHandler(default_handler) + + return logger diff --git a/psets/9/finance/env/lib/python3.12/site-packages/flask/py.typed b/psets/9/finance/env/lib/python3.12/site-packages/flask/py.typed new file mode 100644 index 0000000..e69de29 diff --git a/psets/9/finance/env/lib/python3.12/site-packages/flask/sansio/README.md b/psets/9/finance/env/lib/python3.12/site-packages/flask/sansio/README.md new file mode 100644 index 0000000..623ac19 --- /dev/null +++ b/psets/9/finance/env/lib/python3.12/site-packages/flask/sansio/README.md @@ -0,0 +1,6 @@ +# Sansio + +This folder contains code that can be used by alternative Flask +implementations, for example Quart. The code therefore cannot do any +IO, nor be part of a likely IO path. Finally this code cannot use the +Flask globals. diff --git a/psets/9/finance/env/lib/python3.12/site-packages/flask/sansio/__pycache__/app.cpython-312.pyc b/psets/9/finance/env/lib/python3.12/site-packages/flask/sansio/__pycache__/app.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..02163b81e6ee4865675a204c8fab0525e5a4c5be GIT binary patch literal 33686 zcmd6QdvqMvdEe{{SOAMRKs*SNLl7jeB)A|cJ|u_|1(M*yCLxM|+s$hw&fJ-~_q(s}e(!tnU#qJtHT?cK_v*#(e@WB+j2`S?KqNem zKk{nYEzQsjPg0xojCwqj_9nffUcUQAeSG(i`uQFhEyLZHET0UH205=kSut5TTFL1^ zvT8Ck8sc;r($%BYoGwSYX0(RW!DQ`Z-Dn-BE0C@qt><(l(hZ{xoUTeXPBx7;aXOT2 zp4>3Hfz#DUw~V$TU1QWH+a?2}?VPSlZk+5G?cj7h(wjy%ak?S7d2-9>7EU)N^~tTH zTRGi?bmwR%r<;@8Cc8$vIK2Vs?W5Z{-IDZ9?ik&{>DFZTWY1_1r`wPYkA{(MH#R1B zPVO4r#pw>Ddq;aYy$R{vqq{l18R^Jq#G{#ImwwS6e&=qrVmzyod(hv#$X{b@N$#6` zYV;{i>qze(-Oq5gCJ#&=96jjKyaXxbK(JFrr`djK%6@Y0-`w^t=9qq?&#YUv3uUt+ zm;34}`|P@9x1;P;cPWu}m3?mAvO7>V_r$VC)-BtOve%zjcEH$W^t|C8J?hm?YDV}C z&Dd$~e%B|;j2@fyhI@ZV4`ENfDxONEv+-;qoyrX1xgwjGGz~MEjpHFOHW5#xkSHIx zkhZd>g=FQ?xN+Y6%(R)w;;F%T`lLBKXjy5IXF8EI>?hyZ_!P4G&rc^!+=J)M%oJ*) zbnRGtY{E36Q&xJ)w6e4G*)olUWsYTkNVA6*W!c%OMCu}?j-^xM2};$9)Ic_CB`!>7 z2~QeknIxdP<4W_OntaNJ9Ol5!Q5j|;*nki!{O)VL>(v#6E33DboKAjpv3qs?G6viPw zb~%2LM`?I0K0cmK8u(U~F|*TClV)}z&5tLN@yz98$pk>-YmNPQema%nW>*}wdz^0@ ziDo9uWHLIIPG!xj7y>IjW@a)xO@RyP>6DSL9EoPlxMiegQu%sHPfjJNm*a^fro7m z@5&OxTG&fyS)MV`10xgm<|`AKL@JYwr^ZZ+>cZE+l{k8wp)&eMuk}r)vVF(VgH+#G z+Q7{8jb#q(>6^kRX8NA#!$4EnJ~MTtFPXT|H#LiKO+6LayRR>k$eO$59Ax@{8=1>} znRqIbNcY93rXo|b`P%4Y{IVHUi^ST4I``vWM#ts4wo)Fte(l#Q?;QAM_#^_@I%0$BR_#C?b1q_#|jd~1i)cZ0x)2Pq%j|R-L(Q-35 zT47d>R)Hpj%<482GQ9Q>jn?qn+Dp0()VZ7WW`p4y_fZKh1$9URk!<#Umwd20ic*fX>`!1v3=)k?#+-*E- zY;wVfn2}OE%{XjqF37dVc+S}3db8Jf-p~PYpDBB894Xyj;{{{u8v)g?rzpQMAo3bV zjZW9M{qAp+!#HMabA3PH{%#yMx?JB5y1#MRL1Vk?`yuyt9WWv;WLF?%Ym%v^01gM-z)H$Qa z^-m3-JgsAiClh1L3iWu((BotDEu&{qbPO4-c(PK*PXLJM`e{JP=u`1b#xyurDn4oI z>2Xd^rVa2rJ#8Ta6LtB4LAa^{oEJfk^aKMF491|RnM5*4ZJ;K^?FQ(Uc`=d6TC@6i z+G0@DI$|U`F%o9uyj4AuvQ@c z>D&SyO8O2Q)}IsadZJN6nrJjEibo=P+?Y&bj3HL`_v?@zF&@;U6A24LdCs0or?wG% z1pdVBNDvO`?~Y zt&D;MJY>`beq?4dSVX=07;3#>iluO2R);`kl5~*b>M%+W9Zg^|B+HAKa0RIVH;A$T zC9>{iN8>r1#;Whm5Mjb#$5WsH=ojMx!Ig^(D;0!?=TDCV?WQ3NT_l{vEh&~B0TY

DV*ssMZ&x9)rB^g_TH-38q$fc~ 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 q!wVg|-#fp2;LPHIGxrK$Q!#tq? literal 0 HcmV?d00001 diff --git a/psets/9/finance/env/lib/python3.12/site-packages/flask/sansio/__pycache__/blueprints.cpython-312.pyc b/psets/9/finance/env/lib/python3.12/site-packages/flask/sansio/__pycache__/blueprints.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..dfccf2379379e612302e89e36a3703bd09c4e74e GIT binary patch literal 31183 zcmd^o3ve9gec$dqfO`RVcpaVu76d>51b6`W5JdU{v(&)jb|&t$Gmt1b zwWm${`+xhq!-1mXD0Zg{a`)Ts{rG?X_qX?-ii%tuuK$>L@yh-oj{5<S}t1H(|XZ{r*+gmR&cR^rP)Rc#~c?O2;0SiQRkTTq6^_d z(J|^C^IY_>uoK~;i$yH#Lb&*1F$=p9_FnYzT-Y`uXk9U$QUU7mjFya*UMyvKwi#(! zNG!U-i6a`)}2N< zEo3TNvuW89lzl=gVLVM`>ozT0in6^%87*WgTfb@9GL$`_l`x*Bvcjfi%Te~QQAP`y z%5L4XYz4|bqm?k8rn1eOmi43TNu!JwGL_x7Y1vAY?bk{ePgB{pP0LoH>{+9X7BZFH zZsDHg#Ol{Lu}FuP4i;B~xY}^>JJ?TjUF@8)wAcNRg6(|99gIfD`$hYdwcQ~Vqsr<3F@TYdOF?N$xQh7>OTzf& zk#Hz3V7de;d?gaY0I`HZP`Iqkxo{&AzbeG9hFt5FZzUqoaC%g%I8@2Se8c0xkx#0hTYMQVlk}1-N5=`G-+J>n$!} zNpOQKfo=&NZv?jNN?7rxVppWu@TRT|-nbE)md|*OIE}Ct68U%38fWYY`%OPe>UC;) zIBtZ|JmZ~0lpk&Cz5glNwCHUXBnmcd)05pEYZLj=Ce0GNeu_4&34Vm2E9cVi4Qega zl75O>ZKB;&gF~w!UZ#aMna^@9-FRwqf}XgwSd{i_VdFVMq&4UIDf$e4K42`%h(8gXUeE{hKOQ1ev%p~y+A?h z?S&azEIc|aHB-qZy0y@axErJ17%eJc1YAG4+%*=BcOAt>jdq2`MPQJwP;5_k*97)- ztZQG_a3o4NqAMJ|-ZdJz+%+);{2tvE=-Js7i^Rh_Ca`;hSHiI_h8VhH!DuWp-ldN> z7MPgII0gqJ(MWu7aJo)M90olIXsPY!R_t$ZyUDHlxbn(b+t(cH1zb%N0>$eNuBrh6 z&$@?e+B0igbu_G%SKWGU;ki_Kvs~W1bZMo$XV#f^mnYqI>8iT7i*FaFs=DQ>?%5M4 zt5mX9QGM%+3tvoCw8#}LOQS0lyJlT!cSX{@C0)Jc?fTpGsp_3__0HLoXtuTmt$DNC zxUl@}Pt)TbJc z$c;x<>W)%Eb=u)cIjUtxb;=>g4gp!}zEPKI?2#LL?grl5y3%;;f#aEnm;tUoWX4sr zhXDWl!*$>#U_fq!^5k4!Iho+4KG8CwV>}~6{t_cPo-%TZIvxUU(06~n^kF^c3?KF6 zZ()W{*z#gn;OTt$Q`>_)u>4JTyhv*|Vbyl!46uJboHb(?Z3)|TPO6QU=%wt#d<0Zr zM8`Z@3de~yt;XNs{}Df9x6rKS!9e+N4bhyDDx)qf^qY`WkW!<)8&8&E`AzOEd)_&< zYkf&rhpiZgJ%V|oegOyZ?FG~S@{n*fJPLkIBd(yM8qF7if;2fA7TSp5D#!&ybqdkM zwdsVl-Np7hZYT?uAcq|oK#a!o5eE>Qj05Gx!7or<3d#dRki}3?h5ANsjR}Mb74l6f z{TaTC;hc;^=cV{Sdoe?88QTcB%S-_y0URihrySm{U4XMVxa^v26)|JM-d*UBo z`@?JRH?17#PYS13D$gv~)+%dny}Iz~ye;kUrW`f0qh|4`W!t;OcZydXd(-Z+q`UTm z%C5W4mCD}PR9UlJ);#L~vRbT^-NFZzwTs8)%BPnL-*w+{-#xj~b`Wo~$JZQN zW^Hdc<{T-<7TK{S?eV3(Whrli>}^OE3rqY`^EcbS(Y{o>d}#UV^2Ma*$&}}y>^bvu)yg8w)EGpJ1OMiy#9x7gd~z>+g*&VWSsgGDI|t=DVx@x*yDji(J4l5 zGPcX()3~)45OrZhcrfD{92^@LvGRk18PDM0%ag%THKlNHP#g~p z4oW+yAT6}Cm2NaFW$}p(Vw^U`$8O^G8uyXKW_PT6I_=N$Yh`uob_#$p6ql?QvY>-2 ztz37qpbHp(-OYj?&Q<)dhy^e6oY0)!(X;N{Vt1{foE=ZpP_|{gkU|cwyo04-rpv3> z-4sW~KPf_pbuNUC=$Fb$@edD!9eq7V%n&V5pjgd+Vf(OSqiB&YMy#3ThIxn_MHdUi zTG0;Cq%iCd>%@ZBZ11SeUv#pVLQ{+j!poNI`owzC0l~$MybYq$l-DB)q6_sFiH)Kg z&*HG!H*srr4ceR7Bzj)6>#ch!zu2s#iY;Q1Da~h2qa5NkvDlPeVon!ZMXxEX)SSl3 zwuwGddYL(0Y!^#RY31fLR(88sYD%xbEOdxvrdjYKrc*38#Z)3@hge~XsiInyKQSQs zO)1r;lrFK-lu~0#=@zR@DYdA-2WkXk9qVSfSNMxt&T;KKr9Lcf@CU%MXCc>yNw5d% zH;{TKUP9xeqmVP9Paru_qJ4=xL~B4rBt})h;_i^bBLmdu@}9<08J{b22)yu z4KN7^Ux+}p0AM2}4JbeQ09Gd)3|(a%COWV21145Qtvo`?l{h0Lk7xs`3?}V#0y;ok zMyK?ehlVsNG&B@ICovbqvBiYZaj0CvY^H{Wr15cRsDkmUL&|_P@S?uy^Qf>;YQIRQ z5(y2GiY+Yl3WqRHO!>o>O-U4>++v`L?G^*Dk3w&wXnd&JSXjD_nNT!2Mk8R?)Y5E6 zQ6oDlvB=ZfE ziPz|avIKae6=WmGu9}pR2B&#csSq1(To@Y4nlW086QtcTbzTt1FIjfo1P zENh>M_e0pqR0^mfXR5Gc0A_Khy$H}kVKEHxxKp1e!i-tX8O4=pxiKDXjT4v#L!_vT zV0yBqLf1y-Uvn*4#jpB;3*b>r^K3BrXkROXsSHY?tLm~1^>y*?TpC{at^71yc; zzA-H~z)i10TW%AW7=>sBfT@7ZNl&OxC;9-o0n8mUx)M>)jj|v{4azKK&7iT0v|$)f zV>(oy8(S*falLX7c&+T`AD}((=kSH43#%&TLF0#1xy!qZ~rDmOx`#c(h(+9|{oiI%Oj%5cOc!lB4;#Iz&Ef>DODnc5q~ zUL`JpfN&ke8q_8Pn7a}ddwYeRKu@4sZ~L&eP(bMlxDE}4Mk7GsSFmyu1W+2;1G$G9 zUKEZzcLIFV7@8Dg2A-k~$BGWJf~bHIHVjBY?r2;ZAEjYu(>J9J7)MlIi;yVg85&{= zH&miFv|&69Az(D!fxT=j&-90&L((tO?N~{tltkc7{uUS4ljhtB?pL83f~MUH9lAZ? z{1*R?sw;wKhL5@9y5`8x7k!l%p-+Ye#+<5aS-#3MO+8vvE~c~AbzF%;v)23ybTKA< zw&SKH!p%4mjx2q&3vaq^nU&Br`Ow?i``hgqw+YZPMOlO)<5gc7vH;1+cr~1&65EVZ z2mR@)R$@6?fe@w`;Q;oAH6}h4kjO?m-I0?_i%HN777SFTHP9*mwxnPP3ms^8W$dv@ zsB)MnnsHqqyV5Z-aVhFvruZclaHbU75!u2bv%E2-u|z7;j1$nOfKbLgsBgkpyNBsM zlxoPPDV?Gl8Kk7=>84k$XjJ+sj%<)H=?yYwc5pC8_5}hl^}4AD$0RjRm+Biq*Vz6Z z;$w5T{m+}+CpDb2c&<=(RHdt$(lxE=x(@p1Z&-J8&gxG%Xc0d0alY~oO6!ta_O6sZ z3GKt0yLi5N?kN^^a;5ZC(sK$5SEgI7X(sh+x_T=f#p#2G6pgRDGU;we*KV18Zmp?{ zq696+v1ey(4;)pB&}>1Mv`dHc0mN*kJC*9uV>pPA6NL)NvJ(MQ{}2 zkvN6?V6ipS0;~d}F&YjM*&&Vt62%n36{?OYJPENh#8;4XgY1C97+D3Q@zJS(>v^JO zu}KhVqJGN8h;;&;YBEiyAvtvl;dm&(WEa!}{DzSUgz2*S%m_Y|HfWPfwt7!VK#9Zy z?bb~B;1%$@#s~(f=kJv=)>VuX6=O#p_ni)3Onu2vG2!e@NP^%>XK|5?(heGPSN{`uk^9yDdp; zxNpyd;^bmC-8E|FGRAh!IvnU_f-deu2%AF}He5jsR+;^VGNjsa*WtSIjQ1FHC- z8i6<1eDzus;5SHKKNj`{OjD)+-GcO`t+S1~l(ouG6p|=B?K75DiTO(ukCCz+`qpC3 zS(I`#$c~1TW1H;QwiJKh=-jwMy21E3ioFifCR%5C=(qUSJj{Hcn~RaGUdHxMSmt=m z4DpVd6YFJZw@v@=FN{mqAksy!mDH(F`Z&bIe)6eM2)HrfAOhHynxcfTs-DKynQ>0x zDBGB{dU`6BYCHs(|1Gv?%Q@PkCGKdt1NjE1y6ArW-ri z*T&$a|Bg)xA`?^fn$*Y^=_QIKwx->x&{673=~8r5iXZwQKb!<{d^MC&Ompd zNACmW8UO$d4G|j+kwr06G5`U?0!=IHmcq<1P-}ysx{-)42kD319+A2irTPsX5}icG-jM97m^D=5V#qY=2OvDRZ*^^j^; z(HkKIVOG&zQ%{X)(F8F}ie7fQvU1H3~ap-6W57F7F=F z%h?iEu;MWJ!>De}>&T#sp3EtWA0h0Tb3s_$3pa;6DG59I6V1^cw}|#AFBZ%ckSKg@ zFQy&NLJ2!scf4gqie;uSu8W?clX@h&5(T)s6NR{Y-YR@YorSORaa{yw7Pq3;9QoTH zA){)}^^W>}l+!|5y&e*e?fGlE&d)gKfUok8vJZ8N#d9V{FU)&MPQ!R*^v9vOoX)tA zt8`;7sUzVUsn{5g+<9EKFgM<}EJ!1&opXu4Z7WJmg&YYcjR|L}HUU`aD`g zZ?@-j5U)qMdH$tJj{71c%9)~>;zaQXDKl~|Z9lQ}d>E@-8`X>#HRQ`tq37@=d^bIb zqI~ZEGd}E(Ku+U${Yq8B_Z5G_C)%d*mOl?mDHbbe$3~lwzaZgDXz#W8%Y4O~KVB=B z@Uor~51(^koUV~P@n3l&;r+_){AnY*aw@^A=-1{&^s^Co^WthfmpaOFb(CI=5;HC; z?=;GMecGh2S~+0GVv(mBu_}8u_7V7_SliV+;N@#IHg2k{y)w7}rtb*22t@!^`D$k9 z%|l3svJ}B6V?8V8vF{epkdPcX#9mq?@lwom@<7hYQ?G}Y_G<$ z>Y9fb8G~=Y#~<@f_7=S$Ri#Ncn=XTC1O^MHu$H9T-x=7IRbRiNvDe2!vhNM(&Y*Y= zL2<^^DN}~+2I_phc>e0M+1|4z&wPy$H8FbHQZoisVQw|{Q*VYwt+1k)W{6Y}sK%ww z>_#sCy>XnRzcbcL0RVI{B9YdbtQf>=8=@F>gK3jgwpxq~Lp@E3BGcUE84u&Hvj(FY zNubU&>R@Jas02TIesc#l@c)TmLGw?S;_N5@jVYRbvOr{PB+^a0VQ|n^W!fUNX86`= z7tIfonp&spT1i;a)XS!|Cn;vyWh~@0l+ov7VS(8-_O}vd!?Bm^B*zEMvQS`yP6#A` ze@Gn1oBSz`XX??HV5NZ{Fh6IRLbfxFPZ0Qq7GyV6x$G#mE@1eycC(Cq~ByhAv)AvE45Mv;u0ky zEE$)v7ns}z_y6crra-aAN*5^KFy$+Oo}ZnU(S17?z5SSaHTzrt+eR|bReOoei$0clEg>am7OC7LET zD}ia^n0qj@b7e}&um!{V_$XXf6bqN)aq2>i+PR4$gbfRS#)DVgvK}MJWr%i(`BH3H zUq+JIhNTU-gh1sG#8$w`dM{U5f9u-9wWS?*OIQ56XWi-Y+FPdi(jR^)wg0TV|Lp4i0mQ5{ zpHB+slW_grx@|f1ZuCwxxwS8evl0zWv(`6?=Zfd!vZF5D+(yQ;#g}^9({1|F6 z?I~e5AZoq{^{bxU-j2IP$?g+t<<-hrm{fU(T;8#KWTm|O?k>6fiF;d8`<|EgJ^y}a zW#3u3{48d_q;|3IzOM~SP>QCur#qfRGZd39@ux}}<&wr^$&PeKcdFwlx#KBHlYMP# zZJo0x=VxS33w*^D&{&Kuo&1ic>!W?#wkI|!glIc5g^+;z>y}%pTdV5aYMr&HMj1K{ zf~>h$J|mhYszIQ?p^9}jD0pl)EpwJ=!5q$5z;er!LNhkQOCheScoOzU*ZM}m8-;H; z-f)KO5iVqT35b-5js-J?@K`APjIvbD%F2P}v2u zL)fq(NE^u~=;)CZwoimeubB^Ej3ZWH(6$kShT|H{zlDr+IO;bR%M{>*HCb`(3jL=u ziEj8XK?oRR2NbQ>!c$TV4KOAlM)nRO#0nQDk)z0Tx52;VXKD;?PH8N`=rf8EeRgm{ z>)SK8XMXF|1^2vl{zAIGaq-%Mc(?hk|L)88%I?{hU!Aw6eYJ~63_?-xz}NMWofEnk zeo{tMApHtz{7EbI`Vx+t9GaLoE$Kaj4W$!S-dOw+JJ0gcOVU3?Zs}L)W}G~6XG)nU zrX5WmB%d>BmNL=ODJPbS^@B&ufhSX*eZF1c<1%Gg=i${zzjn?YED<{=uf|uHeE(RK zQgbCmGe$G(lzJ>vt2;K4UsBc?`B=N##O*OQmKI6+8g3aotBlx15$9a#uAV*3IK!`m z6ptZhwq*=*%#AVvtfcCtFkROXX*yCB$iL)YrX~Ir+-Qj{1t$SRFOGyYG^Of$U3DB&>*nwyNjN&)crfY0O3Ei&^_yPKKWN+?fHkl zhrsLn>z3E8uiIX?-{R&hl2?S($2P(_UvjQl%dCCYHp|aihwV7n;&oMj+FDsmKV6HUg!wj@NNF>)=fTqf?ym6C24M%hl+Z@Rq1Ol#WEEI>pzV|>G}{|3I?XpPW$us z`s>t3YUqF6tbNc)4@~>CI=6iCrdhfj>@9j$+IWOa1 z-+7j4V5RhY(sO>z;UVXizqY_>?o+EnJuaHX%z*z_BmuJZy{3LHKQs43BaG~+ zyIfI~*!Dmcsw0GCMzvXL;Ha_6`^7V@?t;*JmP zR1(x;N{o-*D80U8&G5sDBC7*A74@42{!ZOX)Xcu+sm0g^dWk>9f<7dpE%pH;UTw0c zZMo!bdD7Fi>UknvRz7>20X<;;cacpZ^RdEZu@LD7@2DPGj6wNlh+y3t(mb-t^7LeS ziwWd64)@;>NL>KGc!Ym&u`9t(6>zXz95MCe`9Z4#Uil1K@M2C3xfB&U-6-x zm2=HmUg2Z-zT8}1r-?q~p5mk-JOHyzcx0R-k?2SeAI-X+DOC1TjG=4*ZV>4TU=#Fa z@2e6`2dU5Rbe{=q^Y2t+k8LQO28c1`JMFat2WOAHaboU7%F`fw8dQCp?S5PDUH%VT z-*(;iJf+YYDTIFA;U$qCs-GR(h-|mLOP!`Ef|rw^P?X=s+jQe+_VdrtnOF_-(iW@Y zoln!zd2-(+U!r97_6Lp*)`7njnP}W(Gtn2k{(guAwPYp{hA|NPg`FaTp{m<37Cs&c zQTqQ2MnI&0id6*dsMtU|sJqhdATxu@fnUW1{PuH42*Gw6xV;|BE(&$3X-wRy`ex9KG z7*v6V{j<>oRzqHc^e^~U_<7L_>05x)jGg99p%W6x&e?m25bt!a2~=~b0hKoP(FR)Z zH?*I&p%S76efzU%K?_v)OXB@)Pc8@F9l0}d-?Ps|3#4zOl=S=5qin?guc%9=V>fxx z0ezt=Mmk19`*pnYz~3R(Z{1|8D4%lt`@#E4TYvYMUmL?ODDK}VHz*z64EvkZyjd7n zDP_Q|j{kj-S)^|gF>V)C_%!uZcW z{23Yk$ma{KkAd2iq5f>hU9IEq9K9>`b}CyMWinLEnFbe2?VYmFE1YQ|H@(z#ofmCqlvYOg92_;x4~Xte(O%DPiZB#%}tp z=S*knvP~rFH+9rQreT~XqR-|qgGeVkr^b%Sv2R7-d_H|7*f{)>`_+>ifmf4~RRvH^ zyPu_riDIampM1+JYuZsH=MuRqoTjhI_iaENMg$(A>s*%1Da|8FdV+43aJyrX-l8x` zZsucj(r+Qc%!{joB&4j)q5)r;?y`$OfIOSPJ3w<8UI?fB-Lk(s<$p@{KXvaYzEtTy zmhwL*`=5LNg;oD)27QceKsQKzWa@^ZhRl?1Y}b4)Wn*eP^Z)1O!^ z_%vMs=PQ|Yu$HqV$e$Gw|A`qAv&?cTAhI~&^Mu3fR)4|4aDkRv2Se%K<8>qa?J)7N z?91Pe1iyWGz^_a8ccuKjvcLDdYuaEs#$Xs-6qHEjKSq~z&|&oXr=!Fh z8~+7|#5W%Y5_^ngCji_q$c>z|1$mL-nm(pT z0QXqb*8IsVGJ!lM(#vXc6ELH(FzXvxT;H_N(N@s{&jQVQNxljymxc`bmC$)NI+jTG z&Hns&^f-!;;bJpOcRqhDgE5@bKg12E29-&)D254-d2~2B97IFXExIvAk;WxxR=#5P zQy==QO&`k!S947Ur0Vj!5tUsHIi$tv&<^RLe4X?5Th0Y%%C}AS;p-hMzRu+r;GU&` zZHW3s$|p_wU!@4vTV|6a)^14auA*c%GZp~e&*MF*&X4GP+M>@0t7~HMWW-aE%fe z&5zSRk$R(vUS^Dc z_R$#sXNAx#N4fHJTaiV=b*STjZR(T$2p`{`!%pdhDO=|69t&TRcTBe3@4 zYyBR@(~KoCcQZDH%;)R~Rrht=rrq?Ze{G`kbVc)(V6CtUsF%|_;{iHdP2OCWE}4FY zOYxw1sZ-b(hd~qLGF=Uy?E%&E>lx-6rq!eXh~9|wG_qrfa+(fo(li;>vKwYGTC?=a z1X{BL$okVYy4iRYy=!)}YMj=vdA!fEA1?chrfHU>61p*fppeE@dG%NdX|W)&YF-Ly zv2>h4sewX>C8lS(0>2g)zI5!BP?-Ie5$z8A!W+vsoinqH5z;*5*$}g1w1&uHs5C?& zEtW(FC6+?%^@<y8S8L{)}#aPPf0H+XK3#>GnO`GDYgAGehCg(ZNCZ*$p5z z#^d(1;w{6rC*5vP!X7IaVftZ-o%msit2|fNn6y>lCm){dOK;nr-nT#9*n$&m>F(Wh z7uwe=TkOYq_QMer0K4k1UN2-p{2bDrbtenDxSHm5Hw${Wn!W2qELhA{G^~4B5I?3= zzh1(ErCeoTy^ICRDYk+I{Rn=_+IrZ}JM6{lat;P20G=@&kHRn?w+woMhA+#<~wu46~xiejYlb7_|iSr0}t~rY+ zd#9egQ^`)X`qWzSTyyUI*p8=~4WadBs&)S%%7$9u{7=vBUiM_Q;$6?)sbt?!EBczJ zR_ZIO6@8^A^%c)eYW>(!XfIJ)LP%YZ$BSFHIPE3rk{#<-JlC8pAKUR%>p}=;9|%_1 z^tP+hi;37cy=pzk!|G|wSC7%pPpHQVw?X@;eFy!{%kU&VBZuF4k+7k-jAc9~6;go5 zfh6MxD`M;*PR7Z+Z9$@9?E8L_z={mVGme=0>y?rdQ3?)mQ;5(r5|!lA9BtAm8<=b3w+2me8|;*$ThB6 zZLc5v>cJ0fRclq%Z@X^0lFj>)O}+PyCYzp?s}3c(igao1eB-V5h4y6Kj=N`5d!Cc` zz;yK&=l|@yyyx6%>A+2Ix~y)#=hnW3eaS6dccs+c)AHWat7T`BoG)M5)zartq{u(} z!W%Eny*Qs(-kIt+Aa@*CEjoD9g)_j5FTXu?dn#?)y1X^D{dsx&^I&BKOOmSt2CJx_ zKXmKF!ii*k&%M$V4&?4TyIOuO$(5wbw``V@r~675N^0gyZdET-Cu=+I?o91EF7Gm!ctpNv=zIrx%!$EO@U H*>e0}7uii! literal 0 HcmV?d00001 diff --git a/psets/9/finance/env/lib/python3.12/site-packages/flask/sansio/__pycache__/scaffold.cpython-312.pyc b/psets/9/finance/env/lib/python3.12/site-packages/flask/sansio/__pycache__/scaffold.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..4d7b697e91c88b0d0bf1b34e91ab16d9faeb6d39 GIT binary patch literal 30223 zcmdUYdvF}bncwUSSYQ`#fOwOG2MH_*F8F>x6e)^ti>7Filp{#;?s8`UEV$T(XBH#@ zgJ($Al|kD%kvaQF#pe^1QbkZ?-!ZwW*neCquB$pHS68X*3cOl)OjUSwzEoV5Kh`4a z&Q_AD{J!p)o>^eQht8+OLt>_;AY$l5R+fq_~pOglpL4qOd#Z9`>-Oci79GzF{AGmJOG&XZf%nPfxO9qH?&BW1rB*pG1ia6JoGBpW6ghZ_;DR07GSiSpq! zEF4TWPqYlTuy9qfb)s#!%_XV+@m*Fk?59Tcs!n!HbPjjAB)6ol{lNSv@n`I` zR!FHq{Ik}Z{ZwiZf7pJvLL=^01ixSRft$w+_pA!JUR^VO+{$M^OT%3Tb^WSP8vymB z4b2KUYSg!C-bUm-ZRN0^j=Z5&^EM&xSv!vva^&5#YTh--`_HT#_S2Df^Qw89k@pol zj}>y{9b7eU3-U&-9QM^H?EA-tCI4w7uaS-r<&xNlN=0lF}itVyDuj zbmH4CrCV8x=WeA(S%>GIX?Lji7X&QiG6JzwDxHaC66utFiry7p zbD1E-Rb5Y0^?b*)^wgx`IvS>z^XaLSV$__C#6~iz7SYr%PpNvws687wua2ZORm32P zs%dF0G8RiINmVl{&qgw8OjFXAQbq@bt@6^TjCvV0vdT27&qk)Sq*XKBXyNY{W63EM z$y7UK`B}7PDx=0-)=1)6jz7>o*Zm9vUzfh_z9C(e#vKW);5XcgdtRD%kGK`r8^J5C z407>n+-rsGXU3$gl9Z{iVrN}fB?~*O=NT#FIaO34ACj-53hhVWJE+dAH14dh3GJ%) z12dM$+*Qx4H0qjl{VUfG$`aD7`(4-Xxz0%My9lM4A{giRg@~?ZrY0jJiBv+zxQBd( zS67oGhBu~->PFdxOYG?yG0H|Fsn~?7Q$=K1o}2q5IyjNa3?9aKrv~F`1=ukd*LQ9i zoCHXHaPJ^s#!_*0P)%JNOeW3`PEKdW(y8s?t=k6mL`K~_8H-~(ys*ZtWYbJkW%%ASFqNA8W?X8 z^%DVQqf%Xzs#4jc)Hq_Q7^GT9Oto5F64HQDSCpzo*{sw%VruPL^Na$c``T0A-KT<%p3T zY49Wv1jb>@=*TB?6>4}MSN#%0IejXYOis%~u}nrAidtkLiiV`8lGG4+N=HIxC3Ir#@d%MQRU48|gOAFY zv>cOp4Ap}tkw?JDb^4~O+C`NEp&Fc^nxY!`4{9=itY!wr%H&IlWRgmbDN5<0i8m7a z9+JusD*anu#7xlY$-MtLqqbm z@D`R&tHBg7Jn>}0@PK<5UP8fBpHw0&&&sFLDb=Ws6k&={YrR{;7Z>sbU=i!_kchAV z5dZ>$YgURNieIyCya|C}7J@;9Bs+G^dhv#w=9_P>$swJTlzKieAzks!`jD4OW*3AE zDI)5Wp%$_WvXNxvK?=VWZ>PxATXBwbOhcvkN2Ci_c^{E3_^@<}lxefRkGc{rOBO?Y ztF8D)z!&X(L^_fb*flMM+^6E!8$D?l8fXw@1a3$fF=QDrTvi92k+cpZ3b{36{f3v6 zgZCvS7;r(uzb_e^IIqO^&-7TrO*j(4?94J@Ev(80~M+> z0uIDBs)|vv#(cFf(x|cKy-D7*Dym$Cn5{y^BGti+Tx015mIA@!H5xvnUDS(cRFSfv8_iVxmAZj$G|>l3y&)--D^6uh zX4Liqur@@ur|3q4llC-jI!ys0)3R)igw^dcbt^{VIm+-;+~%Z0qtwwi@4e%1x!1Xo zo^4C(!u0GYR7&z73*8GeW&<5}Th`xF@*8&LHtbq#**$-v;FsEZ=DpvlF4Ri<_EW<4 z2fb2NORi<>VsKlbT&k$L<6rln8&QAgT?}>>d@QExfxIk6UXiB9jJcV)v*Ac~{n6~& zV~fG#CV+lc3J1vx>2<_VA%E@f=CZ25WHeQfs#AD@fyrg#`K%xm;{xN6$h^J_^Aj{5 zQ`WU&>G@r^;`yErij()0;o4`oWW%*T^<-P$?bm zF4E{kV&|m0)m>SC*UJ8<{$tg80|BN>;<@~KZHG;BO7-|SDap$&jEx}f_9w*JFCt_S z*fY|!E99OTBWWylUQZ{XjLV#zrXEev;BH@sAk;T=yWQf%sKpT`#mda&s|vqtoI5%v3Tl$JnY>Q+j@ z+I(PbF0eKm*m$?0>BjEsyKn5fzVDXzz3O+WZ+r7w4&}BST5LF+4IaMN(7X~=i1M>B z`4R%ezF+ILXGN*GFzd27!MI?+$ZB4S_<98v05CCv&o0JvX56m~hP>Jt#6Y#zSud1n zkUbKUtaIMy7-;wyRn(n0NCa=S9{B~n=``EsqLr%pt1ycsl<_pp2S#1h9Kx1zT;YEXl4@^il z^#H<@l|tE;@J@k4u#Rw|z6=$Ny0MsUNnjiUXW9f}toT--u4rOiQ3y)4jrp3cTus*k ztPq>C{>>|!Eyn*R4{7#m!P0Z-4B3O6gazDG)eYxho1#iB8DAzx<*!nFcm;+d&_+c+*;~hvjFd$$&r>eWu0>Bt`O=%q$+lv@uTF@U}2l zhxPDs%YGC}tH^HRxK)rTfiud;X9jEqjyd%xGFZkXT4M8zQLyQtougNha+kA8BgpC+ z;Z>b!5>vq$jio+G-;Lau2eoV-tjh(~Wdob;HuSvv?0d)FIriSkcTV1J{NdVvyY|P8 z`Ge` zz^0%wxz6yh++e&k6^t^T-0*6!HyPz=zAU3t>xfNp-JvSNQ}I;_2jeY@@1TC&iHzvi zpcHJnS&nYKTi>4TcyY0w^<7QteCExWt1~xyb2a-G)-3q5HT!NKLpbZ-w~}yBuY$h2 z?)M|Wrkx-Nh%hhev03*A=G0^C_?0tbu&>3ZGR&GZL{%S(vPMT?%Ylg|8a4aq>6g2Y z9XZ?msxXyMlUJgoWiFwwh6gzy!jm-lzK4s*V+d;r+;pl267gR1V3lenC{Pe@eQ3b_ zR-|D)Wbxx$>lYdqE-kJizJJ!op0FFdltr7MmZw&<+&h`pGc#49>GV2C z*s-$h8y0$RmoL`r$@=&FKf-|1=bo_X9^_c9<(|nY=a}PdH`=XDQa`Q7E$$SMKJCy( zo@8hbA31sC?2#wK@iLxiwMLdHYEsRpGc{s>dBlOzL)^b`_;%l7%}~}q^qcF0FFi>g zoIZH=(D5hh0w2q>S`YZ3ti;D=sznE|_hY5o-?y;icJpG*-mHJ`%JvhXWkinbXjtWS z(K;{IbKUcegSg}F-An3zh0j+n(L z*rDyhNlh}vlLohb$vPmgnBxdW@lq@=cC5S|POonQKH3>}>Kok{5c4UfS zC7mP)wu-?G2+U`on8#ynR^5Ca>!lZ9eddd>d`W~zDqYXOiy+Ksbbt3?cSsaN-yo(y zwpP^3{h^_v5A=~QiOSu_)nqa~Ab&BfC6%sj8~7Pjm4~plFcgItyqT4-nfDVoC;2v5 zR&oMH5)_sNCZUOE_;QT39>FqN0ux&ep(Z<5Y-lt@?Zl`+A*6)Ss09{EB3lK*{J}Ws zslE)}b+$Sqa#J+~k1EPwN^GnG(WuS6ko@?OgNKpUT9%^bM5E82K6~Q%Q)eh1iww;C zFUO`b=?Pl=p%n(lFb(n5DH?XZoIxrR!xd7=u}&iDXQnjKXGlJBIitm7^VMt);Uiiu z@=$%mLfR!&yD+0pjj|CZ&@T|KnPRG4P8{<|TtqCHRr*B)zT<&2guAp7p$J!oE0DFW zdQ0h~@JfI^V#JdG6q2-DkjY4PIA!>)fr8NFnM_X_LFasc*`^D{YhR@saeR&Oev+hg zsvtQf%yI5tA*8dJEkJz0%kM=X=? zqCg8)S8W7Q4r0b?`8-vLRtY|tlm20wr=khwrP|i4zlGB?yw_ zy@r&GF!ZHj5A++)?x`-CIuD7!nV0| z!gyIMsi`q#8Vl55juzh}dktTI7Jw{j;20S~!B0z_9jF*fUW!cvV`+K3m?rbZVkhw? z%%*grT17NmJ}*>xM>V5SCx$C&tl`sYa!MuhR!mFK>avQWF;B2c&w0=QrX9>zjAx0m zI1AvO1Yi+h90^D};P>b_a|*}M|3z$bVoJ{dtbhRymyRcpOW_*Wa^Z!R%+v6G;GEZ* zr6RjI7kjSjtvIxOA%=RMG_*F0k4$FGSOEvvFA?YxF}hiTBs z6VoL0(3--W^x&{ts_7O>mrlLig9P|<-ETpFbT+23k-o+~aNVW+@s> zT@yH9jlYSkjE^yTY;gpJ@uYzf2@zca+Cel_fGMTf{o^U8dKvPARl}#d)ypwjLVg7G zv{UgR;di2+=9f}RUXd(gBA!+7OKt|bxJ6Dv-ltaZ^aGmT>d0^HvjI*0Yu z@x1EVhd0t7xHpVT+mCn41()dxOhX`mP!PDxO=9>=uh0yv=9Ewl{(_K_P>qy>fz6~0 ztjh)0-SX#xAzKG{-_!v}Wal~n3o#wQv{SO0F!7&i0wm!zp=gKWfmM?~rD6#NT!R0; z*9`^0?^FPs6M~Ew0O`8_3IeMwkkCe+<(J|b71~;<6=ZvT85$Z}Y>oXpfN`i3))*4` z(x%9X6Eg|YJGKy53WWpHk3zgN@r-yXW>Fln3*;Zh*8l=L4pMSV#@2=yExAG3PeEcL zL&1QY)&%w-B`q;95}Qnqj)IXu90CxHt@yEcot6>PDM#s#BcU*1quAd_lu9^DGlhzd zP+_I!3TQ+(eTyWNZmN`7jg^)Yf;Jjvb$(h_&WEk~!cN_9hF=ztUUkSsBmj$Ux7<8Q z*D|F$MvhX`V*LSX8>Ak{58PH`Yhy8p2dT|b(}6-}%ltGfDi4xE$9G*Ykpm3_3|f9g z3ehK~{fFhX`<|vc7o$g}G$bc?PqxE@17vEaT@O8z#vT^<#|o%tO~=;QMHsnav=&VM z!D*P(AVG5d)N<}MtrlqH7fF;rf0A1!(oj;4WCE;uS;evhBykH%;g>mWRc$!{S-29L zsJbk-4b=$+odaQ-`cPyyJCU?!hmDX4*)c~dr{%~js$@L}*iw_pQfw#Zu!*#2wdMQf z5Qk2I8Xm;#H!89IX9|o)8PbBXy-ti<F zKzRTBrbtbRTCPTE_~5TjXr2Wr(7r*pZ_@2sxE0ZrDh|M836ACLqWJ&rpentLs>nIN zocC|a`8Q!jt9#MEGw zMzN7Jj2`I^;j199AttAYrdspdL5IkOYzjr=+!{s%$fU_!7Aev76WBfrsf{QQ?X?jF zu!_duzr%N)igK7dWEOK?jmJR4Xiz{zr&6ZuBwz@#%GU?Eg_Ij-7}X`OUuzA9B(_*e zWVH-%l*HT!%R0lhoHEBZMtk{p)=*KR07PaO>Tl5yL9R6zCTRmqqKGsuZ!eIEIx}`L zoxpw?Sa(U36UA^z6Y!@+ftDmgW_wPsCK97#a1DWAM>Uz|0QD&}4O@bF5|)@_mH-ru zX0+*ObP!8C`@q6WFYh;;|jrfgPYD_BrfDYsSE zqB#VzOOohsRv8ntoXKRCWJ8+*QFl>|Wm=uBFPTc2fFgQ{NqCl@CD^P9k(`NH3x!?= ze@xO-AEB2CxI|~LFCEqhnOD}TW4yrQ1s7i0n-+Sw9&c8A5-uAjdH-O}KX@Cm;n1?d)-5(B| zIcWP^aPkBEVa768B`pmQBB7wy+~w4vKC;4CL17u*f^3~|$l+E+OA*}5!l7XH@7S_q zr6cGhSWW~6J8Ue0y4KGiukIGw$82kqM;0D1(Czh1-+&D8Hoti(J;nGe&hv4!$y9aC z8Lgd9z|Ro|dt2XpbR%#!5nD+*LM>a_9NJ}`h$Zb4v8;2Z9@#PrFbVbM5*1TwRRwL^ zxn+ypwtph~BCVViBNLNEig?N+nVk(pP%{%V8L)pe*Aq~QY!*q+Cg_K8JysJF2S5Y_ zEZC)B2X!8(u_e4)d?jRdn1HPbQhbaUtS2eBYGVlzS`!!UoX(B}!`w;5Dq&#-JCy+L zPjD29XOhzcoYmN3DXiZxbFeH$^|287NgDBdiVRpOSjR7s_gR9(UhqE1kwtSP4toqV z8!;zj+U;&DcxVWdSd=s~vpe0-aM}*^J?4HEgJJzV-*m>cNN4R=x($oM^l;JPanTi| z%XAhX8W+JKZX)9lnB|w;+SWcg^l9TJohKDSe@jVk>EbXh9r8gScp= zocR>cpxA(XY@I$L>*F-Gr~#N3U35zpLJ0ff3ExFDZbjiG23kN3P4}+T=CNJG^KpS zx#?xrOIR=}SfOu~gf1#J*m%&JQMdgOK>_#j)f6Kg@v=GdnN*zU`0nt-#? zHVbS`hH(>iN?;_8zk@x3Z}1}o#hSUzj|G-Z>0ok?J-tuCyS+I=rzm1ZMA*cOfI`At z0Q1KIG!c&O%;Aa+Sr;OV3Xu|L%^{iT?~W`OQY#)G>qGk5>|p1seN6( zZC9>sS9bUD#kLbyYvwDi?O577H1Ey(*X8`{Zh3Ql95F)6Ehj$o@8V0g&dEfMU2LF_ zBi4CP&8%b}8(~c&El?rZ`*LR`8qO=O6b2n9CJLytu1qC9uuJ5u&d>oe?83Hlx8nVt z*kb;=%RXnPR9?N+KF5f*Dvpyw&9Vyziuk_g`M|8hGKlt>MCdxYv}$Z!aE;UCT6T@V z>ulDgc<9+9+2=g=N*YeIEvkn^hnU!9DxTNfm!!*{m!wOsP+2U1svJ|zRUT_C*4z_( zUL}h=Cy-boBHICxV78Zj3K|SyhCoVu#Ksio@t&CU7NuA90Z5O`G|oILn8G7U12zgU zw2$3{?Z9x$4@@91=sOiZ1b1+UjK=Ftq?{Hx9Ca1oiKsu({wauj;tl z5zY=ilj}Hmy#m|CTQ|<1_<5k|TH@W-JJ>N^-@eq)acy%!a?3Jqb@F|Wx1qWqd8?`) z;KYr#o1u4Kx>GZFx4vVkzTw)5eB*{(sQ-=Pc48b)3+<7N32&gv`Z>Qc$ zWg7;v!GU{tRjwV#2D^XtV5ijB@v-DX#n#A6Ynrnyp=|R;fZ9a2rj3BtTn|^hmX1P& zx2~h$LCQ~b@@f4S70;GSe_r19Y?lWo6yXY0^5dfh@sXW4@ku8?`7N!7Ps3<;GI2qD z88NS#hr#h9rf8cI-HV7!EsomACT;R9z2sW6+U^`B<_Fzd^+|k7U9xz#&ex zO0l}~cj;?@T4}|w%~^ELD+kYd!^?M?iEf;!ch>hPYI^ilOYnkNX=bI66-)es1Ei1@ zOJ~CHSPEIOYeX!CtXMKN@U#@NVw*)Qg%C@U!Y556{J$(FF(D4kcpAHzu(RsRPE}@I z&Zv~7>AZ@rXTrxHQ$bw>fclb=36mIFUCJwG_SgHAoaJGKcH?AW4DGUNVX+z;JoyQS zuZGq$(qdFbBK*`%9H<+NM7|6s1@6{wlt&^;I*#a?2&5!10lsrI5@E*_@v}&dQMsq+ z)`^?p#}XSmyqe7`qYPeekQO!akL9z7qzvsm-Nxxg>VTG}n@+cjbepEzEZs)v_8Q$7 zdi`?>y-Bz0bo+g}eTQy0==O(nBWcVC@&jPF-#;UT+HU%|o^CyKBhO}b+kt>S2x01X zrC+*heEveWR9W-2&n;C}eeJ|j*ZR3r*FLxCUBA@Rm-RMY8(;MHVK?BOeM=iQF717K zN$xFFopk%w-fLx|BBb;+jGCn z|*0(%H#U4cSW0T#Dc#O)PvrP4hm(mf^84T-oRGp^Iu zYQ`Z{*iWVTCAoKL^VX%UI}3q>=)8N?bp;;KXR$}!tQAe7RD=p)7T4mdGgBf|*umoJMI1tfeipY*#3598)`iG| zyV_TGFVI);;fY#SZuqzyArlF;Yq2wKQ2eeOhs{9SOEbMhftx7P)aF|vR;CD<@FE0{ zZ7|h-h(!N^BrOsRpa9}v@un;epz@x{cAr_qJs>Xy8qL$Eyd}E3I>P7VJ*UMH@ z?d@}kAChU6bg9Pp4>u>_YT)?40IrP5@7zIjcb=O>4GrkD@%_iae%X}?S`noVIv;PhzS_^y z<$OTcfXjM*qbx%_kzMm;IONFthQD;59hR&aV&%Q!OHpr?(3%w=)8KuNsP#IlWcxYm zv!I`mo;>%H=O{heRvoP8r>V=sAu}rg$rAnlV2RAIvvo~a<^nJwBF6(m>TyvKO) z4_X)@igzO>knKvTrTNbtzKzb`hn*XKi(9- zGf|z;;Tf7_rn*QbjU!pz;Vp)re!hW>+D6c?DS-b;>S{=u@cHs9<}nS-mRwp~v{)3d4)D5|Ty*s{ySUY5$sP7r>#d zIPQQ6#pXGhu<6AwDMlOAW>cEg;cXZn!;xsbwfIGiw3Zl6q>OSJKL(tXJ$}$&CHL;2 zFE|Yxe!)gL78_{1Lgh?ZG^*G!%7D!_y&A5Fd9X4&FIn^?d#hPiwDuoSX}ugbSX^*D z!~3{?WyflZNc0!fl`#+#^y9s@_4&5JT-)Gn&tlt-oVR)I^Vhasixs>9U;Ew0&Ksw$ zpUO85Zz@JKjvxKZ-g<;yoMmTzL5rac#E&jxyK zP3QY|=lXX4=&29;j{dy8_wD^}?a#Mw&$VyA{oG>vGxI0!)wJV>I~Gpn2hMyraOUUh zHoQIi)+`+>dhGf!uF~I{&G((k^_^O5eEz=2E!STQJ}8rV`tH;4-|O9+?>+uu@A3OS zydkQm{(21ryPko3_t9MU(I0;~*L~tz&CksPTMt}6aO=Qg!}e@&J7Ay?I>i-{?{0f< z_dC1aJMhkd+k5ld59PKWTI@Nz*l;8pJc4w!^>1Ffdg;xtUj6FL>HNCE+`7TVnk`xX zmR~(MY)kEJqS`vaII>ffBcI{nSBeCTg0R3YjUW?8>EaI{|fNqx`JJ)WQJ zcHv$m(a@~GpX>fv4IkO_jz4rLthy9OR1o;k3#o1LJjeZYzZ2 z;Y^MMB7uWL$v*msnl@N@?WbLaSTOL83w~;+v*@PcV%+@qK1E5w7R*ZWT`8L_duT~+ zR+1Oz;6F~=Ku(umHb;Dna=ISTB4W$SE*n0tA0|1k)*A`*k| z7yFSOGLSMuBHQ4E#eWsH99q^TnU)AvCD9bVih_ND)-PXh8cHTo`!v_Hl!KRH%EWv{ zHI2o6la-N`n*fvHQlS+Xk%AR7mQdje5FeYC`$0jm?;(-GUg%6b95R1Sf~q8{O{~wZ zI$suIV088aS#rO1GVHV-=Jkq(n86y-xR!w-0>57*_eY~ezgZNGh6WgrsI`F-ZQ*Ky za3W_7Mb}W@QEPCT4VnnIAZLO29_9U3ijA`(NWtJ8`N-zcMgX`n;a~$CK1qYa-PITv zt4nATXVJK@%EjS>j|yVwvDLH6=gF-$g-u7z*n8mqq!>tR84cq2U-mR^_QGUJr zM$Pq_cRlY_zEinayJ_wO$h*HLU*4Q6Z@w8^EMK25-;pcdar>n^<=A%Aa&sVCvmxu> z@bh(DZ(n-r(%V-MYF^JUk{NExnwbKli{-`s!m+=qegrH0m<`(Uch2K!KfVD+23ukOwV zh-Kb9x)|um2ST|(Xfd#9Vd}%c4(qgWVqUuz8#XSS%r@-F2KNAHZTroW*_!^Wzn@B| zz1ES%;lieRr_ED`dzlhBQ@h+&$_;yD{6vzyc-Z!27FrQIvxb}dxD}f$&e*XB`*mn9 zS@%Y!$YB;%JK|*!3YqK#Bnp#krTsa3*Gb~h?zjwzLKeP(^TrECR`MO5@&%lZBBapec=CAV~ zuBbE}y)h^F??_aged+X($f4s$4n23`)G@<{-*1Uu&}t}u8QXgo;2fA<349BqBqNNF{io@HAmmwzMHXf&3z!_t~0enQXO z-6Eh7lQiVBrc3-Gz6as7^)q=Q8EK?OJsc?y^J7-T2Vz)82R^WcqSKBa&J#(~Xw0t4teihY5>6{<{w*_v8vcD;THdeyZ+seO0s`!~y z{WGcZXHxw~QqMHVf#pUbrl-tlgkb1l`kU+cONx*p1QY`*|714G;O`H_xj#!=iqHEzx(;z?&t3`oX$$MrSjgX z|2(o(t(pJAn=f5`>DuhVw*033xlQ};R2`VBTw2$E^UH5fzcsz&?Oy24Z~T02FW8VMECnIH2Pd? T@7Hd0ZGAB8+TdEttZ4riy}zF) literal 0 HcmV?d00001 diff --git a/psets/9/finance/env/lib/python3.12/site-packages/flask/sansio/app.py b/psets/9/finance/env/lib/python3.12/site-packages/flask/sansio/app.py new file mode 100644 index 0000000..3620171 --- /dev/null +++ b/psets/9/finance/env/lib/python3.12/site-packages/flask/sansio/app.py @@ -0,0 +1,964 @@ +from __future__ import annotations + +import logging +import os +import sys +import typing as t +from datetime import timedelta +from itertools import chain + +from werkzeug.exceptions import Aborter +from werkzeug.exceptions import BadRequest +from werkzeug.exceptions import BadRequestKeyError +from werkzeug.routing import BuildError +from werkzeug.routing import Map +from werkzeug.routing import Rule +from werkzeug.sansio.response import Response +from werkzeug.utils import cached_property +from werkzeug.utils import redirect as _wz_redirect + +from .. import typing as ft +from ..config import Config +from ..config import ConfigAttribute +from ..ctx import _AppCtxGlobals +from ..helpers import _split_blueprint_path +from ..helpers import get_debug_flag +from ..json.provider import DefaultJSONProvider +from ..json.provider import JSONProvider +from ..logging import create_logger +from ..templating import DispatchingJinjaLoader +from ..templating import Environment +from .scaffold import _endpoint_from_view_func +from .scaffold import find_package +from .scaffold import Scaffold +from .scaffold import setupmethod + +if t.TYPE_CHECKING: # pragma: no cover + from werkzeug.wrappers import Response as BaseResponse + + from ..testing import FlaskClient + from ..testing import FlaskCliRunner + from .blueprints import Blueprint + +T_shell_context_processor = t.TypeVar( + "T_shell_context_processor", bound=ft.ShellContextProcessorCallable +) +T_teardown = t.TypeVar("T_teardown", bound=ft.TeardownCallable) +T_template_filter = t.TypeVar("T_template_filter", bound=ft.TemplateFilterCallable) +T_template_global = t.TypeVar("T_template_global", bound=ft.TemplateGlobalCallable) +T_template_test = t.TypeVar("T_template_test", bound=ft.TemplateTestCallable) + + +def _make_timedelta(value: timedelta | int | None) -> timedelta | None: + if value is None or isinstance(value, timedelta): + return value + + return timedelta(seconds=value) + + +class App(Scaffold): + """The flask object implements a WSGI application and acts as the central + object. It is passed the name of the module or package of the + application. Once it is created it will act as a central registry for + the view functions, the URL rules, template configuration and much more. + + The name of the package is used to resolve resources from inside the + package or the folder the module is contained in depending on if the + package parameter resolves to an actual python package (a folder with + an :file:`__init__.py` file inside) or a standard module (just a ``.py`` file). + + For more information about resource loading, see :func:`open_resource`. + + Usually you create a :class:`Flask` instance in your main module or + in the :file:`__init__.py` file of your package like this:: + + from flask import Flask + app = Flask(__name__) + + .. admonition:: About the First Parameter + + The idea of the first parameter is to give Flask an idea of what + belongs to your application. This name is used to find resources + on the filesystem, can be used by extensions to improve debugging + information and a lot more. + + So it's important what you provide there. If you are using a single + module, `__name__` is always the correct value. If you however are + using a package, it's usually recommended to hardcode the name of + your package there. + + For example if your application is defined in :file:`yourapplication/app.py` + you should create it with one of the two versions below:: + + app = Flask('yourapplication') + app = Flask(__name__.split('.')[0]) + + Why is that? The application will work even with `__name__`, thanks + to how resources are looked up. However it will make debugging more + painful. Certain extensions can make assumptions based on the + import name of your application. For example the Flask-SQLAlchemy + extension will look for the code in your application that triggered + an SQL query in debug mode. If the import name is not properly set + up, that debugging information is lost. (For example it would only + pick up SQL queries in `yourapplication.app` and not + `yourapplication.views.frontend`) + + .. versionadded:: 0.7 + The `static_url_path`, `static_folder`, and `template_folder` + parameters were added. + + .. versionadded:: 0.8 + The `instance_path` and `instance_relative_config` parameters were + added. + + .. versionadded:: 0.11 + The `root_path` parameter was added. + + .. versionadded:: 1.0 + The ``host_matching`` and ``static_host`` parameters were added. + + .. versionadded:: 1.0 + The ``subdomain_matching`` parameter was added. Subdomain + matching needs to be enabled manually now. Setting + :data:`SERVER_NAME` does not implicitly enable it. + + :param import_name: the name of the application package + :param static_url_path: can be used to specify a different path for the + static files on the web. Defaults to the name + of the `static_folder` folder. + :param static_folder: The folder with static files that is served at + ``static_url_path``. Relative to the application ``root_path`` + or an absolute path. Defaults to ``'static'``. + :param static_host: the host to use when adding the static route. + Defaults to None. Required when using ``host_matching=True`` + with a ``static_folder`` configured. + :param host_matching: set ``url_map.host_matching`` attribute. + Defaults to False. + :param subdomain_matching: consider the subdomain relative to + :data:`SERVER_NAME` when matching routes. Defaults to False. + :param template_folder: the folder that contains the templates that should + be used by the application. Defaults to + ``'templates'`` folder in the root path of the + application. + :param instance_path: An alternative instance path for the application. + By default the folder ``'instance'`` next to the + package or module is assumed to be the instance + path. + :param instance_relative_config: if set to ``True`` relative filenames + for loading the config are assumed to + be relative to the instance path instead + of the application root. + :param root_path: The path to the root of the application files. + This should only be set manually when it can't be detected + automatically, such as for namespace packages. + """ + + #: The class of the object assigned to :attr:`aborter`, created by + #: :meth:`create_aborter`. That object is called by + #: :func:`flask.abort` to raise HTTP errors, and can be + #: called directly as well. + #: + #: Defaults to :class:`werkzeug.exceptions.Aborter`. + #: + #: .. versionadded:: 2.2 + aborter_class = Aborter + + #: The class that is used for the Jinja environment. + #: + #: .. versionadded:: 0.11 + jinja_environment = Environment + + #: The class that is used for the :data:`~flask.g` instance. + #: + #: Example use cases for a custom class: + #: + #: 1. Store arbitrary attributes on flask.g. + #: 2. Add a property for lazy per-request database connectors. + #: 3. Return None instead of AttributeError on unexpected attributes. + #: 4. Raise exception if an unexpected attr is set, a "controlled" flask.g. + #: + #: In Flask 0.9 this property was called `request_globals_class` but it + #: was changed in 0.10 to :attr:`app_ctx_globals_class` because the + #: flask.g object is now application context scoped. + #: + #: .. versionadded:: 0.10 + app_ctx_globals_class = _AppCtxGlobals + + #: The class that is used for the ``config`` attribute of this app. + #: Defaults to :class:`~flask.Config`. + #: + #: Example use cases for a custom class: + #: + #: 1. Default values for certain config options. + #: 2. Access to config values through attributes in addition to keys. + #: + #: .. versionadded:: 0.11 + config_class = Config + + #: The testing flag. Set this to ``True`` to enable the test mode of + #: Flask extensions (and in the future probably also Flask itself). + #: For example this might activate test helpers that have an + #: additional runtime cost which should not be enabled by default. + #: + #: If this is enabled and PROPAGATE_EXCEPTIONS is not changed from the + #: default it's implicitly enabled. + #: + #: This attribute can also be configured from the config with the + #: ``TESTING`` configuration key. Defaults to ``False``. + testing = ConfigAttribute[bool]("TESTING") + + #: If a secret key is set, cryptographic components can use this to + #: sign cookies and other things. Set this to a complex random value + #: when you want to use the secure cookie for instance. + #: + #: This attribute can also be configured from the config with the + #: :data:`SECRET_KEY` configuration key. Defaults to ``None``. + secret_key = ConfigAttribute[t.Union[str, bytes, None]]("SECRET_KEY") + + #: A :class:`~datetime.timedelta` which is used to set the expiration + #: date of a permanent session. The default is 31 days which makes a + #: permanent session survive for roughly one month. + #: + #: This attribute can also be configured from the config with the + #: ``PERMANENT_SESSION_LIFETIME`` configuration key. Defaults to + #: ``timedelta(days=31)`` + permanent_session_lifetime = ConfigAttribute[timedelta]( + "PERMANENT_SESSION_LIFETIME", + get_converter=_make_timedelta, # type: ignore[arg-type] + ) + + json_provider_class: type[JSONProvider] = DefaultJSONProvider + """A subclass of :class:`~flask.json.provider.JSONProvider`. An + instance is created and assigned to :attr:`app.json` when creating + the app. + + The default, :class:`~flask.json.provider.DefaultJSONProvider`, uses + Python's built-in :mod:`json` library. A different provider can use + a different JSON library. + + .. versionadded:: 2.2 + """ + + #: Options that are passed to the Jinja environment in + #: :meth:`create_jinja_environment`. Changing these options after + #: the environment is created (accessing :attr:`jinja_env`) will + #: have no effect. + #: + #: .. versionchanged:: 1.1.0 + #: This is a ``dict`` instead of an ``ImmutableDict`` to allow + #: easier configuration. + #: + jinja_options: dict[str, t.Any] = {} + + #: The rule object to use for URL rules created. This is used by + #: :meth:`add_url_rule`. Defaults to :class:`werkzeug.routing.Rule`. + #: + #: .. versionadded:: 0.7 + url_rule_class = Rule + + #: The map object to use for storing the URL rules and routing + #: configuration parameters. Defaults to :class:`werkzeug.routing.Map`. + #: + #: .. versionadded:: 1.1.0 + url_map_class = Map + + #: The :meth:`test_client` method creates an instance of this test + #: client class. Defaults to :class:`~flask.testing.FlaskClient`. + #: + #: .. versionadded:: 0.7 + test_client_class: type[FlaskClient] | None = None + + #: The :class:`~click.testing.CliRunner` subclass, by default + #: :class:`~flask.testing.FlaskCliRunner` that is used by + #: :meth:`test_cli_runner`. Its ``__init__`` method should take a + #: Flask app object as the first argument. + #: + #: .. versionadded:: 1.0 + test_cli_runner_class: type[FlaskCliRunner] | None = None + + default_config: dict[str, t.Any] + response_class: type[Response] + + def __init__( + self, + import_name: str, + static_url_path: str | None = None, + static_folder: str | os.PathLike[str] | None = "static", + static_host: str | None = None, + host_matching: bool = False, + subdomain_matching: bool = False, + template_folder: str | os.PathLike[str] | None = "templates", + instance_path: str | None = None, + instance_relative_config: bool = False, + root_path: str | None = None, + ) -> None: + super().__init__( + import_name=import_name, + static_folder=static_folder, + static_url_path=static_url_path, + template_folder=template_folder, + root_path=root_path, + ) + + if instance_path is None: + instance_path = self.auto_find_instance_path() + elif not os.path.isabs(instance_path): + raise ValueError( + "If an instance path is provided it must be absolute." + " A relative path was given instead." + ) + + #: Holds the path to the instance folder. + #: + #: .. versionadded:: 0.8 + self.instance_path = instance_path + + #: The configuration dictionary as :class:`Config`. This behaves + #: exactly like a regular dictionary but supports additional methods + #: to load a config from files. + self.config = self.make_config(instance_relative_config) + + #: An instance of :attr:`aborter_class` created by + #: :meth:`make_aborter`. This is called by :func:`flask.abort` + #: to raise HTTP errors, and can be called directly as well. + #: + #: .. versionadded:: 2.2 + #: Moved from ``flask.abort``, which calls this object. + self.aborter = self.make_aborter() + + self.json: JSONProvider = self.json_provider_class(self) + """Provides access to JSON methods. Functions in ``flask.json`` + will call methods on this provider when the application context + is active. Used for handling JSON requests and responses. + + An instance of :attr:`json_provider_class`. Can be customized by + changing that attribute on a subclass, or by assigning to this + attribute afterwards. + + The default, :class:`~flask.json.provider.DefaultJSONProvider`, + uses Python's built-in :mod:`json` library. A different provider + can use a different JSON library. + + .. versionadded:: 2.2 + """ + + #: A list of functions that are called by + #: :meth:`handle_url_build_error` when :meth:`.url_for` raises a + #: :exc:`~werkzeug.routing.BuildError`. Each function is called + #: with ``error``, ``endpoint`` and ``values``. If a function + #: returns ``None`` or raises a ``BuildError``, it is skipped. + #: Otherwise, its return value is returned by ``url_for``. + #: + #: .. versionadded:: 0.9 + self.url_build_error_handlers: list[ + t.Callable[[Exception, str, dict[str, t.Any]], str] + ] = [] + + #: A list of functions that are called when the application context + #: is destroyed. Since the application context is also torn down + #: if the request ends this is the place to store code that disconnects + #: from databases. + #: + #: .. versionadded:: 0.9 + self.teardown_appcontext_funcs: list[ft.TeardownCallable] = [] + + #: A list of shell context processor functions that should be run + #: when a shell context is created. + #: + #: .. versionadded:: 0.11 + self.shell_context_processors: list[ft.ShellContextProcessorCallable] = [] + + #: Maps registered blueprint names to blueprint objects. The + #: dict retains the order the blueprints were registered in. + #: Blueprints can be registered multiple times, this dict does + #: not track how often they were attached. + #: + #: .. versionadded:: 0.7 + self.blueprints: dict[str, Blueprint] = {} + + #: a place where extensions can store application specific state. For + #: example this is where an extension could store database engines and + #: similar things. + #: + #: The key must match the name of the extension module. For example in + #: case of a "Flask-Foo" extension in `flask_foo`, the key would be + #: ``'foo'``. + #: + #: .. versionadded:: 0.7 + self.extensions: dict[str, t.Any] = {} + + #: The :class:`~werkzeug.routing.Map` for this instance. You can use + #: this to change the routing converters after the class was created + #: but before any routes are connected. Example:: + #: + #: from werkzeug.routing import BaseConverter + #: + #: class ListConverter(BaseConverter): + #: def to_python(self, value): + #: return value.split(',') + #: def to_url(self, values): + #: return ','.join(super(ListConverter, self).to_url(value) + #: for value in values) + #: + #: app = Flask(__name__) + #: app.url_map.converters['list'] = ListConverter + self.url_map = self.url_map_class(host_matching=host_matching) + + self.subdomain_matching = subdomain_matching + + # tracks internally if the application already handled at least one + # request. + self._got_first_request = False + + def _check_setup_finished(self, f_name: str) -> None: + if self._got_first_request: + raise AssertionError( + f"The setup method '{f_name}' can no longer be called" + " on the application. It has already handled its first" + " request, any changes will not be applied" + " consistently.\n" + "Make sure all imports, decorators, functions, etc." + " needed to set up the application are done before" + " running it." + ) + + @cached_property + def name(self) -> str: # type: ignore + """The name of the application. This is usually the import name + with the difference that it's guessed from the run file if the + import name is main. This name is used as a display name when + Flask needs the name of the application. It can be set and overridden + to change the value. + + .. versionadded:: 0.8 + """ + if self.import_name == "__main__": + fn: str | None = getattr(sys.modules["__main__"], "__file__", None) + if fn is None: + return "__main__" + return os.path.splitext(os.path.basename(fn))[0] + return self.import_name + + @cached_property + def logger(self) -> logging.Logger: + """A standard Python :class:`~logging.Logger` for the app, with + the same name as :attr:`name`. + + In debug mode, the logger's :attr:`~logging.Logger.level` will + be set to :data:`~logging.DEBUG`. + + If there are no handlers configured, a default handler will be + added. See :doc:`/logging` for more information. + + .. versionchanged:: 1.1.0 + The logger takes the same name as :attr:`name` rather than + hard-coding ``"flask.app"``. + + .. versionchanged:: 1.0.0 + Behavior was simplified. The logger is always named + ``"flask.app"``. The level is only set during configuration, + it doesn't check ``app.debug`` each time. Only one format is + used, not different ones depending on ``app.debug``. No + handlers are removed, and a handler is only added if no + handlers are already configured. + + .. versionadded:: 0.3 + """ + return create_logger(self) + + @cached_property + def jinja_env(self) -> Environment: + """The Jinja environment used to load templates. + + The environment is created the first time this property is + accessed. Changing :attr:`jinja_options` after that will have no + effect. + """ + return self.create_jinja_environment() + + def create_jinja_environment(self) -> Environment: + raise NotImplementedError() + + def make_config(self, instance_relative: bool = False) -> Config: + """Used to create the config attribute by the Flask constructor. + The `instance_relative` parameter is passed in from the constructor + of Flask (there named `instance_relative_config`) and indicates if + the config should be relative to the instance path or the root path + of the application. + + .. versionadded:: 0.8 + """ + root_path = self.root_path + if instance_relative: + root_path = self.instance_path + defaults = dict(self.default_config) + defaults["DEBUG"] = get_debug_flag() + return self.config_class(root_path, defaults) + + def make_aborter(self) -> Aborter: + """Create the object to assign to :attr:`aborter`. That object + is called by :func:`flask.abort` to raise HTTP errors, and can + be called directly as well. + + By default, this creates an instance of :attr:`aborter_class`, + which defaults to :class:`werkzeug.exceptions.Aborter`. + + .. versionadded:: 2.2 + """ + return self.aborter_class() + + def auto_find_instance_path(self) -> str: + """Tries to locate the instance path if it was not provided to the + constructor of the application class. It will basically calculate + the path to a folder named ``instance`` next to your main file or + the package. + + .. versionadded:: 0.8 + """ + prefix, package_path = find_package(self.import_name) + if prefix is None: + return os.path.join(package_path, "instance") + return os.path.join(prefix, "var", f"{self.name}-instance") + + def create_global_jinja_loader(self) -> DispatchingJinjaLoader: + """Creates the loader for the Jinja2 environment. Can be used to + override just the loader and keeping the rest unchanged. It's + discouraged to override this function. Instead one should override + the :meth:`jinja_loader` function instead. + + The global loader dispatches between the loaders of the application + and the individual blueprints. + + .. versionadded:: 0.7 + """ + return DispatchingJinjaLoader(self) + + def select_jinja_autoescape(self, filename: str) -> bool: + """Returns ``True`` if autoescaping should be active for the given + template name. If no template name is given, returns `True`. + + .. versionchanged:: 2.2 + Autoescaping is now enabled by default for ``.svg`` files. + + .. versionadded:: 0.5 + """ + if filename is None: + return True + return filename.endswith((".html", ".htm", ".xml", ".xhtml", ".svg")) + + @property + def debug(self) -> bool: + """Whether debug mode is enabled. When using ``flask run`` to start the + development server, an interactive debugger will be shown for unhandled + exceptions, and the server will be reloaded when code changes. This maps to the + :data:`DEBUG` config key. It may not behave as expected if set late. + + **Do not enable debug mode when deploying in production.** + + Default: ``False`` + """ + return self.config["DEBUG"] # type: ignore[no-any-return] + + @debug.setter + def debug(self, value: bool) -> None: + self.config["DEBUG"] = value + + if self.config["TEMPLATES_AUTO_RELOAD"] is None: + self.jinja_env.auto_reload = value + + @setupmethod + def register_blueprint(self, blueprint: Blueprint, **options: t.Any) -> None: + """Register a :class:`~flask.Blueprint` on the application. Keyword + arguments passed to this method will override the defaults set on the + blueprint. + + Calls the blueprint's :meth:`~flask.Blueprint.register` method after + recording the blueprint in the application's :attr:`blueprints`. + + :param blueprint: The blueprint to register. + :param url_prefix: Blueprint routes will be prefixed with this. + :param subdomain: Blueprint routes will match on this subdomain. + :param url_defaults: Blueprint routes will use these default values for + view arguments. + :param options: Additional keyword arguments are passed to + :class:`~flask.blueprints.BlueprintSetupState`. They can be + accessed in :meth:`~flask.Blueprint.record` callbacks. + + .. versionchanged:: 2.0.1 + The ``name`` option can be used to change the (pre-dotted) + name the blueprint is registered with. This allows the same + blueprint to be registered multiple times with unique names + for ``url_for``. + + .. versionadded:: 0.7 + """ + blueprint.register(self, options) + + def iter_blueprints(self) -> t.ValuesView[Blueprint]: + """Iterates over all blueprints by the order they were registered. + + .. versionadded:: 0.11 + """ + return self.blueprints.values() + + @setupmethod + def add_url_rule( + self, + rule: str, + endpoint: str | None = None, + view_func: ft.RouteCallable | None = None, + provide_automatic_options: bool | None = None, + **options: t.Any, + ) -> None: + if endpoint is None: + endpoint = _endpoint_from_view_func(view_func) # type: ignore + options["endpoint"] = endpoint + methods = options.pop("methods", None) + + # if the methods are not given and the view_func object knows its + # methods we can use that instead. If neither exists, we go with + # a tuple of only ``GET`` as default. + if methods is None: + methods = getattr(view_func, "methods", None) or ("GET",) + if isinstance(methods, str): + raise TypeError( + "Allowed methods must be a list of strings, for" + ' example: @app.route(..., methods=["POST"])' + ) + methods = {item.upper() for item in methods} + + # Methods that should always be added + required_methods: set[str] = set(getattr(view_func, "required_methods", ())) + + # starting with Flask 0.8 the view_func object can disable and + # force-enable the automatic options handling. + if provide_automatic_options is None: + provide_automatic_options = getattr( + view_func, "provide_automatic_options", None + ) + + if provide_automatic_options is None: + if "OPTIONS" not in methods and self.config["PROVIDE_AUTOMATIC_OPTIONS"]: + provide_automatic_options = True + required_methods.add("OPTIONS") + else: + provide_automatic_options = False + + # Add the required methods now. + methods |= required_methods + + rule_obj = self.url_rule_class(rule, methods=methods, **options) + rule_obj.provide_automatic_options = provide_automatic_options # type: ignore[attr-defined] + + self.url_map.add(rule_obj) + if view_func is not None: + old_func = self.view_functions.get(endpoint) + if old_func is not None and old_func != view_func: + raise AssertionError( + "View function mapping is overwriting an existing" + f" endpoint function: {endpoint}" + ) + self.view_functions[endpoint] = view_func + + @setupmethod + def template_filter( + self, name: str | None = None + ) -> t.Callable[[T_template_filter], T_template_filter]: + """A decorator that is used to register custom template filter. + You can specify a name for the filter, otherwise the function + name will be used. Example:: + + @app.template_filter() + def reverse(s): + return s[::-1] + + :param name: the optional name of the filter, otherwise the + function name will be used. + """ + + def decorator(f: T_template_filter) -> T_template_filter: + self.add_template_filter(f, name=name) + return f + + return decorator + + @setupmethod + def add_template_filter( + self, f: ft.TemplateFilterCallable, name: str | None = None + ) -> None: + """Register a custom template filter. Works exactly like the + :meth:`template_filter` decorator. + + :param name: the optional name of the filter, otherwise the + function name will be used. + """ + self.jinja_env.filters[name or f.__name__] = f + + @setupmethod + def template_test( + self, name: str | None = None + ) -> t.Callable[[T_template_test], T_template_test]: + """A decorator that is used to register custom template test. + You can specify a name for the test, otherwise the function + name will be used. Example:: + + @app.template_test() + def is_prime(n): + if n == 2: + return True + for i in range(2, int(math.ceil(math.sqrt(n))) + 1): + if n % i == 0: + return False + return True + + .. versionadded:: 0.10 + + :param name: the optional name of the test, otherwise the + function name will be used. + """ + + def decorator(f: T_template_test) -> T_template_test: + self.add_template_test(f, name=name) + return f + + return decorator + + @setupmethod + def add_template_test( + self, f: ft.TemplateTestCallable, name: str | None = None + ) -> None: + """Register a custom template test. Works exactly like the + :meth:`template_test` decorator. + + .. versionadded:: 0.10 + + :param name: the optional name of the test, otherwise the + function name will be used. + """ + self.jinja_env.tests[name or f.__name__] = f + + @setupmethod + def template_global( + self, name: str | None = None + ) -> t.Callable[[T_template_global], T_template_global]: + """A decorator that is used to register a custom template global function. + You can specify a name for the global function, otherwise the function + name will be used. Example:: + + @app.template_global() + def double(n): + return 2 * n + + .. versionadded:: 0.10 + + :param name: the optional name of the global function, otherwise the + function name will be used. + """ + + def decorator(f: T_template_global) -> T_template_global: + self.add_template_global(f, name=name) + return f + + return decorator + + @setupmethod + def add_template_global( + self, f: ft.TemplateGlobalCallable, name: str | None = None + ) -> None: + """Register a custom template global function. Works exactly like the + :meth:`template_global` decorator. + + .. versionadded:: 0.10 + + :param name: the optional name of the global function, otherwise the + function name will be used. + """ + self.jinja_env.globals[name or f.__name__] = f + + @setupmethod + def teardown_appcontext(self, f: T_teardown) -> T_teardown: + """Registers a function to be called when the application + context is popped. The application context is typically popped + after the request context for each request, at the end of CLI + commands, or after a manually pushed context ends. + + .. code-block:: python + + with app.app_context(): + ... + + When the ``with`` block exits (or ``ctx.pop()`` is called), the + teardown functions are called just before the app context is + made inactive. Since a request context typically also manages an + application context it would also be called when you pop a + request context. + + When a teardown function was called because of an unhandled + exception it will be passed an error object. If an + :meth:`errorhandler` is registered, it will handle the exception + and the teardown will not receive it. + + Teardown functions must avoid raising exceptions. If they + execute code that might fail they must surround that code with a + ``try``/``except`` block and log any errors. + + The return values of teardown functions are ignored. + + .. versionadded:: 0.9 + """ + self.teardown_appcontext_funcs.append(f) + return f + + @setupmethod + def shell_context_processor( + self, f: T_shell_context_processor + ) -> T_shell_context_processor: + """Registers a shell context processor function. + + .. versionadded:: 0.11 + """ + self.shell_context_processors.append(f) + return f + + def _find_error_handler( + self, e: Exception, blueprints: list[str] + ) -> ft.ErrorHandlerCallable | None: + """Return a registered error handler for an exception in this order: + blueprint handler for a specific code, app handler for a specific code, + blueprint handler for an exception class, app handler for an exception + class, or ``None`` if a suitable handler is not found. + """ + exc_class, code = self._get_exc_class_and_code(type(e)) + names = (*blueprints, None) + + for c in (code, None) if code is not None else (None,): + for name in names: + handler_map = self.error_handler_spec[name][c] + + if not handler_map: + continue + + for cls in exc_class.__mro__: + handler = handler_map.get(cls) + + if handler is not None: + return handler + return None + + def trap_http_exception(self, e: Exception) -> bool: + """Checks if an HTTP exception should be trapped or not. By default + this will return ``False`` for all exceptions except for a bad request + key error if ``TRAP_BAD_REQUEST_ERRORS`` is set to ``True``. It + also returns ``True`` if ``TRAP_HTTP_EXCEPTIONS`` is set to ``True``. + + This is called for all HTTP exceptions raised by a view function. + If it returns ``True`` for any exception the error handler for this + exception is not called and it shows up as regular exception in the + traceback. This is helpful for debugging implicitly raised HTTP + exceptions. + + .. versionchanged:: 1.0 + Bad request errors are not trapped by default in debug mode. + + .. versionadded:: 0.8 + """ + if self.config["TRAP_HTTP_EXCEPTIONS"]: + return True + + trap_bad_request = self.config["TRAP_BAD_REQUEST_ERRORS"] + + # if unset, trap key errors in debug mode + if ( + trap_bad_request is None + and self.debug + and isinstance(e, BadRequestKeyError) + ): + return True + + if trap_bad_request: + return isinstance(e, BadRequest) + + return False + + def should_ignore_error(self, error: BaseException | None) -> bool: + """This is called to figure out if an error should be ignored + or not as far as the teardown system is concerned. If this + function returns ``True`` then the teardown handlers will not be + passed the error. + + .. versionadded:: 0.10 + """ + return False + + def redirect(self, location: str, code: int = 302) -> BaseResponse: + """Create a redirect response object. + + This is called by :func:`flask.redirect`, and can be called + directly as well. + + :param location: The URL to redirect to. + :param code: The status code for the redirect. + + .. versionadded:: 2.2 + Moved from ``flask.redirect``, which calls this method. + """ + return _wz_redirect( + location, + code=code, + Response=self.response_class, # type: ignore[arg-type] + ) + + def inject_url_defaults(self, endpoint: str, values: dict[str, t.Any]) -> None: + """Injects the URL defaults for the given endpoint directly into + the values dictionary passed. This is used internally and + automatically called on URL building. + + .. versionadded:: 0.7 + """ + names: t.Iterable[str | None] = (None,) + + # url_for may be called outside a request context, parse the + # passed endpoint instead of using request.blueprints. + if "." in endpoint: + names = chain( + names, reversed(_split_blueprint_path(endpoint.rpartition(".")[0])) + ) + + for name in names: + if name in self.url_default_functions: + for func in self.url_default_functions[name]: + func(endpoint, values) + + def handle_url_build_error( + self, error: BuildError, endpoint: str, values: dict[str, t.Any] + ) -> str: + """Called by :meth:`.url_for` if a + :exc:`~werkzeug.routing.BuildError` was raised. If this returns + a value, it will be returned by ``url_for``, otherwise the error + will be re-raised. + + Each function in :attr:`url_build_error_handlers` is called with + ``error``, ``endpoint`` and ``values``. If a function returns + ``None`` or raises a ``BuildError``, it is skipped. Otherwise, + its return value is returned by ``url_for``. + + :param error: The active ``BuildError`` being handled. + :param endpoint: The endpoint being built. + :param values: The keyword arguments passed to ``url_for``. + """ + for handler in self.url_build_error_handlers: + try: + rv = handler(error, endpoint, values) + except BuildError as e: + # make error available outside except block + error = e + else: + if rv is not None: + return rv + + # Re-raise if called with an active exception, otherwise raise + # the passed in exception. + if error is sys.exc_info()[1]: + raise + + raise error diff --git a/psets/9/finance/env/lib/python3.12/site-packages/flask/sansio/blueprints.py b/psets/9/finance/env/lib/python3.12/site-packages/flask/sansio/blueprints.py new file mode 100644 index 0000000..4f912cc --- /dev/null +++ b/psets/9/finance/env/lib/python3.12/site-packages/flask/sansio/blueprints.py @@ -0,0 +1,632 @@ +from __future__ import annotations + +import os +import typing as t +from collections import defaultdict +from functools import update_wrapper + +from .. import typing as ft +from .scaffold import _endpoint_from_view_func +from .scaffold import _sentinel +from .scaffold import Scaffold +from .scaffold import setupmethod + +if t.TYPE_CHECKING: # pragma: no cover + from .app import App + +DeferredSetupFunction = t.Callable[["BlueprintSetupState"], None] +T_after_request = t.TypeVar("T_after_request", bound=ft.AfterRequestCallable[t.Any]) +T_before_request = t.TypeVar("T_before_request", bound=ft.BeforeRequestCallable) +T_error_handler = t.TypeVar("T_error_handler", bound=ft.ErrorHandlerCallable) +T_teardown = t.TypeVar("T_teardown", bound=ft.TeardownCallable) +T_template_context_processor = t.TypeVar( + "T_template_context_processor", bound=ft.TemplateContextProcessorCallable +) +T_template_filter = t.TypeVar("T_template_filter", bound=ft.TemplateFilterCallable) +T_template_global = t.TypeVar("T_template_global", bound=ft.TemplateGlobalCallable) +T_template_test = t.TypeVar("T_template_test", bound=ft.TemplateTestCallable) +T_url_defaults = t.TypeVar("T_url_defaults", bound=ft.URLDefaultCallable) +T_url_value_preprocessor = t.TypeVar( + "T_url_value_preprocessor", bound=ft.URLValuePreprocessorCallable +) + + +class BlueprintSetupState: + """Temporary holder object for registering a blueprint with the + application. An instance of this class is created by the + :meth:`~flask.Blueprint.make_setup_state` method and later passed + to all register callback functions. + """ + + def __init__( + self, + blueprint: Blueprint, + app: App, + options: t.Any, + first_registration: bool, + ) -> None: + #: a reference to the current application + self.app = app + + #: a reference to the blueprint that created this setup state. + self.blueprint = blueprint + + #: a dictionary with all options that were passed to the + #: :meth:`~flask.Flask.register_blueprint` method. + self.options = options + + #: as blueprints can be registered multiple times with the + #: application and not everything wants to be registered + #: multiple times on it, this attribute can be used to figure + #: out if the blueprint was registered in the past already. + self.first_registration = first_registration + + subdomain = self.options.get("subdomain") + if subdomain is None: + subdomain = self.blueprint.subdomain + + #: The subdomain that the blueprint should be active for, ``None`` + #: otherwise. + self.subdomain = subdomain + + url_prefix = self.options.get("url_prefix") + if url_prefix is None: + url_prefix = self.blueprint.url_prefix + #: The prefix that should be used for all URLs defined on the + #: blueprint. + self.url_prefix = url_prefix + + self.name = self.options.get("name", blueprint.name) + self.name_prefix = self.options.get("name_prefix", "") + + #: A dictionary with URL defaults that is added to each and every + #: URL that was defined with the blueprint. + self.url_defaults = dict(self.blueprint.url_values_defaults) + self.url_defaults.update(self.options.get("url_defaults", ())) + + def add_url_rule( + self, + rule: str, + endpoint: str | None = None, + view_func: ft.RouteCallable | None = None, + **options: t.Any, + ) -> None: + """A helper method to register a rule (and optionally a view function) + to the application. The endpoint is automatically prefixed with the + blueprint's name. + """ + if self.url_prefix is not None: + if rule: + rule = "/".join((self.url_prefix.rstrip("/"), rule.lstrip("/"))) + else: + rule = self.url_prefix + options.setdefault("subdomain", self.subdomain) + if endpoint is None: + endpoint = _endpoint_from_view_func(view_func) # type: ignore + defaults = self.url_defaults + if "defaults" in options: + defaults = dict(defaults, **options.pop("defaults")) + + self.app.add_url_rule( + rule, + f"{self.name_prefix}.{self.name}.{endpoint}".lstrip("."), + view_func, + defaults=defaults, + **options, + ) + + +class Blueprint(Scaffold): + """Represents a blueprint, a collection of routes and other + app-related functions that can be registered on a real application + later. + + A blueprint is an object that allows defining application functions + without requiring an application object ahead of time. It uses the + same decorators as :class:`~flask.Flask`, but defers the need for an + application by recording them for later registration. + + Decorating a function with a blueprint creates a deferred function + that is called with :class:`~flask.blueprints.BlueprintSetupState` + when the blueprint is registered on an application. + + See :doc:`/blueprints` for more information. + + :param name: The name of the blueprint. Will be prepended to each + endpoint name. + :param import_name: The name of the blueprint package, usually + ``__name__``. This helps locate the ``root_path`` for the + blueprint. + :param static_folder: A folder with static files that should be + served by the blueprint's static route. The path is relative to + the blueprint's root path. Blueprint static files are disabled + by default. + :param static_url_path: The url to serve static files from. + Defaults to ``static_folder``. If the blueprint does not have + a ``url_prefix``, the app's static route will take precedence, + and the blueprint's static files won't be accessible. + :param template_folder: A folder with templates that should be added + to the app's template search path. The path is relative to the + blueprint's root path. Blueprint templates are disabled by + default. Blueprint templates have a lower precedence than those + in the app's templates folder. + :param url_prefix: A path to prepend to all of the blueprint's URLs, + to make them distinct from the rest of the app's routes. + :param subdomain: A subdomain that blueprint routes will match on by + default. + :param url_defaults: A dict of default values that blueprint routes + will receive by default. + :param root_path: By default, the blueprint will automatically set + this based on ``import_name``. In certain situations this + automatic detection can fail, so the path can be specified + manually instead. + + .. versionchanged:: 1.1.0 + Blueprints have a ``cli`` group to register nested CLI commands. + The ``cli_group`` parameter controls the name of the group under + the ``flask`` command. + + .. versionadded:: 0.7 + """ + + _got_registered_once = False + + def __init__( + self, + name: str, + import_name: str, + static_folder: str | os.PathLike[str] | None = None, + static_url_path: str | None = None, + template_folder: str | os.PathLike[str] | None = None, + url_prefix: str | None = None, + subdomain: str | None = None, + url_defaults: dict[str, t.Any] | None = None, + root_path: str | None = None, + cli_group: str | None = _sentinel, # type: ignore[assignment] + ): + super().__init__( + import_name=import_name, + static_folder=static_folder, + static_url_path=static_url_path, + template_folder=template_folder, + root_path=root_path, + ) + + if not name: + raise ValueError("'name' may not be empty.") + + if "." in name: + raise ValueError("'name' may not contain a dot '.' character.") + + self.name = name + self.url_prefix = url_prefix + self.subdomain = subdomain + self.deferred_functions: list[DeferredSetupFunction] = [] + + if url_defaults is None: + url_defaults = {} + + self.url_values_defaults = url_defaults + self.cli_group = cli_group + self._blueprints: list[tuple[Blueprint, dict[str, t.Any]]] = [] + + def _check_setup_finished(self, f_name: str) -> None: + if self._got_registered_once: + raise AssertionError( + f"The setup method '{f_name}' can no longer be called on the blueprint" + f" '{self.name}'. It has already been registered at least once, any" + " changes will not be applied consistently.\n" + "Make sure all imports, decorators, functions, etc. needed to set up" + " the blueprint are done before registering it." + ) + + @setupmethod + def record(self, func: DeferredSetupFunction) -> None: + """Registers a function that is called when the blueprint is + registered on the application. This function is called with the + state as argument as returned by the :meth:`make_setup_state` + method. + """ + self.deferred_functions.append(func) + + @setupmethod + def record_once(self, func: DeferredSetupFunction) -> None: + """Works like :meth:`record` but wraps the function in another + function that will ensure the function is only called once. If the + blueprint is registered a second time on the application, the + function passed is not called. + """ + + def wrapper(state: BlueprintSetupState) -> None: + if state.first_registration: + func(state) + + self.record(update_wrapper(wrapper, func)) + + def make_setup_state( + self, app: App, options: dict[str, t.Any], first_registration: bool = False + ) -> BlueprintSetupState: + """Creates an instance of :meth:`~flask.blueprints.BlueprintSetupState` + object that is later passed to the register callback functions. + Subclasses can override this to return a subclass of the setup state. + """ + return BlueprintSetupState(self, app, options, first_registration) + + @setupmethod + def register_blueprint(self, blueprint: Blueprint, **options: t.Any) -> None: + """Register a :class:`~flask.Blueprint` on this blueprint. Keyword + arguments passed to this method will override the defaults set + on the blueprint. + + .. versionchanged:: 2.0.1 + The ``name`` option can be used to change the (pre-dotted) + name the blueprint is registered with. This allows the same + blueprint to be registered multiple times with unique names + for ``url_for``. + + .. versionadded:: 2.0 + """ + if blueprint is self: + raise ValueError("Cannot register a blueprint on itself") + self._blueprints.append((blueprint, options)) + + def register(self, app: App, options: dict[str, t.Any]) -> None: + """Called by :meth:`Flask.register_blueprint` to register all + views and callbacks registered on the blueprint with the + application. Creates a :class:`.BlueprintSetupState` and calls + each :meth:`record` callback with it. + + :param app: The application this blueprint is being registered + with. + :param options: Keyword arguments forwarded from + :meth:`~Flask.register_blueprint`. + + .. versionchanged:: 2.3 + Nested blueprints now correctly apply subdomains. + + .. versionchanged:: 2.1 + Registering the same blueprint with the same name multiple + times is an error. + + .. versionchanged:: 2.0.1 + Nested blueprints are registered with their dotted name. + This allows different blueprints with the same name to be + nested at different locations. + + .. versionchanged:: 2.0.1 + The ``name`` option can be used to change the (pre-dotted) + name the blueprint is registered with. This allows the same + blueprint to be registered multiple times with unique names + for ``url_for``. + """ + name_prefix = options.get("name_prefix", "") + self_name = options.get("name", self.name) + name = f"{name_prefix}.{self_name}".lstrip(".") + + if name in app.blueprints: + bp_desc = "this" if app.blueprints[name] is self else "a different" + existing_at = f" '{name}'" if self_name != name else "" + + raise ValueError( + f"The name '{self_name}' is already registered for" + f" {bp_desc} blueprint{existing_at}. Use 'name=' to" + f" provide a unique name." + ) + + first_bp_registration = not any(bp is self for bp in app.blueprints.values()) + first_name_registration = name not in app.blueprints + + app.blueprints[name] = self + self._got_registered_once = True + state = self.make_setup_state(app, options, first_bp_registration) + + if self.has_static_folder: + state.add_url_rule( + f"{self.static_url_path}/", + view_func=self.send_static_file, # type: ignore[attr-defined] + endpoint="static", + ) + + # Merge blueprint data into parent. + if first_bp_registration or first_name_registration: + self._merge_blueprint_funcs(app, name) + + for deferred in self.deferred_functions: + deferred(state) + + cli_resolved_group = options.get("cli_group", self.cli_group) + + if self.cli.commands: + if cli_resolved_group is None: + app.cli.commands.update(self.cli.commands) + elif cli_resolved_group is _sentinel: + self.cli.name = name + app.cli.add_command(self.cli) + else: + self.cli.name = cli_resolved_group + app.cli.add_command(self.cli) + + for blueprint, bp_options in self._blueprints: + bp_options = bp_options.copy() + bp_url_prefix = bp_options.get("url_prefix") + bp_subdomain = bp_options.get("subdomain") + + if bp_subdomain is None: + bp_subdomain = blueprint.subdomain + + if state.subdomain is not None and bp_subdomain is not None: + bp_options["subdomain"] = bp_subdomain + "." + state.subdomain + elif bp_subdomain is not None: + bp_options["subdomain"] = bp_subdomain + elif state.subdomain is not None: + bp_options["subdomain"] = state.subdomain + + if bp_url_prefix is None: + bp_url_prefix = blueprint.url_prefix + + if state.url_prefix is not None and bp_url_prefix is not None: + bp_options["url_prefix"] = ( + state.url_prefix.rstrip("/") + "/" + bp_url_prefix.lstrip("/") + ) + elif bp_url_prefix is not None: + bp_options["url_prefix"] = bp_url_prefix + elif state.url_prefix is not None: + bp_options["url_prefix"] = state.url_prefix + + bp_options["name_prefix"] = name + blueprint.register(app, bp_options) + + def _merge_blueprint_funcs(self, app: App, name: str) -> None: + def extend( + bp_dict: dict[ft.AppOrBlueprintKey, list[t.Any]], + parent_dict: dict[ft.AppOrBlueprintKey, list[t.Any]], + ) -> None: + for key, values in bp_dict.items(): + key = name if key is None else f"{name}.{key}" + parent_dict[key].extend(values) + + for key, value in self.error_handler_spec.items(): + key = name if key is None else f"{name}.{key}" + value = defaultdict( + dict, + { + code: {exc_class: func for exc_class, func in code_values.items()} + for code, code_values in value.items() + }, + ) + app.error_handler_spec[key] = value + + for endpoint, func in self.view_functions.items(): + app.view_functions[endpoint] = func + + extend(self.before_request_funcs, app.before_request_funcs) + extend(self.after_request_funcs, app.after_request_funcs) + extend( + self.teardown_request_funcs, + app.teardown_request_funcs, + ) + extend(self.url_default_functions, app.url_default_functions) + extend(self.url_value_preprocessors, app.url_value_preprocessors) + extend(self.template_context_processors, app.template_context_processors) + + @setupmethod + def add_url_rule( + self, + rule: str, + endpoint: str | None = None, + view_func: ft.RouteCallable | None = None, + provide_automatic_options: bool | None = None, + **options: t.Any, + ) -> None: + """Register a URL rule with the blueprint. See :meth:`.Flask.add_url_rule` for + full documentation. + + The URL rule is prefixed with the blueprint's URL prefix. The endpoint name, + used with :func:`url_for`, is prefixed with the blueprint's name. + """ + if endpoint and "." in endpoint: + raise ValueError("'endpoint' may not contain a dot '.' character.") + + if view_func and hasattr(view_func, "__name__") and "." in view_func.__name__: + raise ValueError("'view_func' name may not contain a dot '.' character.") + + self.record( + lambda s: s.add_url_rule( + rule, + endpoint, + view_func, + provide_automatic_options=provide_automatic_options, + **options, + ) + ) + + @setupmethod + def app_template_filter( + self, name: str | None = None + ) -> t.Callable[[T_template_filter], T_template_filter]: + """Register a template filter, available in any template rendered by the + application. Equivalent to :meth:`.Flask.template_filter`. + + :param name: the optional name of the filter, otherwise the + function name will be used. + """ + + def decorator(f: T_template_filter) -> T_template_filter: + self.add_app_template_filter(f, name=name) + return f + + return decorator + + @setupmethod + def add_app_template_filter( + self, f: ft.TemplateFilterCallable, name: str | None = None + ) -> None: + """Register a template filter, available in any template rendered by the + application. Works like the :meth:`app_template_filter` decorator. Equivalent to + :meth:`.Flask.add_template_filter`. + + :param name: the optional name of the filter, otherwise the + function name will be used. + """ + + def register_template(state: BlueprintSetupState) -> None: + state.app.jinja_env.filters[name or f.__name__] = f + + self.record_once(register_template) + + @setupmethod + def app_template_test( + self, name: str | None = None + ) -> t.Callable[[T_template_test], T_template_test]: + """Register a template test, available in any template rendered by the + application. Equivalent to :meth:`.Flask.template_test`. + + .. versionadded:: 0.10 + + :param name: the optional name of the test, otherwise the + function name will be used. + """ + + def decorator(f: T_template_test) -> T_template_test: + self.add_app_template_test(f, name=name) + return f + + return decorator + + @setupmethod + def add_app_template_test( + self, f: ft.TemplateTestCallable, name: str | None = None + ) -> None: + """Register a template test, available in any template rendered by the + application. Works like the :meth:`app_template_test` decorator. Equivalent to + :meth:`.Flask.add_template_test`. + + .. versionadded:: 0.10 + + :param name: the optional name of the test, otherwise the + function name will be used. + """ + + def register_template(state: BlueprintSetupState) -> None: + state.app.jinja_env.tests[name or f.__name__] = f + + self.record_once(register_template) + + @setupmethod + def app_template_global( + self, name: str | None = None + ) -> t.Callable[[T_template_global], T_template_global]: + """Register a template global, available in any template rendered by the + application. Equivalent to :meth:`.Flask.template_global`. + + .. versionadded:: 0.10 + + :param name: the optional name of the global, otherwise the + function name will be used. + """ + + def decorator(f: T_template_global) -> T_template_global: + self.add_app_template_global(f, name=name) + return f + + return decorator + + @setupmethod + def add_app_template_global( + self, f: ft.TemplateGlobalCallable, name: str | None = None + ) -> None: + """Register a template global, available in any template rendered by the + application. Works like the :meth:`app_template_global` decorator. Equivalent to + :meth:`.Flask.add_template_global`. + + .. versionadded:: 0.10 + + :param name: the optional name of the global, otherwise the + function name will be used. + """ + + def register_template(state: BlueprintSetupState) -> None: + state.app.jinja_env.globals[name or f.__name__] = f + + self.record_once(register_template) + + @setupmethod + def before_app_request(self, f: T_before_request) -> T_before_request: + """Like :meth:`before_request`, but before every request, not only those handled + by the blueprint. Equivalent to :meth:`.Flask.before_request`. + """ + self.record_once( + lambda s: s.app.before_request_funcs.setdefault(None, []).append(f) + ) + return f + + @setupmethod + def after_app_request(self, f: T_after_request) -> T_after_request: + """Like :meth:`after_request`, but after every request, not only those handled + by the blueprint. Equivalent to :meth:`.Flask.after_request`. + """ + self.record_once( + lambda s: s.app.after_request_funcs.setdefault(None, []).append(f) + ) + return f + + @setupmethod + def teardown_app_request(self, f: T_teardown) -> T_teardown: + """Like :meth:`teardown_request`, but after every request, not only those + handled by the blueprint. Equivalent to :meth:`.Flask.teardown_request`. + """ + self.record_once( + lambda s: s.app.teardown_request_funcs.setdefault(None, []).append(f) + ) + return f + + @setupmethod + def app_context_processor( + self, f: T_template_context_processor + ) -> T_template_context_processor: + """Like :meth:`context_processor`, but for templates rendered by every view, not + only by the blueprint. Equivalent to :meth:`.Flask.context_processor`. + """ + self.record_once( + lambda s: s.app.template_context_processors.setdefault(None, []).append(f) + ) + return f + + @setupmethod + def app_errorhandler( + self, code: type[Exception] | int + ) -> t.Callable[[T_error_handler], T_error_handler]: + """Like :meth:`errorhandler`, but for every request, not only those handled by + the blueprint. Equivalent to :meth:`.Flask.errorhandler`. + """ + + def decorator(f: T_error_handler) -> T_error_handler: + def from_blueprint(state: BlueprintSetupState) -> None: + state.app.errorhandler(code)(f) + + self.record_once(from_blueprint) + return f + + return decorator + + @setupmethod + def app_url_value_preprocessor( + self, f: T_url_value_preprocessor + ) -> T_url_value_preprocessor: + """Like :meth:`url_value_preprocessor`, but for every request, not only those + handled by the blueprint. Equivalent to :meth:`.Flask.url_value_preprocessor`. + """ + self.record_once( + lambda s: s.app.url_value_preprocessors.setdefault(None, []).append(f) + ) + return f + + @setupmethod + def app_url_defaults(self, f: T_url_defaults) -> T_url_defaults: + """Like :meth:`url_defaults`, but for every request, not only those handled by + the blueprint. Equivalent to :meth:`.Flask.url_defaults`. + """ + self.record_once( + lambda s: s.app.url_default_functions.setdefault(None, []).append(f) + ) + return f diff --git a/psets/9/finance/env/lib/python3.12/site-packages/flask/sansio/scaffold.py b/psets/9/finance/env/lib/python3.12/site-packages/flask/sansio/scaffold.py new file mode 100644 index 0000000..3a839f5 --- /dev/null +++ b/psets/9/finance/env/lib/python3.12/site-packages/flask/sansio/scaffold.py @@ -0,0 +1,792 @@ +from __future__ import annotations + +import importlib.util +import os +import pathlib +import sys +import typing as t +from collections import defaultdict +from functools import update_wrapper + +from jinja2 import BaseLoader +from jinja2 import FileSystemLoader +from werkzeug.exceptions import default_exceptions +from werkzeug.exceptions import HTTPException +from werkzeug.utils import cached_property + +from .. import typing as ft +from ..helpers import get_root_path +from ..templating import _default_template_ctx_processor + +if t.TYPE_CHECKING: # pragma: no cover + from click import Group + +# a singleton sentinel value for parameter defaults +_sentinel = object() + +F = t.TypeVar("F", bound=t.Callable[..., t.Any]) +T_after_request = t.TypeVar("T_after_request", bound=ft.AfterRequestCallable[t.Any]) +T_before_request = t.TypeVar("T_before_request", bound=ft.BeforeRequestCallable) +T_error_handler = t.TypeVar("T_error_handler", bound=ft.ErrorHandlerCallable) +T_teardown = t.TypeVar("T_teardown", bound=ft.TeardownCallable) +T_template_context_processor = t.TypeVar( + "T_template_context_processor", bound=ft.TemplateContextProcessorCallable +) +T_url_defaults = t.TypeVar("T_url_defaults", bound=ft.URLDefaultCallable) +T_url_value_preprocessor = t.TypeVar( + "T_url_value_preprocessor", bound=ft.URLValuePreprocessorCallable +) +T_route = t.TypeVar("T_route", bound=ft.RouteCallable) + + +def setupmethod(f: F) -> F: + f_name = f.__name__ + + def wrapper_func(self: Scaffold, *args: t.Any, **kwargs: t.Any) -> t.Any: + self._check_setup_finished(f_name) + return f(self, *args, **kwargs) + + return t.cast(F, update_wrapper(wrapper_func, f)) + + +class Scaffold: + """Common behavior shared between :class:`~flask.Flask` and + :class:`~flask.blueprints.Blueprint`. + + :param import_name: The import name of the module where this object + is defined. Usually :attr:`__name__` should be used. + :param static_folder: Path to a folder of static files to serve. + If this is set, a static route will be added. + :param static_url_path: URL prefix for the static route. + :param template_folder: Path to a folder containing template files. + for rendering. If this is set, a Jinja loader will be added. + :param root_path: The path that static, template, and resource files + are relative to. Typically not set, it is discovered based on + the ``import_name``. + + .. versionadded:: 2.0 + """ + + cli: Group + name: str + _static_folder: str | None = None + _static_url_path: str | None = None + + def __init__( + self, + import_name: str, + static_folder: str | os.PathLike[str] | None = None, + static_url_path: str | None = None, + template_folder: str | os.PathLike[str] | None = None, + root_path: str | None = None, + ): + #: The name of the package or module that this object belongs + #: to. Do not change this once it is set by the constructor. + self.import_name = import_name + + self.static_folder = static_folder # type: ignore + self.static_url_path = static_url_path + + #: The path to the templates folder, relative to + #: :attr:`root_path`, to add to the template loader. ``None`` if + #: templates should not be added. + self.template_folder = template_folder + + if root_path is None: + root_path = get_root_path(self.import_name) + + #: Absolute path to the package on the filesystem. Used to look + #: up resources contained in the package. + self.root_path = root_path + + #: A dictionary mapping endpoint names to view functions. + #: + #: To register a view function, use the :meth:`route` decorator. + #: + #: This data structure is internal. It should not be modified + #: directly and its format may change at any time. + self.view_functions: dict[str, ft.RouteCallable] = {} + + #: A data structure of registered error handlers, in the format + #: ``{scope: {code: {class: handler}}}``. The ``scope`` key is + #: the name of a blueprint the handlers are active for, or + #: ``None`` for all requests. The ``code`` key is the HTTP + #: status code for ``HTTPException``, or ``None`` for + #: other exceptions. The innermost dictionary maps exception + #: classes to handler functions. + #: + #: To register an error handler, use the :meth:`errorhandler` + #: decorator. + #: + #: This data structure is internal. It should not be modified + #: directly and its format may change at any time. + self.error_handler_spec: dict[ + ft.AppOrBlueprintKey, + dict[int | None, dict[type[Exception], ft.ErrorHandlerCallable]], + ] = defaultdict(lambda: defaultdict(dict)) + + #: A data structure of functions to call at the beginning of + #: each request, in the format ``{scope: [functions]}``. The + #: ``scope`` key is the name of a blueprint the functions are + #: active for, or ``None`` for all requests. + #: + #: To register a function, use the :meth:`before_request` + #: decorator. + #: + #: This data structure is internal. It should not be modified + #: directly and its format may change at any time. + self.before_request_funcs: dict[ + ft.AppOrBlueprintKey, list[ft.BeforeRequestCallable] + ] = defaultdict(list) + + #: A data structure of functions to call at the end of each + #: request, in the format ``{scope: [functions]}``. The + #: ``scope`` key is the name of a blueprint the functions are + #: active for, or ``None`` for all requests. + #: + #: To register a function, use the :meth:`after_request` + #: decorator. + #: + #: This data structure is internal. It should not be modified + #: directly and its format may change at any time. + self.after_request_funcs: dict[ + ft.AppOrBlueprintKey, list[ft.AfterRequestCallable[t.Any]] + ] = defaultdict(list) + + #: A data structure of functions to call at the end of each + #: request even if an exception is raised, in the format + #: ``{scope: [functions]}``. The ``scope`` key is the name of a + #: blueprint the functions are active for, or ``None`` for all + #: requests. + #: + #: To register a function, use the :meth:`teardown_request` + #: decorator. + #: + #: This data structure is internal. It should not be modified + #: directly and its format may change at any time. + self.teardown_request_funcs: dict[ + ft.AppOrBlueprintKey, list[ft.TeardownCallable] + ] = defaultdict(list) + + #: A data structure of functions to call to pass extra context + #: values when rendering templates, in the format + #: ``{scope: [functions]}``. The ``scope`` key is the name of a + #: blueprint the functions are active for, or ``None`` for all + #: requests. + #: + #: To register a function, use the :meth:`context_processor` + #: decorator. + #: + #: This data structure is internal. It should not be modified + #: directly and its format may change at any time. + self.template_context_processors: dict[ + ft.AppOrBlueprintKey, list[ft.TemplateContextProcessorCallable] + ] = defaultdict(list, {None: [_default_template_ctx_processor]}) + + #: A data structure of functions to call to modify the keyword + #: arguments passed to the view function, in the format + #: ``{scope: [functions]}``. The ``scope`` key is the name of a + #: blueprint the functions are active for, or ``None`` for all + #: requests. + #: + #: To register a function, use the + #: :meth:`url_value_preprocessor` decorator. + #: + #: This data structure is internal. It should not be modified + #: directly and its format may change at any time. + self.url_value_preprocessors: dict[ + ft.AppOrBlueprintKey, + list[ft.URLValuePreprocessorCallable], + ] = defaultdict(list) + + #: A data structure of functions to call to modify the keyword + #: arguments when generating URLs, in the format + #: ``{scope: [functions]}``. The ``scope`` key is the name of a + #: blueprint the functions are active for, or ``None`` for all + #: requests. + #: + #: To register a function, use the :meth:`url_defaults` + #: decorator. + #: + #: This data structure is internal. It should not be modified + #: directly and its format may change at any time. + self.url_default_functions: dict[ + ft.AppOrBlueprintKey, list[ft.URLDefaultCallable] + ] = defaultdict(list) + + def __repr__(self) -> str: + return f"<{type(self).__name__} {self.name!r}>" + + def _check_setup_finished(self, f_name: str) -> None: + raise NotImplementedError + + @property + def static_folder(self) -> str | None: + """The absolute path to the configured static folder. ``None`` + if no static folder is set. + """ + if self._static_folder is not None: + return os.path.join(self.root_path, self._static_folder) + else: + return None + + @static_folder.setter + def static_folder(self, value: str | os.PathLike[str] | None) -> None: + if value is not None: + value = os.fspath(value).rstrip(r"\/") + + self._static_folder = value + + @property + def has_static_folder(self) -> bool: + """``True`` if :attr:`static_folder` is set. + + .. versionadded:: 0.5 + """ + return self.static_folder is not None + + @property + def static_url_path(self) -> str | None: + """The URL prefix that the static route will be accessible from. + + If it was not configured during init, it is derived from + :attr:`static_folder`. + """ + if self._static_url_path is not None: + return self._static_url_path + + if self.static_folder is not None: + basename = os.path.basename(self.static_folder) + return f"/{basename}".rstrip("/") + + return None + + @static_url_path.setter + def static_url_path(self, value: str | None) -> None: + if value is not None: + value = value.rstrip("/") + + self._static_url_path = value + + @cached_property + def jinja_loader(self) -> BaseLoader | None: + """The Jinja loader for this object's templates. By default this + is a class :class:`jinja2.loaders.FileSystemLoader` to + :attr:`template_folder` if it is set. + + .. versionadded:: 0.5 + """ + if self.template_folder is not None: + return FileSystemLoader(os.path.join(self.root_path, self.template_folder)) + else: + return None + + def _method_route( + self, + method: str, + rule: str, + options: dict[str, t.Any], + ) -> t.Callable[[T_route], T_route]: + if "methods" in options: + raise TypeError("Use the 'route' decorator to use the 'methods' argument.") + + return self.route(rule, methods=[method], **options) + + @setupmethod + def get(self, rule: str, **options: t.Any) -> t.Callable[[T_route], T_route]: + """Shortcut for :meth:`route` with ``methods=["GET"]``. + + .. versionadded:: 2.0 + """ + return self._method_route("GET", rule, options) + + @setupmethod + def post(self, rule: str, **options: t.Any) -> t.Callable[[T_route], T_route]: + """Shortcut for :meth:`route` with ``methods=["POST"]``. + + .. versionadded:: 2.0 + """ + return self._method_route("POST", rule, options) + + @setupmethod + def put(self, rule: str, **options: t.Any) -> t.Callable[[T_route], T_route]: + """Shortcut for :meth:`route` with ``methods=["PUT"]``. + + .. versionadded:: 2.0 + """ + return self._method_route("PUT", rule, options) + + @setupmethod + def delete(self, rule: str, **options: t.Any) -> t.Callable[[T_route], T_route]: + """Shortcut for :meth:`route` with ``methods=["DELETE"]``. + + .. versionadded:: 2.0 + """ + return self._method_route("DELETE", rule, options) + + @setupmethod + def patch(self, rule: str, **options: t.Any) -> t.Callable[[T_route], T_route]: + """Shortcut for :meth:`route` with ``methods=["PATCH"]``. + + .. versionadded:: 2.0 + """ + return self._method_route("PATCH", rule, options) + + @setupmethod + def route(self, rule: str, **options: t.Any) -> t.Callable[[T_route], T_route]: + """Decorate a view function to register it with the given URL + rule and options. Calls :meth:`add_url_rule`, which has more + details about the implementation. + + .. code-block:: python + + @app.route("/") + def index(): + return "Hello, World!" + + See :ref:`url-route-registrations`. + + The endpoint name for the route defaults to the name of the view + function if the ``endpoint`` parameter isn't passed. + + The ``methods`` parameter defaults to ``["GET"]``. ``HEAD`` and + ``OPTIONS`` are added automatically. + + :param rule: The URL rule string. + :param options: Extra options passed to the + :class:`~werkzeug.routing.Rule` object. + """ + + def decorator(f: T_route) -> T_route: + endpoint = options.pop("endpoint", None) + self.add_url_rule(rule, endpoint, f, **options) + return f + + return decorator + + @setupmethod + def add_url_rule( + self, + rule: str, + endpoint: str | None = None, + view_func: ft.RouteCallable | None = None, + provide_automatic_options: bool | None = None, + **options: t.Any, + ) -> None: + """Register a rule for routing incoming requests and building + URLs. The :meth:`route` decorator is a shortcut to call this + with the ``view_func`` argument. These are equivalent: + + .. code-block:: python + + @app.route("/") + def index(): + ... + + .. code-block:: python + + def index(): + ... + + app.add_url_rule("/", view_func=index) + + See :ref:`url-route-registrations`. + + The endpoint name for the route defaults to the name of the view + function if the ``endpoint`` parameter isn't passed. An error + will be raised if a function has already been registered for the + endpoint. + + The ``methods`` parameter defaults to ``["GET"]``. ``HEAD`` is + always added automatically, and ``OPTIONS`` is added + automatically by default. + + ``view_func`` does not necessarily need to be passed, but if the + rule should participate in routing an endpoint name must be + associated with a view function at some point with the + :meth:`endpoint` decorator. + + .. code-block:: python + + app.add_url_rule("/", endpoint="index") + + @app.endpoint("index") + def index(): + ... + + If ``view_func`` has a ``required_methods`` attribute, those + methods are added to the passed and automatic methods. If it + has a ``provide_automatic_methods`` attribute, it is used as the + default if the parameter is not passed. + + :param rule: The URL rule string. + :param endpoint: The endpoint name to associate with the rule + and view function. Used when routing and building URLs. + Defaults to ``view_func.__name__``. + :param view_func: The view function to associate with the + endpoint name. + :param provide_automatic_options: Add the ``OPTIONS`` method and + respond to ``OPTIONS`` requests automatically. + :param options: Extra options passed to the + :class:`~werkzeug.routing.Rule` object. + """ + raise NotImplementedError + + @setupmethod + def endpoint(self, endpoint: str) -> t.Callable[[F], F]: + """Decorate a view function to register it for the given + endpoint. Used if a rule is added without a ``view_func`` with + :meth:`add_url_rule`. + + .. code-block:: python + + app.add_url_rule("/ex", endpoint="example") + + @app.endpoint("example") + def example(): + ... + + :param endpoint: The endpoint name to associate with the view + function. + """ + + def decorator(f: F) -> F: + self.view_functions[endpoint] = f + return f + + return decorator + + @setupmethod + def before_request(self, f: T_before_request) -> T_before_request: + """Register a function to run before each request. + + For example, this can be used to open a database connection, or + to load the logged in user from the session. + + .. code-block:: python + + @app.before_request + def load_user(): + if "user_id" in session: + g.user = db.session.get(session["user_id"]) + + The function will be called without any arguments. If it returns + a non-``None`` value, the value is handled as if it was the + return value from the view, and further request handling is + stopped. + + This is available on both app and blueprint objects. When used on an app, this + executes before every request. When used on a blueprint, this executes before + every request that the blueprint handles. To register with a blueprint and + execute before every request, use :meth:`.Blueprint.before_app_request`. + """ + self.before_request_funcs.setdefault(None, []).append(f) + return f + + @setupmethod + def after_request(self, f: T_after_request) -> T_after_request: + """Register a function to run after each request to this object. + + The function is called with the response object, and must return + a response object. This allows the functions to modify or + replace the response before it is sent. + + If a function raises an exception, any remaining + ``after_request`` functions will not be called. Therefore, this + should not be used for actions that must execute, such as to + close resources. Use :meth:`teardown_request` for that. + + This is available on both app and blueprint objects. When used on an app, this + executes after every request. When used on a blueprint, this executes after + every request that the blueprint handles. To register with a blueprint and + execute after every request, use :meth:`.Blueprint.after_app_request`. + """ + self.after_request_funcs.setdefault(None, []).append(f) + return f + + @setupmethod + def teardown_request(self, f: T_teardown) -> T_teardown: + """Register a function to be called when the request context is + popped. Typically this happens at the end of each request, but + contexts may be pushed manually as well during testing. + + .. code-block:: python + + with app.test_request_context(): + ... + + When the ``with`` block exits (or ``ctx.pop()`` is called), the + teardown functions are called just before the request context is + made inactive. + + When a teardown function was called because of an unhandled + exception it will be passed an error object. If an + :meth:`errorhandler` is registered, it will handle the exception + and the teardown will not receive it. + + Teardown functions must avoid raising exceptions. If they + execute code that might fail they must surround that code with a + ``try``/``except`` block and log any errors. + + The return values of teardown functions are ignored. + + This is available on both app and blueprint objects. When used on an app, this + executes after every request. When used on a blueprint, this executes after + every request that the blueprint handles. To register with a blueprint and + execute after every request, use :meth:`.Blueprint.teardown_app_request`. + """ + self.teardown_request_funcs.setdefault(None, []).append(f) + return f + + @setupmethod + def context_processor( + self, + f: T_template_context_processor, + ) -> T_template_context_processor: + """Registers a template context processor function. These functions run before + rendering a template. The keys of the returned dict are added as variables + available in the template. + + This is available on both app and blueprint objects. When used on an app, this + is called for every rendered template. When used on a blueprint, this is called + for templates rendered from the blueprint's views. To register with a blueprint + and affect every template, use :meth:`.Blueprint.app_context_processor`. + """ + self.template_context_processors[None].append(f) + return f + + @setupmethod + def url_value_preprocessor( + self, + f: T_url_value_preprocessor, + ) -> T_url_value_preprocessor: + """Register a URL value preprocessor function for all view + functions in the application. These functions will be called before the + :meth:`before_request` functions. + + The function can modify the values captured from the matched url before + they are passed to the view. For example, this can be used to pop a + common language code value and place it in ``g`` rather than pass it to + every view. + + The function is passed the endpoint name and values dict. The return + value is ignored. + + This is available on both app and blueprint objects. When used on an app, this + is called for every request. When used on a blueprint, this is called for + requests that the blueprint handles. To register with a blueprint and affect + every request, use :meth:`.Blueprint.app_url_value_preprocessor`. + """ + self.url_value_preprocessors[None].append(f) + return f + + @setupmethod + def url_defaults(self, f: T_url_defaults) -> T_url_defaults: + """Callback function for URL defaults for all view functions of the + application. It's called with the endpoint and values and should + update the values passed in place. + + This is available on both app and blueprint objects. When used on an app, this + is called for every request. When used on a blueprint, this is called for + requests that the blueprint handles. To register with a blueprint and affect + every request, use :meth:`.Blueprint.app_url_defaults`. + """ + self.url_default_functions[None].append(f) + return f + + @setupmethod + def errorhandler( + self, code_or_exception: type[Exception] | int + ) -> t.Callable[[T_error_handler], T_error_handler]: + """Register a function to handle errors by code or exception class. + + A decorator that is used to register a function given an + error code. Example:: + + @app.errorhandler(404) + def page_not_found(error): + return 'This page does not exist', 404 + + You can also register handlers for arbitrary exceptions:: + + @app.errorhandler(DatabaseError) + def special_exception_handler(error): + return 'Database connection failed', 500 + + This is available on both app and blueprint objects. When used on an app, this + can handle errors from every request. When used on a blueprint, this can handle + errors from requests that the blueprint handles. To register with a blueprint + and affect every request, use :meth:`.Blueprint.app_errorhandler`. + + .. versionadded:: 0.7 + Use :meth:`register_error_handler` instead of modifying + :attr:`error_handler_spec` directly, for application wide error + handlers. + + .. versionadded:: 0.7 + One can now additionally also register custom exception types + that do not necessarily have to be a subclass of the + :class:`~werkzeug.exceptions.HTTPException` class. + + :param code_or_exception: the code as integer for the handler, or + an arbitrary exception + """ + + def decorator(f: T_error_handler) -> T_error_handler: + self.register_error_handler(code_or_exception, f) + return f + + return decorator + + @setupmethod + def register_error_handler( + self, + code_or_exception: type[Exception] | int, + f: ft.ErrorHandlerCallable, + ) -> None: + """Alternative error attach function to the :meth:`errorhandler` + decorator that is more straightforward to use for non decorator + usage. + + .. versionadded:: 0.7 + """ + exc_class, code = self._get_exc_class_and_code(code_or_exception) + self.error_handler_spec[None][code][exc_class] = f + + @staticmethod + def _get_exc_class_and_code( + exc_class_or_code: type[Exception] | int, + ) -> tuple[type[Exception], int | None]: + """Get the exception class being handled. For HTTP status codes + or ``HTTPException`` subclasses, return both the exception and + status code. + + :param exc_class_or_code: Any exception class, or an HTTP status + code as an integer. + """ + exc_class: type[Exception] + + if isinstance(exc_class_or_code, int): + try: + exc_class = default_exceptions[exc_class_or_code] + except KeyError: + raise ValueError( + f"'{exc_class_or_code}' is not a recognized HTTP" + " error code. Use a subclass of HTTPException with" + " that code instead." + ) from None + else: + exc_class = exc_class_or_code + + if isinstance(exc_class, Exception): + raise TypeError( + f"{exc_class!r} is an instance, not a class. Handlers" + " can only be registered for Exception classes or HTTP" + " error codes." + ) + + if not issubclass(exc_class, Exception): + raise ValueError( + f"'{exc_class.__name__}' is not a subclass of Exception." + " Handlers can only be registered for Exception classes" + " or HTTP error codes." + ) + + if issubclass(exc_class, HTTPException): + return exc_class, exc_class.code + else: + return exc_class, None + + +def _endpoint_from_view_func(view_func: ft.RouteCallable) -> str: + """Internal helper that returns the default endpoint for a given + function. This always is the function name. + """ + assert view_func is not None, "expected view func if endpoint is not provided." + return view_func.__name__ + + +def _find_package_path(import_name: str) -> str: + """Find the path that contains the package or module.""" + root_mod_name, _, _ = import_name.partition(".") + + try: + root_spec = importlib.util.find_spec(root_mod_name) + + if root_spec is None: + raise ValueError("not found") + except (ImportError, ValueError): + # ImportError: the machinery told us it does not exist + # ValueError: + # - the module name was invalid + # - the module name is __main__ + # - we raised `ValueError` due to `root_spec` being `None` + return os.getcwd() + + if root_spec.submodule_search_locations: + if root_spec.origin is None or root_spec.origin == "namespace": + # namespace package + package_spec = importlib.util.find_spec(import_name) + + if package_spec is not None and package_spec.submodule_search_locations: + # Pick the path in the namespace that contains the submodule. + package_path = pathlib.Path( + os.path.commonpath(package_spec.submodule_search_locations) + ) + search_location = next( + location + for location in root_spec.submodule_search_locations + if package_path.is_relative_to(location) + ) + else: + # Pick the first path. + search_location = root_spec.submodule_search_locations[0] + + return os.path.dirname(search_location) + else: + # package with __init__.py + return os.path.dirname(os.path.dirname(root_spec.origin)) + else: + # module + return os.path.dirname(root_spec.origin) # type: ignore[type-var, return-value] + + +def find_package(import_name: str) -> tuple[str | None, str]: + """Find the prefix that a package is installed under, and the path + that it would be imported from. + + The prefix is the directory containing the standard directory + hierarchy (lib, bin, etc.). If the package is not installed to the + system (:attr:`sys.prefix`) or a virtualenv (``site-packages``), + ``None`` is returned. + + The path is the entry in :attr:`sys.path` that contains the package + for import. If the package is not installed, it's assumed that the + package was imported from the current working directory. + """ + package_path = _find_package_path(import_name) + py_prefix = os.path.abspath(sys.prefix) + + # installed to the system + if pathlib.PurePath(package_path).is_relative_to(py_prefix): + return py_prefix, package_path + + site_parent, site_folder = os.path.split(package_path) + + # installed to a virtualenv + if site_folder.lower() == "site-packages": + parent, folder = os.path.split(site_parent) + + # Windows (prefix/lib/site-packages) + if folder.lower() == "lib": + return parent, package_path + + # Unix (prefix/lib/pythonX.Y/site-packages) + if os.path.basename(parent).lower() == "lib": + return os.path.dirname(parent), package_path + + # something else (prefix/site-packages) + return site_parent, package_path + + # not installed + return None, package_path diff --git a/psets/9/finance/env/lib/python3.12/site-packages/flask/sessions.py b/psets/9/finance/env/lib/python3.12/site-packages/flask/sessions.py new file mode 100644 index 0000000..375de06 --- /dev/null +++ b/psets/9/finance/env/lib/python3.12/site-packages/flask/sessions.py @@ -0,0 +1,398 @@ +from __future__ import annotations + +import collections.abc as c +import hashlib +import typing as t +from collections.abc import MutableMapping +from datetime import datetime +from datetime import timezone + +from itsdangerous import BadSignature +from itsdangerous import URLSafeTimedSerializer +from werkzeug.datastructures import CallbackDict + +from .json.tag import TaggedJSONSerializer + +if t.TYPE_CHECKING: # pragma: no cover + import typing_extensions as te + + from .app import Flask + from .wrappers import Request + from .wrappers import Response + + +class SessionMixin(MutableMapping[str, t.Any]): + """Expands a basic dictionary with session attributes.""" + + @property + def permanent(self) -> bool: + """This reflects the ``'_permanent'`` key in the dict.""" + return self.get("_permanent", False) + + @permanent.setter + def permanent(self, value: bool) -> None: + self["_permanent"] = bool(value) + + #: Some implementations can detect whether a session is newly + #: created, but that is not guaranteed. Use with caution. The mixin + # default is hard-coded ``False``. + new = False + + #: Some implementations can detect changes to the session and set + #: this when that happens. The mixin default is hard coded to + #: ``True``. + modified = True + + #: Some implementations can detect when session data is read or + #: written and set this when that happens. The mixin default is hard + #: coded to ``True``. + accessed = True + + +class SecureCookieSession(CallbackDict[str, t.Any], SessionMixin): + """Base class for sessions based on signed cookies. + + This session backend will set the :attr:`modified` and + :attr:`accessed` attributes. It cannot reliably track whether a + session is new (vs. empty), so :attr:`new` remains hard coded to + ``False``. + """ + + #: When data is changed, this is set to ``True``. Only the session + #: dictionary itself is tracked; if the session contains mutable + #: data (for example a nested dict) then this must be set to + #: ``True`` manually when modifying that data. The session cookie + #: will only be written to the response if this is ``True``. + modified = False + + #: When data is read or written, this is set to ``True``. Used by + # :class:`.SecureCookieSessionInterface` to add a ``Vary: Cookie`` + #: header, which allows caching proxies to cache different pages for + #: different users. + accessed = False + + def __init__( + self, + initial: c.Mapping[str, t.Any] | c.Iterable[tuple[str, t.Any]] | None = None, + ) -> None: + def on_update(self: te.Self) -> None: + self.modified = True + self.accessed = True + + super().__init__(initial, on_update) + + def __getitem__(self, key: str) -> t.Any: + self.accessed = True + return super().__getitem__(key) + + def get(self, key: str, default: t.Any = None) -> t.Any: + self.accessed = True + return super().get(key, default) + + def setdefault(self, key: str, default: t.Any = None) -> t.Any: + self.accessed = True + return super().setdefault(key, default) + + +class NullSession(SecureCookieSession): + """Class used to generate nicer error messages if sessions are not + available. Will still allow read-only access to the empty session + but fail on setting. + """ + + def _fail(self, *args: t.Any, **kwargs: t.Any) -> t.NoReturn: + raise RuntimeError( + "The session is unavailable because no secret " + "key was set. Set the secret_key on the " + "application to something unique and secret." + ) + + __setitem__ = __delitem__ = clear = pop = popitem = update = setdefault = _fail # type: ignore # noqa: B950 + del _fail + + +class SessionInterface: + """The basic interface you have to implement in order to replace the + default session interface which uses werkzeug's securecookie + implementation. The only methods you have to implement are + :meth:`open_session` and :meth:`save_session`, the others have + useful defaults which you don't need to change. + + The session object returned by the :meth:`open_session` method has to + provide a dictionary like interface plus the properties and methods + from the :class:`SessionMixin`. We recommend just subclassing a dict + and adding that mixin:: + + class Session(dict, SessionMixin): + pass + + If :meth:`open_session` returns ``None`` Flask will call into + :meth:`make_null_session` to create a session that acts as replacement + if the session support cannot work because some requirement is not + fulfilled. The default :class:`NullSession` class that is created + will complain that the secret key was not set. + + To replace the session interface on an application all you have to do + is to assign :attr:`flask.Flask.session_interface`:: + + app = Flask(__name__) + app.session_interface = MySessionInterface() + + Multiple requests with the same session may be sent and handled + concurrently. When implementing a new session interface, consider + whether reads or writes to the backing store must be synchronized. + There is no guarantee on the order in which the session for each + request is opened or saved, it will occur in the order that requests + begin and end processing. + + .. versionadded:: 0.8 + """ + + #: :meth:`make_null_session` will look here for the class that should + #: be created when a null session is requested. Likewise the + #: :meth:`is_null_session` method will perform a typecheck against + #: this type. + null_session_class = NullSession + + #: A flag that indicates if the session interface is pickle based. + #: This can be used by Flask extensions to make a decision in regards + #: to how to deal with the session object. + #: + #: .. versionadded:: 0.10 + pickle_based = False + + def make_null_session(self, app: Flask) -> NullSession: + """Creates a null session which acts as a replacement object if the + real session support could not be loaded due to a configuration + error. This mainly aids the user experience because the job of the + null session is to still support lookup without complaining but + modifications are answered with a helpful error message of what + failed. + + This creates an instance of :attr:`null_session_class` by default. + """ + return self.null_session_class() + + def is_null_session(self, obj: object) -> bool: + """Checks if a given object is a null session. Null sessions are + not asked to be saved. + + This checks if the object is an instance of :attr:`null_session_class` + by default. + """ + return isinstance(obj, self.null_session_class) + + def get_cookie_name(self, app: Flask) -> str: + """The name of the session cookie. Uses``app.config["SESSION_COOKIE_NAME"]``.""" + return app.config["SESSION_COOKIE_NAME"] # type: ignore[no-any-return] + + def get_cookie_domain(self, app: Flask) -> str | None: + """The value of the ``Domain`` parameter on the session cookie. If not set, + browsers will only send the cookie to the exact domain it was set from. + Otherwise, they will send it to any subdomain of the given value as well. + + Uses the :data:`SESSION_COOKIE_DOMAIN` config. + + .. versionchanged:: 2.3 + Not set by default, does not fall back to ``SERVER_NAME``. + """ + return app.config["SESSION_COOKIE_DOMAIN"] # type: ignore[no-any-return] + + def get_cookie_path(self, app: Flask) -> str: + """Returns the path for which the cookie should be valid. The + default implementation uses the value from the ``SESSION_COOKIE_PATH`` + config var if it's set, and falls back to ``APPLICATION_ROOT`` or + uses ``/`` if it's ``None``. + """ + return app.config["SESSION_COOKIE_PATH"] or app.config["APPLICATION_ROOT"] # type: ignore[no-any-return] + + def get_cookie_httponly(self, app: Flask) -> bool: + """Returns True if the session cookie should be httponly. This + currently just returns the value of the ``SESSION_COOKIE_HTTPONLY`` + config var. + """ + return app.config["SESSION_COOKIE_HTTPONLY"] # type: ignore[no-any-return] + + def get_cookie_secure(self, app: Flask) -> bool: + """Returns True if the cookie should be secure. This currently + just returns the value of the ``SESSION_COOKIE_SECURE`` setting. + """ + return app.config["SESSION_COOKIE_SECURE"] # type: ignore[no-any-return] + + def get_cookie_samesite(self, app: Flask) -> str | None: + """Return ``'Strict'`` or ``'Lax'`` if the cookie should use the + ``SameSite`` attribute. This currently just returns the value of + the :data:`SESSION_COOKIE_SAMESITE` setting. + """ + return app.config["SESSION_COOKIE_SAMESITE"] # type: ignore[no-any-return] + + def get_cookie_partitioned(self, app: Flask) -> bool: + """Returns True if the cookie should be partitioned. By default, uses + the value of :data:`SESSION_COOKIE_PARTITIONED`. + + .. versionadded:: 3.1 + """ + return app.config["SESSION_COOKIE_PARTITIONED"] # type: ignore[no-any-return] + + def get_expiration_time(self, app: Flask, session: SessionMixin) -> datetime | None: + """A helper method that returns an expiration date for the session + or ``None`` if the session is linked to the browser session. The + default implementation returns now + the permanent session + lifetime configured on the application. + """ + if session.permanent: + return datetime.now(timezone.utc) + app.permanent_session_lifetime + return None + + def should_set_cookie(self, app: Flask, session: SessionMixin) -> bool: + """Used by session backends to determine if a ``Set-Cookie`` header + should be set for this session cookie for this response. If the session + has been modified, the cookie is set. If the session is permanent and + the ``SESSION_REFRESH_EACH_REQUEST`` config is true, the cookie is + always set. + + This check is usually skipped if the session was deleted. + + .. versionadded:: 0.11 + """ + + return session.modified or ( + session.permanent and app.config["SESSION_REFRESH_EACH_REQUEST"] + ) + + def open_session(self, app: Flask, request: Request) -> SessionMixin | None: + """This is called at the beginning of each request, after + pushing the request context, before matching the URL. + + This must return an object which implements a dictionary-like + interface as well as the :class:`SessionMixin` interface. + + This will return ``None`` to indicate that loading failed in + some way that is not immediately an error. The request + context will fall back to using :meth:`make_null_session` + in this case. + """ + raise NotImplementedError() + + def save_session( + self, app: Flask, session: SessionMixin, response: Response + ) -> None: + """This is called at the end of each request, after generating + a response, before removing the request context. It is skipped + if :meth:`is_null_session` returns ``True``. + """ + raise NotImplementedError() + + +session_json_serializer = TaggedJSONSerializer() + + +def _lazy_sha1(string: bytes = b"") -> t.Any: + """Don't access ``hashlib.sha1`` until runtime. FIPS builds may not include + SHA-1, in which case the import and use as a default would fail before the + developer can configure something else. + """ + return hashlib.sha1(string) + + +class SecureCookieSessionInterface(SessionInterface): + """The default session interface that stores sessions in signed cookies + through the :mod:`itsdangerous` module. + """ + + #: the salt that should be applied on top of the secret key for the + #: signing of cookie based sessions. + salt = "cookie-session" + #: the hash function to use for the signature. The default is sha1 + digest_method = staticmethod(_lazy_sha1) + #: the name of the itsdangerous supported key derivation. The default + #: is hmac. + key_derivation = "hmac" + #: A python serializer for the payload. The default is a compact + #: JSON derived serializer with support for some extra Python types + #: such as datetime objects or tuples. + serializer = session_json_serializer + session_class = SecureCookieSession + + def get_signing_serializer(self, app: Flask) -> URLSafeTimedSerializer | None: + if not app.secret_key: + return None + + keys: list[str | bytes] = [app.secret_key] + + if fallbacks := app.config["SECRET_KEY_FALLBACKS"]: + keys.extend(fallbacks) + + return URLSafeTimedSerializer( + keys, # type: ignore[arg-type] + salt=self.salt, + serializer=self.serializer, + signer_kwargs={ + "key_derivation": self.key_derivation, + "digest_method": self.digest_method, + }, + ) + + def open_session(self, app: Flask, request: Request) -> SecureCookieSession | None: + s = self.get_signing_serializer(app) + if s is None: + return None + val = request.cookies.get(self.get_cookie_name(app)) + if not val: + return self.session_class() + max_age = int(app.permanent_session_lifetime.total_seconds()) + try: + data = s.loads(val, max_age=max_age) + return self.session_class(data) + except BadSignature: + return self.session_class() + + def save_session( + self, app: Flask, session: SessionMixin, response: Response + ) -> None: + name = self.get_cookie_name(app) + domain = self.get_cookie_domain(app) + path = self.get_cookie_path(app) + secure = self.get_cookie_secure(app) + partitioned = self.get_cookie_partitioned(app) + samesite = self.get_cookie_samesite(app) + httponly = self.get_cookie_httponly(app) + + # Add a "Vary: Cookie" header if the session was accessed at all. + if session.accessed: + response.vary.add("Cookie") + + # If the session is modified to be empty, remove the cookie. + # If the session is empty, return without setting the cookie. + if not session: + if session.modified: + response.delete_cookie( + name, + domain=domain, + path=path, + secure=secure, + partitioned=partitioned, + samesite=samesite, + httponly=httponly, + ) + response.vary.add("Cookie") + + return + + if not self.should_set_cookie(app, session): + return + + expires = self.get_expiration_time(app, session) + val = self.get_signing_serializer(app).dumps(dict(session)) # type: ignore[union-attr] + response.set_cookie( + name, + val, + expires=expires, + httponly=httponly, + domain=domain, + path=path, + secure=secure, + partitioned=partitioned, + samesite=samesite, + ) + response.vary.add("Cookie") diff --git a/psets/9/finance/env/lib/python3.12/site-packages/flask/signals.py b/psets/9/finance/env/lib/python3.12/site-packages/flask/signals.py new file mode 100644 index 0000000..444fda9 --- /dev/null +++ b/psets/9/finance/env/lib/python3.12/site-packages/flask/signals.py @@ -0,0 +1,17 @@ +from __future__ import annotations + +from blinker import Namespace + +# This namespace is only for signals provided by Flask itself. +_signals = Namespace() + +template_rendered = _signals.signal("template-rendered") +before_render_template = _signals.signal("before-render-template") +request_started = _signals.signal("request-started") +request_finished = _signals.signal("request-finished") +request_tearing_down = _signals.signal("request-tearing-down") +got_request_exception = _signals.signal("got-request-exception") +appcontext_tearing_down = _signals.signal("appcontext-tearing-down") +appcontext_pushed = _signals.signal("appcontext-pushed") +appcontext_popped = _signals.signal("appcontext-popped") +message_flashed = _signals.signal("message-flashed") diff --git a/psets/9/finance/env/lib/python3.12/site-packages/flask/templating.py b/psets/9/finance/env/lib/python3.12/site-packages/flask/templating.py new file mode 100644 index 0000000..618a3b3 --- /dev/null +++ b/psets/9/finance/env/lib/python3.12/site-packages/flask/templating.py @@ -0,0 +1,219 @@ +from __future__ import annotations + +import typing as t + +from jinja2 import BaseLoader +from jinja2 import Environment as BaseEnvironment +from jinja2 import Template +from jinja2 import TemplateNotFound + +from .globals import _cv_app +from .globals import _cv_request +from .globals import current_app +from .globals import request +from .helpers import stream_with_context +from .signals import before_render_template +from .signals import template_rendered + +if t.TYPE_CHECKING: # pragma: no cover + from .app import Flask + from .sansio.app import App + from .sansio.scaffold import Scaffold + + +def _default_template_ctx_processor() -> dict[str, t.Any]: + """Default template context processor. Injects `request`, + `session` and `g`. + """ + appctx = _cv_app.get(None) + reqctx = _cv_request.get(None) + rv: dict[str, t.Any] = {} + if appctx is not None: + rv["g"] = appctx.g + if reqctx is not None: + rv["request"] = reqctx.request + rv["session"] = reqctx.session + return rv + + +class Environment(BaseEnvironment): + """Works like a regular Jinja2 environment but has some additional + knowledge of how Flask's blueprint works so that it can prepend the + name of the blueprint to referenced templates if necessary. + """ + + def __init__(self, app: App, **options: t.Any) -> None: + if "loader" not in options: + options["loader"] = app.create_global_jinja_loader() + BaseEnvironment.__init__(self, **options) + self.app = app + + +class DispatchingJinjaLoader(BaseLoader): + """A loader that looks for templates in the application and all + the blueprint folders. + """ + + def __init__(self, app: App) -> None: + self.app = app + + def get_source( + self, environment: BaseEnvironment, template: str + ) -> tuple[str, str | None, t.Callable[[], bool] | None]: + if self.app.config["EXPLAIN_TEMPLATE_LOADING"]: + return self._get_source_explained(environment, template) + return self._get_source_fast(environment, template) + + def _get_source_explained( + self, environment: BaseEnvironment, template: str + ) -> tuple[str, str | None, t.Callable[[], bool] | None]: + attempts = [] + rv: tuple[str, str | None, t.Callable[[], bool] | None] | None + trv: None | (tuple[str, str | None, t.Callable[[], bool] | None]) = None + + for srcobj, loader in self._iter_loaders(template): + try: + rv = loader.get_source(environment, template) + if trv is None: + trv = rv + except TemplateNotFound: + rv = None + attempts.append((loader, srcobj, rv)) + + from .debughelpers import explain_template_loading_attempts + + explain_template_loading_attempts(self.app, template, attempts) + + if trv is not None: + return trv + raise TemplateNotFound(template) + + def _get_source_fast( + self, environment: BaseEnvironment, template: str + ) -> tuple[str, str | None, t.Callable[[], bool] | None]: + for _srcobj, loader in self._iter_loaders(template): + try: + return loader.get_source(environment, template) + except TemplateNotFound: + continue + raise TemplateNotFound(template) + + def _iter_loaders(self, template: str) -> t.Iterator[tuple[Scaffold, BaseLoader]]: + loader = self.app.jinja_loader + if loader is not None: + yield self.app, loader + + for blueprint in self.app.iter_blueprints(): + loader = blueprint.jinja_loader + if loader is not None: + yield blueprint, loader + + def list_templates(self) -> list[str]: + result = set() + loader = self.app.jinja_loader + if loader is not None: + result.update(loader.list_templates()) + + for blueprint in self.app.iter_blueprints(): + loader = blueprint.jinja_loader + if loader is not None: + for template in loader.list_templates(): + result.add(template) + + return list(result) + + +def _render(app: Flask, template: Template, context: dict[str, t.Any]) -> str: + app.update_template_context(context) + before_render_template.send( + app, _async_wrapper=app.ensure_sync, template=template, context=context + ) + rv = template.render(context) + template_rendered.send( + app, _async_wrapper=app.ensure_sync, template=template, context=context + ) + return rv + + +def render_template( + template_name_or_list: str | Template | list[str | Template], + **context: t.Any, +) -> str: + """Render a template by name with the given context. + + :param template_name_or_list: The name of the template to render. If + a list is given, the first name to exist will be rendered. + :param context: The variables to make available in the template. + """ + app = current_app._get_current_object() # type: ignore[attr-defined] + template = app.jinja_env.get_or_select_template(template_name_or_list) + return _render(app, template, context) + + +def render_template_string(source: str, **context: t.Any) -> str: + """Render a template from the given source string with the given + context. + + :param source: The source code of the template to render. + :param context: The variables to make available in the template. + """ + app = current_app._get_current_object() # type: ignore[attr-defined] + template = app.jinja_env.from_string(source) + return _render(app, template, context) + + +def _stream( + app: Flask, template: Template, context: dict[str, t.Any] +) -> t.Iterator[str]: + app.update_template_context(context) + before_render_template.send( + app, _async_wrapper=app.ensure_sync, template=template, context=context + ) + + def generate() -> t.Iterator[str]: + yield from template.generate(context) + template_rendered.send( + app, _async_wrapper=app.ensure_sync, template=template, context=context + ) + + rv = generate() + + # If a request context is active, keep it while generating. + if request: + rv = stream_with_context(rv) + + return rv + + +def stream_template( + template_name_or_list: str | Template | list[str | Template], + **context: t.Any, +) -> t.Iterator[str]: + """Render a template by name with the given context as a stream. + This returns an iterator of strings, which can be used as a + streaming response from a view. + + :param template_name_or_list: The name of the template to render. If + a list is given, the first name to exist will be rendered. + :param context: The variables to make available in the template. + + .. versionadded:: 2.2 + """ + app = current_app._get_current_object() # type: ignore[attr-defined] + template = app.jinja_env.get_or_select_template(template_name_or_list) + return _stream(app, template, context) + + +def stream_template_string(source: str, **context: t.Any) -> t.Iterator[str]: + """Render a template from the given source string with the given + context as a stream. This returns an iterator of strings, which can + be used as a streaming response from a view. + + :param source: The source code of the template to render. + :param context: The variables to make available in the template. + + .. versionadded:: 2.2 + """ + app = current_app._get_current_object() # type: ignore[attr-defined] + template = app.jinja_env.from_string(source) + return _stream(app, template, context) diff --git a/psets/9/finance/env/lib/python3.12/site-packages/flask/testing.py b/psets/9/finance/env/lib/python3.12/site-packages/flask/testing.py new file mode 100644 index 0000000..602b773 --- /dev/null +++ b/psets/9/finance/env/lib/python3.12/site-packages/flask/testing.py @@ -0,0 +1,297 @@ +from __future__ import annotations + +import importlib.metadata +import typing as t +from contextlib import contextmanager +from contextlib import ExitStack +from copy import copy +from types import TracebackType +from urllib.parse import urlsplit + +import werkzeug.test +from click.testing import CliRunner +from werkzeug.test import Client +from werkzeug.wrappers import Request as BaseRequest + +from .cli import ScriptInfo +from .sessions import SessionMixin + +if t.TYPE_CHECKING: # pragma: no cover + from _typeshed.wsgi import WSGIEnvironment + from werkzeug.test import TestResponse + + from .app import Flask + + +class EnvironBuilder(werkzeug.test.EnvironBuilder): + """An :class:`~werkzeug.test.EnvironBuilder`, that takes defaults from the + application. + + :param app: The Flask application to configure the environment from. + :param path: URL path being requested. + :param base_url: Base URL where the app is being served, which + ``path`` is relative to. If not given, built from + :data:`PREFERRED_URL_SCHEME`, ``subdomain``, + :data:`SERVER_NAME`, and :data:`APPLICATION_ROOT`. + :param subdomain: Subdomain name to append to :data:`SERVER_NAME`. + :param url_scheme: Scheme to use instead of + :data:`PREFERRED_URL_SCHEME`. + :param json: If given, this is serialized as JSON and passed as + ``data``. Also defaults ``content_type`` to + ``application/json``. + :param args: other positional arguments passed to + :class:`~werkzeug.test.EnvironBuilder`. + :param kwargs: other keyword arguments passed to + :class:`~werkzeug.test.EnvironBuilder`. + """ + + def __init__( + self, + app: Flask, + path: str = "/", + base_url: str | None = None, + subdomain: str | None = None, + url_scheme: str | None = None, + *args: t.Any, + **kwargs: t.Any, + ) -> None: + assert not (base_url or subdomain or url_scheme) or ( + base_url is not None + ) != bool( + subdomain or url_scheme + ), 'Cannot pass "subdomain" or "url_scheme" with "base_url".' + + if base_url is None: + http_host = app.config.get("SERVER_NAME") or "localhost" + app_root = app.config["APPLICATION_ROOT"] + + if subdomain: + http_host = f"{subdomain}.{http_host}" + + if url_scheme is None: + url_scheme = app.config["PREFERRED_URL_SCHEME"] + + url = urlsplit(path) + base_url = ( + f"{url.scheme or url_scheme}://{url.netloc or http_host}" + f"/{app_root.lstrip('/')}" + ) + path = url.path + + if url.query: + path = f"{path}?{url.query}" + + self.app = app + super().__init__(path, base_url, *args, **kwargs) + + def json_dumps(self, obj: t.Any, **kwargs: t.Any) -> str: # type: ignore + """Serialize ``obj`` to a JSON-formatted string. + + The serialization will be configured according to the config associated + with this EnvironBuilder's ``app``. + """ + return self.app.json.dumps(obj, **kwargs) + + +_werkzeug_version = "" + + +def _get_werkzeug_version() -> str: + global _werkzeug_version + + if not _werkzeug_version: + _werkzeug_version = importlib.metadata.version("werkzeug") + + return _werkzeug_version + + +class FlaskClient(Client): + """Works like a regular Werkzeug test client but has knowledge about + Flask's contexts to defer the cleanup of the request context until + the end of a ``with`` block. For general information about how to + use this class refer to :class:`werkzeug.test.Client`. + + .. versionchanged:: 0.12 + `app.test_client()` includes preset default environment, which can be + set after instantiation of the `app.test_client()` object in + `client.environ_base`. + + Basic usage is outlined in the :doc:`/testing` chapter. + """ + + application: Flask + + def __init__(self, *args: t.Any, **kwargs: t.Any) -> None: + super().__init__(*args, **kwargs) + self.preserve_context = False + self._new_contexts: list[t.ContextManager[t.Any]] = [] + self._context_stack = ExitStack() + self.environ_base = { + "REMOTE_ADDR": "127.0.0.1", + "HTTP_USER_AGENT": f"Werkzeug/{_get_werkzeug_version()}", + } + + @contextmanager + def session_transaction( + self, *args: t.Any, **kwargs: t.Any + ) -> t.Iterator[SessionMixin]: + """When used in combination with a ``with`` statement this opens a + session transaction. This can be used to modify the session that + the test client uses. Once the ``with`` block is left the session is + stored back. + + :: + + with client.session_transaction() as session: + session['value'] = 42 + + Internally this is implemented by going through a temporary test + request context and since session handling could depend on + request variables this function accepts the same arguments as + :meth:`~flask.Flask.test_request_context` which are directly + passed through. + """ + if self._cookies is None: + raise TypeError( + "Cookies are disabled. Create a client with 'use_cookies=True'." + ) + + app = self.application + ctx = app.test_request_context(*args, **kwargs) + self._add_cookies_to_wsgi(ctx.request.environ) + + with ctx: + sess = app.session_interface.open_session(app, ctx.request) + + if sess is None: + raise RuntimeError("Session backend did not open a session.") + + yield sess + resp = app.response_class() + + if app.session_interface.is_null_session(sess): + return + + with ctx: + app.session_interface.save_session(app, sess, resp) + + self._update_cookies_from_response( + ctx.request.host.partition(":")[0], + ctx.request.path, + resp.headers.getlist("Set-Cookie"), + ) + + def _copy_environ(self, other: WSGIEnvironment) -> WSGIEnvironment: + out = {**self.environ_base, **other} + + if self.preserve_context: + out["werkzeug.debug.preserve_context"] = self._new_contexts.append + + return out + + def _request_from_builder_args( + self, args: tuple[t.Any, ...], kwargs: dict[str, t.Any] + ) -> BaseRequest: + kwargs["environ_base"] = self._copy_environ(kwargs.get("environ_base", {})) + builder = EnvironBuilder(self.application, *args, **kwargs) + + try: + return builder.get_request() + finally: + builder.close() + + def open( + self, + *args: t.Any, + buffered: bool = False, + follow_redirects: bool = False, + **kwargs: t.Any, + ) -> TestResponse: + if args and isinstance( + args[0], (werkzeug.test.EnvironBuilder, dict, BaseRequest) + ): + if isinstance(args[0], werkzeug.test.EnvironBuilder): + builder = copy(args[0]) + builder.environ_base = self._copy_environ(builder.environ_base or {}) # type: ignore[arg-type] + request = builder.get_request() + elif isinstance(args[0], dict): + request = EnvironBuilder.from_environ( + args[0], app=self.application, environ_base=self._copy_environ({}) + ).get_request() + else: + # isinstance(args[0], BaseRequest) + request = copy(args[0]) + request.environ = self._copy_environ(request.environ) + else: + # request is None + request = self._request_from_builder_args(args, kwargs) + + # Pop any previously preserved contexts. This prevents contexts + # from being preserved across redirects or multiple requests + # within a single block. + self._context_stack.close() + + response = super().open( + request, + buffered=buffered, + follow_redirects=follow_redirects, + ) + response.json_module = self.application.json # type: ignore[assignment] + + # Re-push contexts that were preserved during the request. + while self._new_contexts: + cm = self._new_contexts.pop() + self._context_stack.enter_context(cm) + + return response + + def __enter__(self) -> FlaskClient: + if self.preserve_context: + raise RuntimeError("Cannot nest client invocations") + self.preserve_context = True + return self + + def __exit__( + self, + exc_type: type | None, + exc_value: BaseException | None, + tb: TracebackType | None, + ) -> None: + self.preserve_context = False + self._context_stack.close() + + +class FlaskCliRunner(CliRunner): + """A :class:`~click.testing.CliRunner` for testing a Flask app's + CLI commands. Typically created using + :meth:`~flask.Flask.test_cli_runner`. See :ref:`testing-cli`. + """ + + def __init__(self, app: Flask, **kwargs: t.Any) -> None: + self.app = app + super().__init__(**kwargs) + + def invoke( # type: ignore + self, cli: t.Any = None, args: t.Any = None, **kwargs: t.Any + ) -> t.Any: + """Invokes a CLI command in an isolated environment. See + :meth:`CliRunner.invoke ` for + full method documentation. See :ref:`testing-cli` for examples. + + If the ``obj`` argument is not given, passes an instance of + :class:`~flask.cli.ScriptInfo` that knows how to load the Flask + app being tested. + + :param cli: Command object to invoke. Default is the app's + :attr:`~flask.app.Flask.cli` group. + :param args: List of strings to invoke the command with. + + :return: a :class:`~click.testing.Result` object. + """ + if cli is None: + cli = self.app.cli + + if "obj" not in kwargs: + kwargs["obj"] = ScriptInfo(create_app=lambda: self.app) + + return super().invoke(cli, args, **kwargs) diff --git a/psets/9/finance/env/lib/python3.12/site-packages/flask/typing.py b/psets/9/finance/env/lib/python3.12/site-packages/flask/typing.py new file mode 100644 index 0000000..e7234e9 --- /dev/null +++ b/psets/9/finance/env/lib/python3.12/site-packages/flask/typing.py @@ -0,0 +1,90 @@ +from __future__ import annotations + +import typing as t + +if t.TYPE_CHECKING: # pragma: no cover + from _typeshed.wsgi import WSGIApplication # noqa: F401 + from werkzeug.datastructures import Headers # noqa: F401 + from werkzeug.sansio.response import Response # noqa: F401 + +# The possible types that are directly convertible or are a Response object. +ResponseValue = t.Union[ + "Response", + str, + bytes, + list[t.Any], + # Only dict is actually accepted, but Mapping allows for TypedDict. + t.Mapping[str, t.Any], + t.Iterator[str], + t.Iterator[bytes], +] + +# the possible types for an individual HTTP header +# This should be a Union, but mypy doesn't pass unless it's a TypeVar. +HeaderValue = t.Union[str, list[str], tuple[str, ...]] + +# the possible types for HTTP headers +HeadersValue = t.Union[ + "Headers", + t.Mapping[str, HeaderValue], + t.Sequence[tuple[str, HeaderValue]], +] + +# The possible types returned by a route function. +ResponseReturnValue = t.Union[ + ResponseValue, + tuple[ResponseValue, HeadersValue], + tuple[ResponseValue, int], + tuple[ResponseValue, int, HeadersValue], + "WSGIApplication", +] + +# Allow any subclass of werkzeug.Response, such as the one from Flask, +# as a callback argument. Using werkzeug.Response directly makes a +# callback annotated with flask.Response fail type checking. +ResponseClass = t.TypeVar("ResponseClass", bound="Response") + +AppOrBlueprintKey = t.Optional[str] # The App key is None, whereas blueprints are named +AfterRequestCallable = t.Union[ + t.Callable[[ResponseClass], ResponseClass], + t.Callable[[ResponseClass], t.Awaitable[ResponseClass]], +] +BeforeFirstRequestCallable = t.Union[ + t.Callable[[], None], t.Callable[[], t.Awaitable[None]] +] +BeforeRequestCallable = t.Union[ + t.Callable[[], t.Optional[ResponseReturnValue]], + t.Callable[[], t.Awaitable[t.Optional[ResponseReturnValue]]], +] +ShellContextProcessorCallable = t.Callable[[], dict[str, t.Any]] +TeardownCallable = t.Union[ + t.Callable[[t.Optional[BaseException]], None], + t.Callable[[t.Optional[BaseException]], t.Awaitable[None]], +] +TemplateContextProcessorCallable = t.Union[ + t.Callable[[], dict[str, t.Any]], + t.Callable[[], t.Awaitable[dict[str, t.Any]]], +] +TemplateFilterCallable = t.Callable[..., t.Any] +TemplateGlobalCallable = t.Callable[..., t.Any] +TemplateTestCallable = t.Callable[..., bool] +URLDefaultCallable = t.Callable[[str, dict[str, t.Any]], None] +URLValuePreprocessorCallable = t.Callable[ + [t.Optional[str], t.Optional[dict[str, t.Any]]], None +] + +# This should take Exception, but that either breaks typing the argument +# with a specific exception, or decorating multiple times with different +# exceptions (and using a union type on the argument). +# https://github.com/pallets/flask/issues/4095 +# https://github.com/pallets/flask/issues/4295 +# https://github.com/pallets/flask/issues/4297 +ErrorHandlerCallable = t.Union[ + t.Callable[[t.Any], ResponseReturnValue], + t.Callable[[t.Any], t.Awaitable[ResponseReturnValue]], +] + +RouteCallable = t.Union[ + t.Callable[..., ResponseReturnValue], + t.Callable[..., t.Awaitable[ResponseReturnValue]], +] diff --git a/psets/9/finance/env/lib/python3.12/site-packages/flask/views.py b/psets/9/finance/env/lib/python3.12/site-packages/flask/views.py new file mode 100644 index 0000000..53fe976 --- /dev/null +++ b/psets/9/finance/env/lib/python3.12/site-packages/flask/views.py @@ -0,0 +1,191 @@ +from __future__ import annotations + +import typing as t + +from . import typing as ft +from .globals import current_app +from .globals import request + +F = t.TypeVar("F", bound=t.Callable[..., t.Any]) + +http_method_funcs = frozenset( + ["get", "post", "head", "options", "delete", "put", "trace", "patch"] +) + + +class View: + """Subclass this class and override :meth:`dispatch_request` to + create a generic class-based view. Call :meth:`as_view` to create a + view function that creates an instance of the class with the given + arguments and calls its ``dispatch_request`` method with any URL + variables. + + See :doc:`views` for a detailed guide. + + .. code-block:: python + + class Hello(View): + init_every_request = False + + def dispatch_request(self, name): + return f"Hello, {name}!" + + app.add_url_rule( + "/hello/", view_func=Hello.as_view("hello") + ) + + Set :attr:`methods` on the class to change what methods the view + accepts. + + Set :attr:`decorators` on the class to apply a list of decorators to + the generated view function. Decorators applied to the class itself + will not be applied to the generated view function! + + Set :attr:`init_every_request` to ``False`` for efficiency, unless + you need to store request-global data on ``self``. + """ + + #: The methods this view is registered for. Uses the same default + #: (``["GET", "HEAD", "OPTIONS"]``) as ``route`` and + #: ``add_url_rule`` by default. + methods: t.ClassVar[t.Collection[str] | None] = None + + #: Control whether the ``OPTIONS`` method is handled automatically. + #: Uses the same default (``True``) as ``route`` and + #: ``add_url_rule`` by default. + provide_automatic_options: t.ClassVar[bool | None] = None + + #: A list of decorators to apply, in order, to the generated view + #: function. Remember that ``@decorator`` syntax is applied bottom + #: to top, so the first decorator in the list would be the bottom + #: decorator. + #: + #: .. versionadded:: 0.8 + decorators: t.ClassVar[list[t.Callable[..., t.Any]]] = [] + + #: Create a new instance of this view class for every request by + #: default. If a view subclass sets this to ``False``, the same + #: instance is used for every request. + #: + #: A single instance is more efficient, especially if complex setup + #: is done during init. However, storing data on ``self`` is no + #: longer safe across requests, and :data:`~flask.g` should be used + #: instead. + #: + #: .. versionadded:: 2.2 + init_every_request: t.ClassVar[bool] = True + + def dispatch_request(self) -> ft.ResponseReturnValue: + """The actual view function behavior. Subclasses must override + this and return a valid response. Any variables from the URL + rule are passed as keyword arguments. + """ + raise NotImplementedError() + + @classmethod + def as_view( + cls, name: str, *class_args: t.Any, **class_kwargs: t.Any + ) -> ft.RouteCallable: + """Convert the class into a view function that can be registered + for a route. + + By default, the generated view will create a new instance of the + view class for every request and call its + :meth:`dispatch_request` method. If the view class sets + :attr:`init_every_request` to ``False``, the same instance will + be used for every request. + + Except for ``name``, all other arguments passed to this method + are forwarded to the view class ``__init__`` method. + + .. versionchanged:: 2.2 + Added the ``init_every_request`` class attribute. + """ + if cls.init_every_request: + + def view(**kwargs: t.Any) -> ft.ResponseReturnValue: + self = view.view_class( # type: ignore[attr-defined] + *class_args, **class_kwargs + ) + return current_app.ensure_sync(self.dispatch_request)(**kwargs) # type: ignore[no-any-return] + + else: + self = cls(*class_args, **class_kwargs) # pyright: ignore + + def view(**kwargs: t.Any) -> ft.ResponseReturnValue: + return current_app.ensure_sync(self.dispatch_request)(**kwargs) # type: ignore[no-any-return] + + if cls.decorators: + view.__name__ = name + view.__module__ = cls.__module__ + for decorator in cls.decorators: + view = decorator(view) + + # We attach the view class to the view function for two reasons: + # first of all it allows us to easily figure out what class-based + # view this thing came from, secondly it's also used for instantiating + # the view class so you can actually replace it with something else + # for testing purposes and debugging. + view.view_class = cls # type: ignore + view.__name__ = name + view.__doc__ = cls.__doc__ + view.__module__ = cls.__module__ + view.methods = cls.methods # type: ignore + view.provide_automatic_options = cls.provide_automatic_options # type: ignore + return view + + +class MethodView(View): + """Dispatches request methods to the corresponding instance methods. + For example, if you implement a ``get`` method, it will be used to + handle ``GET`` requests. + + This can be useful for defining a REST API. + + :attr:`methods` is automatically set based on the methods defined on + the class. + + See :doc:`views` for a detailed guide. + + .. code-block:: python + + class CounterAPI(MethodView): + def get(self): + return str(session.get("counter", 0)) + + def post(self): + session["counter"] = session.get("counter", 0) + 1 + return redirect(url_for("counter")) + + app.add_url_rule( + "/counter", view_func=CounterAPI.as_view("counter") + ) + """ + + def __init_subclass__(cls, **kwargs: t.Any) -> None: + super().__init_subclass__(**kwargs) + + if "methods" not in cls.__dict__: + methods = set() + + for base in cls.__bases__: + if getattr(base, "methods", None): + methods.update(base.methods) # type: ignore[attr-defined] + + for key in http_method_funcs: + if hasattr(cls, key): + methods.add(key.upper()) + + if methods: + cls.methods = methods + + def dispatch_request(self, **kwargs: t.Any) -> ft.ResponseReturnValue: + meth = getattr(self, request.method.lower(), None) + + # If the request method is HEAD and we don't have a handler for it + # retry with GET. + if meth is None and request.method == "HEAD": + meth = getattr(self, "get", None) + + assert meth is not None, f"Unimplemented method {request.method!r}" + return current_app.ensure_sync(meth)(**kwargs) # type: ignore[no-any-return] diff --git a/psets/9/finance/env/lib/python3.12/site-packages/flask/wrappers.py b/psets/9/finance/env/lib/python3.12/site-packages/flask/wrappers.py new file mode 100644 index 0000000..bab6102 --- /dev/null +++ b/psets/9/finance/env/lib/python3.12/site-packages/flask/wrappers.py @@ -0,0 +1,257 @@ +from __future__ import annotations + +import typing as t + +from werkzeug.exceptions import BadRequest +from werkzeug.exceptions import HTTPException +from werkzeug.wrappers import Request as RequestBase +from werkzeug.wrappers import Response as ResponseBase + +from . import json +from .globals import current_app +from .helpers import _split_blueprint_path + +if t.TYPE_CHECKING: # pragma: no cover + from werkzeug.routing import Rule + + +class Request(RequestBase): + """The request object used by default in Flask. Remembers the + matched endpoint and view arguments. + + It is what ends up as :class:`~flask.request`. If you want to replace + the request object used you can subclass this and set + :attr:`~flask.Flask.request_class` to your subclass. + + The request object is a :class:`~werkzeug.wrappers.Request` subclass and + provides all of the attributes Werkzeug defines plus a few Flask + specific ones. + """ + + json_module: t.Any = json + + #: The internal URL rule that matched the request. This can be + #: useful to inspect which methods are allowed for the URL from + #: a before/after handler (``request.url_rule.methods``) etc. + #: Though if the request's method was invalid for the URL rule, + #: the valid list is available in ``routing_exception.valid_methods`` + #: instead (an attribute of the Werkzeug exception + #: :exc:`~werkzeug.exceptions.MethodNotAllowed`) + #: because the request was never internally bound. + #: + #: .. versionadded:: 0.6 + url_rule: Rule | None = None + + #: A dict of view arguments that matched the request. If an exception + #: happened when matching, this will be ``None``. + view_args: dict[str, t.Any] | None = None + + #: If matching the URL failed, this is the exception that will be + #: raised / was raised as part of the request handling. This is + #: usually a :exc:`~werkzeug.exceptions.NotFound` exception or + #: something similar. + routing_exception: HTTPException | None = None + + _max_content_length: int | None = None + _max_form_memory_size: int | None = None + _max_form_parts: int | None = None + + @property + def max_content_length(self) -> int | None: + """The maximum number of bytes that will be read during this request. If + this limit is exceeded, a 413 :exc:`~werkzeug.exceptions.RequestEntityTooLarge` + error is raised. If it is set to ``None``, no limit is enforced at the + Flask application level. However, if it is ``None`` and the request has + no ``Content-Length`` header and the WSGI server does not indicate that + it terminates the stream, then no data is read to avoid an infinite + stream. + + Each request defaults to the :data:`MAX_CONTENT_LENGTH` config, which + defaults to ``None``. It can be set on a specific ``request`` to apply + the limit to that specific view. This should be set appropriately based + on an application's or view's specific needs. + + .. versionchanged:: 3.1 + This can be set per-request. + + .. versionchanged:: 0.6 + This is configurable through Flask config. + """ + if self._max_content_length is not None: + return self._max_content_length + + if not current_app: + return super().max_content_length + + return current_app.config["MAX_CONTENT_LENGTH"] # type: ignore[no-any-return] + + @max_content_length.setter + def max_content_length(self, value: int | None) -> None: + self._max_content_length = value + + @property + def max_form_memory_size(self) -> int | None: + """The maximum size in bytes any non-file form field may be in a + ``multipart/form-data`` body. If this limit is exceeded, a 413 + :exc:`~werkzeug.exceptions.RequestEntityTooLarge` error is raised. If it + is set to ``None``, no limit is enforced at the Flask application level. + + Each request defaults to the :data:`MAX_FORM_MEMORY_SIZE` config, which + defaults to ``500_000``. It can be set on a specific ``request`` to + apply the limit to that specific view. This should be set appropriately + based on an application's or view's specific needs. + + .. versionchanged:: 3.1 + This is configurable through Flask config. + """ + if self._max_form_memory_size is not None: + return self._max_form_memory_size + + if not current_app: + return super().max_form_memory_size + + return current_app.config["MAX_FORM_MEMORY_SIZE"] # type: ignore[no-any-return] + + @max_form_memory_size.setter + def max_form_memory_size(self, value: int | None) -> None: + self._max_form_memory_size = value + + @property # type: ignore[override] + def max_form_parts(self) -> int | None: + """The maximum number of fields that may be present in a + ``multipart/form-data`` body. If this limit is exceeded, a 413 + :exc:`~werkzeug.exceptions.RequestEntityTooLarge` error is raised. If it + is set to ``None``, no limit is enforced at the Flask application level. + + Each request defaults to the :data:`MAX_FORM_PARTS` config, which + defaults to ``1_000``. It can be set on a specific ``request`` to apply + the limit to that specific view. This should be set appropriately based + on an application's or view's specific needs. + + .. versionchanged:: 3.1 + This is configurable through Flask config. + """ + if self._max_form_parts is not None: + return self._max_form_parts + + if not current_app: + return super().max_form_parts + + return current_app.config["MAX_FORM_PARTS"] # type: ignore[no-any-return] + + @max_form_parts.setter + def max_form_parts(self, value: int | None) -> None: + self._max_form_parts = value + + @property + def endpoint(self) -> str | None: + """The endpoint that matched the request URL. + + This will be ``None`` if matching failed or has not been + performed yet. + + This in combination with :attr:`view_args` can be used to + reconstruct the same URL or a modified URL. + """ + if self.url_rule is not None: + return self.url_rule.endpoint # type: ignore[no-any-return] + + return None + + @property + def blueprint(self) -> str | None: + """The registered name of the current blueprint. + + This will be ``None`` if the endpoint is not part of a + blueprint, or if URL matching failed or has not been performed + yet. + + This does not necessarily match the name the blueprint was + created with. It may have been nested, or registered with a + different name. + """ + endpoint = self.endpoint + + if endpoint is not None and "." in endpoint: + return endpoint.rpartition(".")[0] + + return None + + @property + def blueprints(self) -> list[str]: + """The registered names of the current blueprint upwards through + parent blueprints. + + This will be an empty list if there is no current blueprint, or + if URL matching failed. + + .. versionadded:: 2.0.1 + """ + name = self.blueprint + + if name is None: + return [] + + return _split_blueprint_path(name) + + def _load_form_data(self) -> None: + super()._load_form_data() + + # In debug mode we're replacing the files multidict with an ad-hoc + # subclass that raises a different error for key errors. + if ( + current_app + and current_app.debug + and self.mimetype != "multipart/form-data" + and not self.files + ): + from .debughelpers import attach_enctype_error_multidict + + attach_enctype_error_multidict(self) + + def on_json_loading_failed(self, e: ValueError | None) -> t.Any: + try: + return super().on_json_loading_failed(e) + except BadRequest as ebr: + if current_app and current_app.debug: + raise + + raise BadRequest() from ebr + + +class Response(ResponseBase): + """The response object that is used by default in Flask. Works like the + response object from Werkzeug but is set to have an HTML mimetype by + default. Quite often you don't have to create this object yourself because + :meth:`~flask.Flask.make_response` will take care of that for you. + + If you want to replace the response object used you can subclass this and + set :attr:`~flask.Flask.response_class` to your subclass. + + .. versionchanged:: 1.0 + JSON support is added to the response, like the request. This is useful + when testing to get the test client response data as JSON. + + .. versionchanged:: 1.0 + + Added :attr:`max_cookie_size`. + """ + + default_mimetype: str | None = "text/html" + + json_module = json + + autocorrect_location_header = False + + @property + def max_cookie_size(self) -> int: # type: ignore + """Read-only view of the :data:`MAX_COOKIE_SIZE` config key. + + See :attr:`~werkzeug.wrappers.Response.max_cookie_size` in + Werkzeug's docs. + """ + if current_app: + return current_app.config["MAX_COOKIE_SIZE"] # type: ignore[no-any-return] + + # return Werkzeug's default when not in an app context + return super().max_cookie_size diff --git a/psets/9/finance/env/lib/python3.12/site-packages/flask_session-0.8.0.dist-info/INSTALLER b/psets/9/finance/env/lib/python3.12/site-packages/flask_session-0.8.0.dist-info/INSTALLER new file mode 100644 index 0000000..a1b589e --- /dev/null +++ b/psets/9/finance/env/lib/python3.12/site-packages/flask_session-0.8.0.dist-info/INSTALLER @@ -0,0 +1 @@ +pip diff --git a/psets/9/finance/env/lib/python3.12/site-packages/flask_session-0.8.0.dist-info/LICENSE.rst b/psets/9/finance/env/lib/python3.12/site-packages/flask_session-0.8.0.dist-info/LICENSE.rst new file mode 100644 index 0000000..6a65079 --- /dev/null +++ b/psets/9/finance/env/lib/python3.12/site-packages/flask_session-0.8.0.dist-info/LICENSE.rst @@ -0,0 +1,28 @@ +Copyright 2014 Pallets Community Ecosystem + +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/psets/9/finance/env/lib/python3.12/site-packages/flask_session-0.8.0.dist-info/METADATA b/psets/9/finance/env/lib/python3.12/site-packages/flask_session-0.8.0.dist-info/METADATA new file mode 100644 index 0000000..584bb2a --- /dev/null +++ b/psets/9/finance/env/lib/python3.12/site-packages/flask_session-0.8.0.dist-info/METADATA @@ -0,0 +1,149 @@ +Metadata-Version: 2.1 +Name: Flask-Session +Version: 0.8.0 +Summary: Server-side session support for Flask +Author-email: Shipeng Feng +Maintainer-email: Pallets Community Ecosystem +Requires-Python: >=3.8 +Description-Content-Type: text/x-rst +Classifier: Development Status :: 4 - Beta +Classifier: Environment :: Web Environment +Classifier: Framework :: Flask +Classifier: Intended Audience :: Developers +Classifier: License :: OSI Approved :: BSD License +Classifier: Operating System :: OS Independent +Classifier: Programming Language :: Python +Classifier: Topic :: Internet :: WWW/HTTP :: Session +Classifier: Topic :: Internet :: WWW/HTTP :: WSGI +Classifier: Topic :: Internet :: WWW/HTTP :: WSGI :: Application +Classifier: Topic :: Software Development :: Libraries :: Application Frameworks +Requires-Dist: flask>=2.2 +Requires-Dist: msgspec>=0.18.6 +Requires-Dist: cachelib +Requires-Dist: Flask-Session[cachelib, memcached, mongodb, redis, sqlalchemy] ; extra == "all" +Requires-Dist: cachelib>=0.10.2 ; extra == "cachelib" +Requires-Dist: pymemcache ; extra == "memcached" +Requires-Dist: pymongo>=4.6.2 ; extra == "mongodb" +Requires-Dist: redis>=5.0.3 ; extra == "redis" +Requires-Dist: flask-sqlalchemy>=3.0.5 ; extra == "sqlalchemy" +Project-URL: Changes, https://flask-session.readthedocs.io/changes.html +Project-URL: Chat, https://discord.gg/pallets +Project-URL: Documentation, https://flask-session.readthedocs.io +Project-URL: Issue Tracker, https://github.com/pallets-eco/flask-session/issues/ +Project-URL: Source Code, https://github.com/pallets-eco/flask-session/ +Provides-Extra: all +Provides-Extra: cachelib +Provides-Extra: memcached +Provides-Extra: mongodb +Provides-Extra: redis +Provides-Extra: sqlalchemy + +.. image:: https://raw.githubusercontent.com/pallets-eco/flask-session/main/docs/_static/icon/favicon-192x192.png + :alt: Flask-Session + :target: https://flask-session.readthedocs.io + :align: left + :width: 60px + +============== +Flask-Session +============== + +Flask-Session is an extension for Flask that adds support for server-side sessions to +your application. + +.. image:: https://img.shields.io/github/actions/workflow/status/pallets-eco/flask-session/test.yaml?logo=github + :alt: GitHub Actions Workflow Status + :target: https://github.com/pallets-eco/flask-session/actions/workflows/test.yaml?query=workflow%3ACI+branch%3Adevelopment + +.. image:: https://img.shields.io/readthedocs/flask-session?logo=readthedocs + :target: https://flask-session.readthedocs.io + :alt: Documentation status + +.. image:: https://img.shields.io/github/license/pallets-eco/flask-session?logo=bsd + :target: ./LICENSE + :alt: BSD-3 Clause License + +.. image:: https://common-changelog.org/badge.svg + :target: https://common-changelog.org + :alt: Common Changelog + +.. image:: https://img.shields.io/endpoint?url=https://raw.githubusercontent.com/astral-sh/ruff/main/assets/badge/v2.json&label=style + :target: https://github.com/astral-sh/ruff + :alt: Code style: ruff + +.. image:: https://img.shields.io/pypi/v/flask-session.svg?logo=pypi + :target: https://pypi.org/project/flask-session + :alt: PyPI - Latest Version + +.. image:: https://img.shields.io/badge/dynamic/json?query=info.requires_python&label=python&logo=python&url=https%3A%2F%2Fpypi.org%2Fpypi%2Fflask-session%2Fjson + :target: https://pypi.org/project/Flask-Session/ + :alt: PyPI - Python Version + +.. image:: https://img.shields.io/discord/531221516914917387?logo=discord + :target: https://discord.gg/pallets + :alt: Discord + +.. image:: https://img.shields.io/pypi/dm/flask-session?logo=pypi + :target: https://pypistats.org/packages/flask-session + :alt: PyPI - Downloads + +Installing +------------ +Install and update using pip: + +.. code-block:: bash + + $ pip install flask-session + +A Simple Example +-------------------- + +.. code-block:: python + + from flask import Flask, session + from flask_session import Session + + app = Flask(__name__) + # Check Configuration section for more details + SESSION_TYPE = 'redis' + app.config.from_object(__name__) + Session(app) + + @app.route('/set/') + def set(): + session['key'] = 'value' + return 'ok' + + @app.route('/get/') + def get(): + return session.get('key', 'not set') + +Supported Storage Types +------------------------ +- Redis +- Memcached +- FileSystem +- MongoDB +- SQLALchemy + +Documentation +------------- +Learn more at the official `Flask-Session Documentation `_. + +Maintainers +------------ +- `Lxstr `_ +- Pallets Team + +Contribute +---------- +Thanks to all those who have contributed to Flask-Session. A full list can be found at `CONTRIBUTORS.md `_. + +If you want to contribute, please check the `CONTRIBUTING.rst `_. + +Donate +-------- +The Pallets organization develops and supports Flask-Session 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. + + + diff --git a/psets/9/finance/env/lib/python3.12/site-packages/flask_session-0.8.0.dist-info/RECORD b/psets/9/finance/env/lib/python3.12/site-packages/flask_session-0.8.0.dist-info/RECORD new file mode 100644 index 0000000..c97e29e --- /dev/null +++ b/psets/9/finance/env/lib/python3.12/site-packages/flask_session-0.8.0.dist-info/RECORD @@ -0,0 +1,42 @@ +flask_session-0.8.0.dist-info/INSTALLER,sha256=zuuue4knoyJ-UwPPXg8fezS7VCrXJQrAP7zeNuwvFQg,4 +flask_session-0.8.0.dist-info/LICENSE.rst,sha256=avK7glmtsxOGN0YcECHYPdjG2EMHdV_HnTtZP0uD4RE,1495 +flask_session-0.8.0.dist-info/METADATA,sha256=ob_zkGN25WgO2VXBuniNU9teghosnahxTxvvIZ7X0vU,5247 +flask_session-0.8.0.dist-info/RECORD,, +flask_session-0.8.0.dist-info/REQUESTED,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0 +flask_session-0.8.0.dist-info/WHEEL,sha256=EZbGkh7Ie4PoZfRQ8I0ZuP9VklN_TvcZ6DSE5Uar4z4,81 +flask_session/__init__.py,sha256=Mf3_KlBP1yt5Se9c3bq2EeXANWc0LR7zAePXxVb64pM,6681 +flask_session/__pycache__/__init__.cpython-312.pyc,, +flask_session/__pycache__/_utils.cpython-312.pyc,, +flask_session/__pycache__/base.cpython-312.pyc,, +flask_session/__pycache__/defaults.cpython-312.pyc,, +flask_session/_utils.py,sha256=5jpvy0Cuna9xIC6-AaQqu1dFbARfST0J22MMWPVQq1Q,2442 +flask_session/base.py,sha256=YuPNCTItdebEvNckQOifXkEThuDCIP9caFMUG9Aok5I,14485 +flask_session/cachelib/__init__.py,sha256=E6CnWBd75b9ahM3Z24CHFjsuKYkFPOJRj5S35TVth2g,78 +flask_session/cachelib/__pycache__/__init__.cpython-312.pyc,, +flask_session/cachelib/__pycache__/cachelib.cpython-312.pyc,, +flask_session/cachelib/cachelib.py,sha256=pcxEtCbIEfOGoORA5TuVDbCOf5mMYVYCF4_eue_m1Ao,2618 +flask_session/defaults.py,sha256=gu6PVax8tPLLF0bbrKP3tJjIv_-E_kYCp947_Vib0C0,1143 +flask_session/dynamodb/__init__.py,sha256=TSISrW_hj8ZoNM65o1-HNHuRzhg60_JWwdxhh6XTUx8,78 +flask_session/dynamodb/__pycache__/__init__.cpython-312.pyc,, +flask_session/dynamodb/__pycache__/dynamodb.cpython-312.pyc,, +flask_session/dynamodb/dynamodb.py,sha256=PWLcbj_rhcO4RL-7z8GjVWKzqIMHikGwJpZXqkRR6wo,4493 +flask_session/filesystem/__init__.py,sha256=uCpk886zujAjyCalsMGiIPoLmJWmyUG9Yh_3tZMN0Xo,84 +flask_session/filesystem/__pycache__/__init__.cpython-312.pyc,, +flask_session/filesystem/__pycache__/filesystem.cpython-312.pyc,, +flask_session/filesystem/filesystem.py,sha256=kyc08CGEPjPUQsDk-snO2ZB8EohJtgtaqOvsSvqrcj4,4160 +flask_session/memcached/__init__.py,sha256=Q2vonBvc1hi1YFEqbmuoL7TjQGaA7LgtfzNQYChMlDo,81 +flask_session/memcached/__pycache__/__init__.cpython-312.pyc,, +flask_session/memcached/__pycache__/memcached.cpython-312.pyc,, +flask_session/memcached/memcached.py,sha256=clH4RcP_CgCerK_zkFAYZuQCZOmw6VQZBnayuUOQCXg,4404 +flask_session/mongodb/__init__.py,sha256=JN2pJpBYxle1XOzBfcfSsYl-kztKTjRS3IS9NBsUr0I,75 +flask_session/mongodb/__pycache__/__init__.cpython-312.pyc,, +flask_session/mongodb/__pycache__/mongodb.cpython-312.pyc,, +flask_session/mongodb/mongodb.py,sha256=oC9YdJ9d5WBLxQcz94pK2-ypz0K7xUqaQecZDCU7d0A,4259 +flask_session/redis/__init__.py,sha256=0NhQKAt1xSdVVbyWzgBzkGxq562qvsanPhJ9p0byaxo,69 +flask_session/redis/__pycache__/__init__.cpython-312.pyc,, +flask_session/redis/__pycache__/redis.cpython-312.pyc,, +flask_session/redis/redis.py,sha256=RYJdf3fJxiXOcA_a8HeqklB-m2wEzIkx-z_ad-6RmH8,2949 +flask_session/sqlalchemy/__init__.py,sha256=g_yQzvis4K9UL_cTQ5KraivKVLT_5Ky6IvCHyE38pG8,84 +flask_session/sqlalchemy/__pycache__/__init__.cpython-312.pyc,, +flask_session/sqlalchemy/__pycache__/sqlalchemy.cpython-312.pyc,, +flask_session/sqlalchemy/sqlalchemy.py,sha256=FZ7M77mbLTRDNq2uTHcnbLHgDU3AKdu_-I2tbAZXXYw,6957 diff --git a/psets/9/finance/env/lib/python3.12/site-packages/flask_session-0.8.0.dist-info/REQUESTED b/psets/9/finance/env/lib/python3.12/site-packages/flask_session-0.8.0.dist-info/REQUESTED new file mode 100644 index 0000000..e69de29 diff --git a/psets/9/finance/env/lib/python3.12/site-packages/flask_session-0.8.0.dist-info/WHEEL b/psets/9/finance/env/lib/python3.12/site-packages/flask_session-0.8.0.dist-info/WHEEL new file mode 100644 index 0000000..3b5e64b --- /dev/null +++ b/psets/9/finance/env/lib/python3.12/site-packages/flask_session-0.8.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/psets/9/finance/env/lib/python3.12/site-packages/flask_session/__init__.py b/psets/9/finance/env/lib/python3.12/site-packages/flask_session/__init__.py new file mode 100644 index 0000000..b95a0b0 --- /dev/null +++ b/psets/9/finance/env/lib/python3.12/site-packages/flask_session/__init__.py @@ -0,0 +1,186 @@ +from .defaults import Defaults + +__version__ = "0.8.0" + + +class Session: + """This class is used to add Server-side Session to one or more Flask + applications. + + :param app: A Flask app instance. + + For a typical setup use the following initialization:: + + app = Flask(__name__) + Session(app) + + .. note:: + + You can not use ``Session`` instance directly, what ``Session`` does + is just change the :attr:`~flask.Flask.session_interface` attribute on + your Flask applications. You should always use :class:`flask.session`. + """ + + def __init__(self, app=None): + self.app = app + if app is not None: + self.init_app(app) + + def init_app(self, app): + """This the the alternate setup method, typically used in an application factory pattern:: + + sess = Session() + + def create_app(): + app = Flask(__name__) + sess.init_app(app) + return app + + :param app: the Flask app object with proper configuration. + """ + app.session_interface = self._get_interface(app) + + def _get_interface(self, app): + config = app.config + + # Flask-session specific settings + SESSION_TYPE = config.get("SESSION_TYPE", Defaults.SESSION_TYPE) + + SESSION_PERMANENT = config.get("SESSION_PERMANENT", Defaults.SESSION_PERMANENT) + SESSION_USE_SIGNER = config.get( + "SESSION_USE_SIGNER", Defaults.SESSION_USE_SIGNER + ) # TODO: remove in 1.0 + SESSION_KEY_PREFIX = config.get( + "SESSION_KEY_PREFIX", Defaults.SESSION_KEY_PREFIX + ) + SESSION_ID_LENGTH = config.get("SESSION_ID_LENGTH", Defaults.SESSION_ID_LENGTH) + SESSION_SERIALIZATION_FORMAT = config.get( + "SESSION_SERIALIZATION_FORMAT", Defaults.SESSION_SERIALIZATION_FORMAT + ) + + # Redis settings + SESSION_REDIS = config.get("SESSION_REDIS", Defaults.SESSION_REDIS) + + # Memcached settings + SESSION_MEMCACHED = config.get("SESSION_MEMCACHED", Defaults.SESSION_MEMCACHED) + + # CacheLib settings + SESSION_CACHELIB = config.get("SESSION_CACHELIB", Defaults.SESSION_CACHELIB) + + # Filesystem settings + # TODO: remove in 1.0 + SESSION_FILE_DIR = config.get("SESSION_FILE_DIR", Defaults.SESSION_FILE_DIR) + SESSION_FILE_THRESHOLD = config.get( + "SESSION_FILE_THRESHOLD", Defaults.SESSION_FILE_THRESHOLD + ) + SESSION_FILE_MODE = config.get("SESSION_FILE_MODE", Defaults.SESSION_FILE_MODE) + + # MongoDB settings + SESSION_MONGODB = config.get("SESSION_MONGODB", Defaults.SESSION_MONGODB) + SESSION_MONGODB_DB = config.get( + "SESSION_MONGODB_DB", Defaults.SESSION_MONGODB_DB + ) + SESSION_MONGODB_COLLECT = config.get( + "SESSION_MONGODB_COLLECT", Defaults.SESSION_MONGODB_COLLECT + ) + + # SQLAlchemy settings + SESSION_SQLALCHEMY = config.get( + "SESSION_SQLALCHEMY", Defaults.SESSION_SQLALCHEMY + ) + SESSION_SQLALCHEMY_TABLE = config.get( + "SESSION_SQLALCHEMY_TABLE", Defaults.SESSION_SQLALCHEMY_TABLE + ) + SESSION_SQLALCHEMY_SEQUENCE = config.get( + "SESSION_SQLALCHEMY_SEQUENCE", Defaults.SESSION_SQLALCHEMY_SEQUENCE + ) + SESSION_SQLALCHEMY_SCHEMA = config.get( + "SESSION_SQLALCHEMY_SCHEMA", Defaults.SESSION_SQLALCHEMY_SCHEMA + ) + SESSION_SQLALCHEMY_BIND_KEY = config.get( + "SESSION_SQLALCHEMY_BIND_KEY", Defaults.SESSION_SQLALCHEMY_BIND_KEY + ) + SESSION_CLEANUP_N_REQUESTS = config.get( + "SESSION_CLEANUP_N_REQUESTS", Defaults.SESSION_CLEANUP_N_REQUESTS + ) + + # DynamoDB settings + SESSION_DYNAMODB = config.get("SESSION_DYNAMODB", Defaults.SESSION_DYNAMODB) + SESSION_DYNAMODB_TABLE = config.get( + "SESSION_DYNAMODB_TABLE", Defaults.SESSION_DYNAMODB_TABLE + ) + + common_params = { + "app": app, + "key_prefix": SESSION_KEY_PREFIX, + "use_signer": SESSION_USE_SIGNER, + "permanent": SESSION_PERMANENT, + "sid_length": SESSION_ID_LENGTH, + "serialization_format": SESSION_SERIALIZATION_FORMAT, + } + + SESSION_TYPE = SESSION_TYPE.lower() + + if SESSION_TYPE == "redis": + from .redis import RedisSessionInterface + + session_interface = RedisSessionInterface( + **common_params, + client=SESSION_REDIS, + ) + elif SESSION_TYPE == "memcached": + from .memcached import MemcachedSessionInterface + + session_interface = MemcachedSessionInterface( + **common_params, + client=SESSION_MEMCACHED, + ) + elif SESSION_TYPE == "filesystem": + from .filesystem import FileSystemSessionInterface + + session_interface = FileSystemSessionInterface( + **common_params, + cache_dir=SESSION_FILE_DIR, + threshold=SESSION_FILE_THRESHOLD, + mode=SESSION_FILE_MODE, + ) + elif SESSION_TYPE == "cachelib": + from .cachelib import CacheLibSessionInterface + + session_interface = CacheLibSessionInterface( + **common_params, client=SESSION_CACHELIB + ) + elif SESSION_TYPE == "mongodb": + from .mongodb import MongoDBSessionInterface + + session_interface = MongoDBSessionInterface( + **common_params, + client=SESSION_MONGODB, + db=SESSION_MONGODB_DB, + collection=SESSION_MONGODB_COLLECT, + ) + elif SESSION_TYPE == "sqlalchemy": + from .sqlalchemy import SqlAlchemySessionInterface + + session_interface = SqlAlchemySessionInterface( + **common_params, + client=SESSION_SQLALCHEMY, + table=SESSION_SQLALCHEMY_TABLE, + sequence=SESSION_SQLALCHEMY_SEQUENCE, + schema=SESSION_SQLALCHEMY_SCHEMA, + bind_key=SESSION_SQLALCHEMY_BIND_KEY, + cleanup_n_requests=SESSION_CLEANUP_N_REQUESTS, + ) + elif SESSION_TYPE == "dynamodb": + from .dynamodb import DynamoDBSessionInterface + + session_interface = DynamoDBSessionInterface( + **common_params, + client=SESSION_DYNAMODB, + table_name=SESSION_DYNAMODB_TABLE, + ) + + else: + raise ValueError(f"Unrecognized value for SESSION_TYPE: {SESSION_TYPE}") + + return session_interface diff --git a/psets/9/finance/env/lib/python3.12/site-packages/flask_session/__pycache__/__init__.cpython-312.pyc b/psets/9/finance/env/lib/python3.12/site-packages/flask_session/__pycache__/__init__.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..cd8fc34cdeb0d23500fe0a730e77a86f74c032e6 GIT binary patch literal 6293 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 Bai{ Callable[..., Any]: + """Decorator to retry a query when an OperationalError is raised. + + Args: + max_attempts: Maximum number of attempts. Defaults to 3. + delay: Delay between attempts in seconds. Defaults to 0.3. + backoff: Backoff factor. Defaults to 2. + """ + + def decorator(func: Callable[..., Any]) -> Callable[..., Any]: + @wraps(func) + def wrapper(*args: Any, **kwargs: Any) -> Any: + for attempt in range(max_attempts): + try: + return func(*args, **kwargs) + # TODO: use proper exception type + except Exception as e: + if attempt == max_attempts - 1: + raise e + + sleep_time = delay * backoff**attempt + current_app.logger.exception( + f"Exception when querying database ({e})." + f"Retrying ({attempt + 1}/{max_attempts}) in {sleep_time:.2f}s." + ) + time.sleep(sleep_time) + + return wrapper + + return decorator diff --git a/psets/9/finance/env/lib/python3.12/site-packages/flask_session/base.py b/psets/9/finance/env/lib/python3.12/site-packages/flask_session/base.py new file mode 100644 index 0000000..04c6473 --- /dev/null +++ b/psets/9/finance/env/lib/python3.12/site-packages/flask_session/base.py @@ -0,0 +1,385 @@ +import secrets +import warnings +from abc import ABC, abstractmethod +from contextlib import suppress + +try: + import cPickle as pickle +except ImportError: + import pickle + +import random +from datetime import timedelta as TimeDelta +from typing import Any, Dict, Optional + +import msgspec +from flask import Flask, Request, Response +from flask.sessions import SessionInterface as FlaskSessionInterface +from flask.sessions import SessionMixin +from itsdangerous import BadSignature, Signer, want_bytes +from werkzeug.datastructures import CallbackDict + +from ._utils import retry_query +from .defaults import Defaults + + +class ServerSideSession(CallbackDict, SessionMixin): + """Baseclass for server-side based sessions. This can be accessed through ``flask.session``. + + .. attribute:: sid + + Session id, internally we use :func:`secrets.token_urlsafe` to generate one + session id. + + .. attribute:: modified + + When data is changed, this is set to ``True``. Only the session dictionary + itself is tracked; if the session contains mutable data (for example a nested + dict) then this must be set to ``True`` manually when modifying that data. The + session cookie will only be written to the response if this is ``True``. + + .. attribute:: accessed + + When data is read (or attempted read) or written, this is set to ``True``. Used by + :class:`.ServerSideSessionInterface` to add a ``Vary: Cookie`` + header, which allows caching proxies to cache different pages for + different users. + + Default is ``False``. + + .. attribute:: permanent + + This sets and reflects the ``'_permanent'`` key in the dict. + + Default is ``False``. + + """ + + def __bool__(self) -> bool: + return bool(dict(self)) and self.keys() != {"_permanent"} + + def __init__( + self, + initial: Optional[Dict[str, Any]] = None, + sid: Optional[str] = None, + permanent: Optional[bool] = None, + ): + def on_update(self) -> None: + self.modified = True + self.accessed = True + + CallbackDict.__init__(self, initial, on_update) + self.sid = sid + if permanent: + self.permanent = permanent + self.modified = False + self.accessed = False + + def __getitem__(self, key: str) -> Any: + self.accessed = True + return super().__getitem__(key) + + def get(self, key: str, default: Any = None) -> Any: + self.accessed = True + return super().get(key, default) + + def setdefault(self, key: str, default: Any = None) -> Any: + self.accessed = True + return super().setdefault(key, default) + + def clear(self) -> None: + """Clear the session except for the '_permanent' key.""" + permanent = self.get("_permanent", False) + super().clear() + self["_permanent"] = permanent + + +class Serializer(ABC): + """Baseclass for session serialization.""" + + @abstractmethod + def decode(self, serialized_data: bytes) -> dict: + """Deserialize the session data.""" + raise NotImplementedError() + + @abstractmethod + def encode(self, session: ServerSideSession) -> bytes: + """Serialize the session data.""" + raise NotImplementedError() + + +class MsgSpecSerializer(Serializer): + def __init__(self, app: Flask, format: str): + self.app: Flask = app + self.encoder: msgspec.msgpack.Encoder or msgspec.json.Encoder + self.decoder: msgspec.msgpack.Decoder or msgspec.json.Decoder + self.alternate_decoder: msgspec.msgpack.Decoder or msgspec.json.Decoder + + if format == "msgpack": + self.encoder = msgspec.msgpack.Encoder() + self.decoder = msgspec.msgpack.Decoder() + self.alternate_decoder = msgspec.json.Decoder() + elif format == "json": + self.encoder = msgspec.json.Encoder() + self.decoder = msgspec.json.Decoder() + self.alternate_decoder = msgspec.msgpack.Decoder() + else: + raise ValueError(f"Unsupported serialization format: {format}") + + def encode(self, session: ServerSideSession) -> bytes: + """Serialize the session data.""" + try: + return self.encoder.encode(dict(session)) + except Exception as e: + self.app.logger.error(f"Failed to serialize session data: {e}") + raise + + def decode(self, serialized_data: bytes) -> dict: + """Deserialize the session data.""" + # TODO: Remove the pickle fallback in 1.0.0 + with suppress(msgspec.DecodeError): + return self.decoder.decode(serialized_data) + with suppress(msgspec.DecodeError): + return self.alternate_decoder.decode(serialized_data) + with suppress(pickle.UnpicklingError): + return pickle.loads(serialized_data) + # If all decoders fail, raise the final exception + self.app.logger.error("Failed to deserialize session data", exc_info=True) + raise pickle.UnpicklingError("Failed to deserialize session data") + + +class ServerSideSessionInterface(FlaskSessionInterface, ABC): + """Used to open a :class:`flask.sessions.ServerSideSessionInterface` instance.""" + + session_class = ServerSideSession + serializer = None + ttl = True + + def __init__( + self, + app: Flask, + key_prefix: str = Defaults.SESSION_KEY_PREFIX, + use_signer: bool = Defaults.SESSION_USE_SIGNER, + permanent: bool = Defaults.SESSION_PERMANENT, + sid_length: int = Defaults.SESSION_ID_LENGTH, + serialization_format: str = Defaults.SESSION_SERIALIZATION_FORMAT, + cleanup_n_requests: Optional[int] = Defaults.SESSION_CLEANUP_N_REQUESTS, + ): + self.app = app + self.key_prefix = key_prefix + self.use_signer = use_signer + if use_signer: + warnings.warn( + "The 'use_signer' option is deprecated and will be removed in the next minor release. " + "Please update your configuration accordingly or open an issue.", + DeprecationWarning, + stacklevel=1, + ) + self.permanent = permanent + self.sid_length = sid_length + self.has_same_site_capability = hasattr(self, "get_cookie_samesite") + self.cleanup_n_requests = cleanup_n_requests + + # Cleanup settings for non-TTL databases only + if getattr(self, "ttl", None) is False: + if self.cleanup_n_requests: + self.app.before_request(self._cleanup_n_requests) + else: + self._register_cleanup_app_command() + + # Set the serialization format + self.serializer = MsgSpecSerializer(format=serialization_format, app=app) + + # INTERNAL METHODS + + def _generate_sid(self, session_id_length: int) -> str: + """Generate a random session id.""" + return secrets.token_urlsafe(session_id_length) + + # TODO: Remove in 1.0.0 + def _get_signer(self, app: Flask) -> Signer: + if not hasattr(app, "secret_key") or not app.secret_key: + raise KeyError("SECRET_KEY must be set when SESSION_USE_SIGNER=True") + return Signer(app.secret_key, salt="flask-session", key_derivation="hmac") + + # TODO: Remove in 1.0.0 + def _unsign(self, app, sid: str) -> str: + signer = self._get_signer(app) + sid_as_bytes = signer.unsign(sid) + sid = sid_as_bytes.decode() + return sid + + # TODO: Remove in 1.0.0 + def _sign(self, app, sid: str) -> str: + signer = self._get_signer(app) + sid_as_bytes = want_bytes(sid) + return signer.sign(sid_as_bytes).decode("utf-8") + + def _get_store_id(self, sid: str) -> str: + return self.key_prefix + sid + + def should_set_storage(self, app: Flask, session: ServerSideSession) -> bool: + """Used by session backends to determine if session in storage + should be set for this session cookie for this response. If the session + has been modified, the session is set to storage. If + the ``SESSION_REFRESH_EACH_REQUEST`` config is true, the session is + always set to storage. In the second case, this means refreshing the + storage expiry even if the session has not been modified. + + .. versionadded:: 0.7.0 + """ + + return session.modified or app.config["SESSION_REFRESH_EACH_REQUEST"] + + # CLEANUP METHODS FOR NON TTL DATABASES + + def _register_cleanup_app_command(self): + """ + Register a custom Flask CLI command for cleaning up expired sessions. + + Run the command with `flask session_cleanup`. Run with a cron job + or scheduler such as Heroku Scheduler to automatically clean up expired sessions. + """ + + @self.app.cli.command("session_cleanup") + def session_cleanup(): + with self.app.app_context(): + self._delete_expired_sessions() + + def _cleanup_n_requests(self) -> None: + """ + Delete expired sessions on average every N requests. + + This is less desirable than using the scheduled app command cleanup as it may + slow down some requests but may be useful for rapid development. + """ + if self.cleanup_n_requests and random.randint(0, self.cleanup_n_requests) == 0: + self._delete_expired_sessions() + + # SECURITY API METHODS + + def regenerate(self, session: ServerSideSession) -> None: + """Regenerate the session id for the given session. Can be used by calling ``flask.session_interface.regenerate()``.""" + if session: + # Remove the old session from storage + self._delete_session(self._get_store_id(session.sid)) + # Generate a new session ID + new_sid = self._generate_sid(self.sid_length) + session.sid = new_sid + # Mark the session as modified to ensure it gets saved + session.modified = True + + # METHODS OVERRIDE FLASK SESSION INTERFACE + + def save_session( + self, app: Flask, session: ServerSideSession, response: Response + ) -> None: + + # Get the domain and path for the cookie from the app + domain = self.get_cookie_domain(app) + path = self.get_cookie_path(app) + name = self.get_cookie_name(app) + + # Generate a prefixed session id + store_id = self._get_store_id(session.sid) + + # Add a "Vary: Cookie" header if the session was accessed at all. + # This assumes the app is checking the session values in a request that + # behaves differently based on those values. ie. session.get("is_authenticated") + if session.accessed: + response.vary.add("Cookie") + + # If the session is empty, do not save it to the database or set a cookie + if not session: + # If the session was deleted (empty and modified), delete the saved session from the database and tell the client to delete the cookie + if session.modified: + self._delete_session(store_id) + response.delete_cookie(key=name, domain=domain, path=path) + response.vary.add("Cookie") + return + + if not self.should_set_storage(app, session): + return + + # Update existing or create new session in the database + self._upsert_session(app.permanent_session_lifetime, session, store_id) + + if not self.should_set_cookie(app, session): + return + + # Get the additional required cookie settings + value = self._sign(app, session.sid) if self.use_signer else session.sid + expires = self.get_expiration_time(app, session) + httponly = self.get_cookie_httponly(app) + secure = self.get_cookie_secure(app) + samesite = ( + self.get_cookie_samesite(app) if self.has_same_site_capability else None + ) + + # Set the browser cookie + response.set_cookie( + key=name, + value=value, + expires=expires, + httponly=httponly, + domain=domain, + path=path, + secure=secure, + samesite=samesite, + ) + response.vary.add("Cookie") + + def open_session(self, app: Flask, request: Request) -> ServerSideSession: + # Get the session ID from the cookie + sid = request.cookies.get(app.config["SESSION_COOKIE_NAME"]) + + # If there's no session ID, generate a new one + if not sid: + sid = self._generate_sid(self.sid_length) + return self.session_class(sid=sid, permanent=self.permanent) + # If the session ID is signed, unsign it + if self.use_signer: + try: + sid = self._unsign(app, sid) + except BadSignature: + sid = self._generate_sid(self.sid_length) + return self.session_class(sid=sid, permanent=self.permanent) + + # Retrieve the session data from the database + store_id = self._get_store_id(sid) + saved_session_data = self._retrieve_session_data(store_id) + + # If the saved session exists, load the session data from the document + if saved_session_data is not None: + return self.session_class(saved_session_data, sid=sid) + + # If the saved session does not exist, create a new session + sid = self._generate_sid(self.sid_length) + return self.session_class(sid=sid, permanent=self.permanent) + + # METHODS TO BE IMPLEMENTED BY SUBCLASSES + + @abstractmethod + @retry_query() # use only when retry not supported directly by the client + def _retrieve_session_data(self, store_id: str) -> Optional[dict]: + """Get the saved session from the session storage.""" + raise NotImplementedError() + + @abstractmethod + @retry_query() # use only when retry not supported directly by the client + def _delete_session(self, store_id: str) -> None: + """Delete session from the session storage.""" + raise NotImplementedError() + + @abstractmethod + @retry_query() # use only when retry not supported directly by the client + def _upsert_session( + self, session_lifetime: TimeDelta, session: ServerSideSession, store_id: str + ) -> None: + """Update existing or create new session in the session storage.""" + raise NotImplementedError() + + @retry_query() # use only when retry not supported directly by the client + def _delete_expired_sessions(self) -> None: + """Delete expired sessions from the session storage. Only required for non-TTL databases.""" + pass diff --git a/psets/9/finance/env/lib/python3.12/site-packages/flask_session/cachelib/__init__.py b/psets/9/finance/env/lib/python3.12/site-packages/flask_session/cachelib/__init__.py new file mode 100644 index 0000000..6073522 --- /dev/null +++ b/psets/9/finance/env/lib/python3.12/site-packages/flask_session/cachelib/__init__.py @@ -0,0 +1 @@ +from .cachelib import CacheLibSession, CacheLibSessionInterface # noqa: F401 diff --git a/psets/9/finance/env/lib/python3.12/site-packages/flask_session/cachelib/__pycache__/__init__.cpython-312.pyc b/psets/9/finance/env/lib/python3.12/site-packages/flask_session/cachelib/__pycache__/__init__.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..07b61b08d73ea46f8f4efd55b9deff5914047e08 GIT binary patch literal 292 zcmZ8cy-ve05Vjp83aDaX;1x2^<3|ighz_tIp)O2xv0UepnkJXXHb{|p51xT%VPVeF z0Two-ZcJPRUHFFY?z{hc9S*kzYS8v?@(L zC8tu=?Oqx?#~U}h#SmOg-TuG8HAVEfu{cSSZeaWB(#?Fr?S6ylMXZ>`_dQe;;mSlL zuyy9B02@vZp$QlRoI&o$kVQax1RelQ8|O8hjE;^WxQGXhu?tgRfV?zep~LSvuwDpS mJ91I$QPXyV^Qz7sO1$t}yt@A+>@a;LQp%+mzlpKmWc>r}Xj1?H literal 0 HcmV?d00001 diff --git a/psets/9/finance/env/lib/python3.12/site-packages/flask_session/cachelib/__pycache__/cachelib.cpython-312.pyc b/psets/9/finance/env/lib/python3.12/site-packages/flask_session/cachelib/__pycache__/cachelib.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..8acc17004b242b8c9aa76eac1a4c9f019fa3e959 GIT binary patch literal 3727 zcmbVP-ESMm5#J+^I z&d$!x&d%)2{&xANWKt#Yeck+IVH&u9V5j>*|4YRx^2{$u6wGk z*BsigkWc9PuNsCGjNB*NX!PHUxtc9<=M2H@T-l+fy^t%rr{BocT_)VzJGqK!8+MuH zn7x#<%=uh>SyUbSt*IZqnR89SPS%a`HDiIfxe9IsgziU~E93s4ewUf5FY_cU=o4gI zEQi~qB`bWOE8iD%8l?Db4?_6A-V-*JN?|6KA~aNr(lCoHW&*{%6r^bNzz5R710v{x zbohnRkrztGzAvrBsLWC{!qO}=3d1zY`e}>}Pz8Q*c8IF1zmi%b6^ZuUPL>8~0>+b| zJ%rj7nWk>brQtwI!_ZGd|1iz45!%m2dvb*ifP8F?+>lD+MUp+_jT}gRuau0x!lqq? zY-onPtWB38IqvkQ-DG^K%|qIlO*I1)v`*4AS2!GUIi;!^eA9J<8#S$Lnamc`+RT5k zV%o02Dw*0l@fus!>zq~08#p=OG*LB#X2PPBGO7uuyQT)(?!M^_m+7v#U^70geOzUt z%DAr&BCx`GPMcIKJI*zeX%5$HN9;3FXS`8?q2i`fgJI<3vY zngOpl72kse2F}63p*<7ei)m}~%YyBX#bw+yEOW&`DA6kpI0ZY37Wa*4!3c(lE<$f# zq|^{b5ZzqC3mf&i7Y&l*sk?jaskTWFF;J#Hm{*;wHb&Whi=Jw}6elOi6 z&CqIAbYX}rBHkVNs3hdBh=v}9yWlDj5$nli8hIFf(3yQR)C@I=-kT--s{?h{l_vQu z91TjE;ilY-G^5SfgJ@tyBFiKjE38-rM_YnTh4go@2KGKELnt<92_ToA&1?3_}NaR$+niHH$4V%S-M< zJaY$BKqD@yoViuUqS=_ITsOFl20R%#FLkA1eC|2%YV?flcB z@iqB3>eotgJ+`Hcv=W)mUf)=}mwi;)oVofu9Ez(xyn70Q3)4;NML81&0qk_+s~>6%w4jJAG=w*DT`iKo1tzlZ$_X3_F97Z z_$~I3B)K)g%LOLU{hs&NsP@UV5OE3G%+?Zn0Zvhn*he+HJ^cY&;u zohZ>xZl3(5Ul?mvLOl(~E-OaT`J4)h7%*mb9da9KfX$`#68a&>Pk@(@~MD856 z>;zAN8ICU~j*lZRrt8!x>$?B?@{-*Ee9-X1LRh>H)iT9=u{e9Vpr4&N`$7KV?9aV{ zuH?h~C;CTM^5NQg$r{ZcoSW% zV*bkP%*EN#%p9(E{xZy&Aj_!$%?J7`#DmIXK}@hnJPgo*b9K*Tf4k@VxhKY@IAn|vEmB1(IZ3>{s))KXKc zXWI%H9&4RA_4q`7>qNdacI5Hc>8-KTt?^eMkH5V&{qqE=k zAC9O`lLPGtw2-p?(T&NiOtu}vu0n=J+HvGmGBn!mLoPuEN7_l`QaGAME<+}dJV!(A zH$#!*_uMvt=FyEWJAY~X8Vmje_!+?651hek%2VD8{;8bdbI`?fxjzQd4oi~s zH Optional[dict]: + # Get the saved session (item) from the database + return self.cache.get(store_id) + + def _delete_session(self, store_id: str) -> None: + self.cache.delete(store_id) + + def _upsert_session( + self, session_lifetime: TimeDelta, session: ServerSideSession, store_id: str + ) -> None: + storage_time_to_live = total_seconds(session_lifetime) + + # Serialize the session data (or just cast into dictionary in this case) + session_data = dict(session) + + # Update existing or create new session in the database + self.cache.set( + key=store_id, + value=session_data, + timeout=storage_time_to_live, + ) diff --git a/psets/9/finance/env/lib/python3.12/site-packages/flask_session/defaults.py b/psets/9/finance/env/lib/python3.12/site-packages/flask_session/defaults.py new file mode 100644 index 0000000..7f890d6 --- /dev/null +++ b/psets/9/finance/env/lib/python3.12/site-packages/flask_session/defaults.py @@ -0,0 +1,45 @@ +import os + + +class Defaults: + # Flask-session specific settings + SESSION_TYPE = "null" + SESSION_KEY_PREFIX = "session:" + SESSION_USE_SIGNER = False + SESSION_PERMANENT = True + SESSION_ID_LENGTH = 32 + SESSION_SERIALIZATION_FORMAT = "msgpack" + + # Clean up settings for non TTL backends (SQL, PostgreSQL, etc.) + SESSION_CLEANUP_N_REQUESTS = None + + # Redis settings + SESSION_REDIS = None + + # Memcached settings + SESSION_MEMCACHED = None + + # CacheLib settings + SESSION_CACHELIB = None + + # Filesystem settings + # TODO: remove in 1.0 + SESSION_FILE_DIR = os.path.join(os.getcwd(), "flask_session") + SESSION_FILE_THRESHOLD = 500 + SESSION_FILE_MODE = 384 + + # MongoDB settings + SESSION_MONGODB = None + SESSION_MONGODB_DB = "flask_session" + SESSION_MONGODB_COLLECT = "sessions" + + # SQLAlchemy settings + SESSION_SQLALCHEMY = None + SESSION_SQLALCHEMY_TABLE = "sessions" + SESSION_SQLALCHEMY_SEQUENCE = None + SESSION_SQLALCHEMY_SCHEMA = None + SESSION_SQLALCHEMY_BIND_KEY = None + + # DynamoDB settings + SESSION_DYNAMODB = None + SESSION_DYNAMODB_TABLE = "Sessions" diff --git a/psets/9/finance/env/lib/python3.12/site-packages/flask_session/dynamodb/__init__.py b/psets/9/finance/env/lib/python3.12/site-packages/flask_session/dynamodb/__init__.py new file mode 100644 index 0000000..a63048f --- /dev/null +++ b/psets/9/finance/env/lib/python3.12/site-packages/flask_session/dynamodb/__init__.py @@ -0,0 +1 @@ +from .dynamodb import DynamoDBSession, DynamoDBSessionInterface # noqa: F401 diff --git a/psets/9/finance/env/lib/python3.12/site-packages/flask_session/dynamodb/__pycache__/__init__.cpython-312.pyc b/psets/9/finance/env/lib/python3.12/site-packages/flask_session/dynamodb/__pycache__/__init__.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..bb210aa9da069d9058bc98c9254dade40898ae78 GIT binary patch literal 292 zcmX@j%ge<81W#%r)BS+-V-N=hn4pZ$B0$D;h7^Vr#vF!R#wf;IrYI&xhDs()=9i2> zDNUwZ{4SMwiMjbMPQj_g#hLkewgsc z44;7{!>=s;+`JNfm&B6PJpJVSl+3(z{p4a(1O0;H)RJO-OZ~LWyu`fZRQ=SvGX0#) zB>jTQl8pR3V?9G7{o>4$RNaEalIYq n;;_lhPbtkwwJYKTS`G3^F*lI-z|6?Vc%Q-k0)u@KJCF|m6PZ&? literal 0 HcmV?d00001 diff --git a/psets/9/finance/env/lib/python3.12/site-packages/flask_session/dynamodb/__pycache__/dynamodb.cpython-312.pyc b/psets/9/finance/env/lib/python3.12/site-packages/flask_session/dynamodb/__pycache__/dynamodb.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..c3a5f6b4a8f1479a58573652b9e25dfe59a64ad6 GIT binary patch literal 5876 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 Optional[dict]: + # Get the saved session (document) from the database + document = self.store.get_item(Key={"id": store_id}).get("Item") + if document: + serialized_session_data = want_bytes(document.get("val").value) + return self.serializer.decode(serialized_session_data) + return None + + def _delete_session(self, store_id: str) -> None: + self.store.delete_item(Key={"id": store_id}) + + def _upsert_session( + self, session_lifetime: TimeDelta, session: ServerSideSession, store_id: str + ) -> None: + storage_expiration_datetime = datetime.utcnow() + session_lifetime + # Serialize the session data + serialized_session_data = self.serializer.encode(session) + + self.store.update_item( + Key={ + "id": store_id, + }, + UpdateExpression="SET val = :value, expiration = :exp", + ExpressionAttributeValues={ + ":value": serialized_session_data, + ":exp": Decimal(storage_expiration_datetime.timestamp()), + }, + ) diff --git a/psets/9/finance/env/lib/python3.12/site-packages/flask_session/filesystem/__init__.py b/psets/9/finance/env/lib/python3.12/site-packages/flask_session/filesystem/__init__.py new file mode 100644 index 0000000..2285f25 --- /dev/null +++ b/psets/9/finance/env/lib/python3.12/site-packages/flask_session/filesystem/__init__.py @@ -0,0 +1 @@ +from .filesystem import FileSystemSession, FileSystemSessionInterface # noqa: F401 diff --git a/psets/9/finance/env/lib/python3.12/site-packages/flask_session/filesystem/__pycache__/__init__.cpython-312.pyc b/psets/9/finance/env/lib/python3.12/site-packages/flask_session/filesystem/__pycache__/__init__.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..122f5fe618988c04453c40ba7237f463fc88a8d4 GIT binary patch literal 300 zcmZWkyG{c!5VY@*fS?peRQ$meWO;}J2~iOw8k*3M#xlOW!;0-Yc@5G@{0HB_x6n{u zLlGJ}q;ynlfK*H|`_k;}z6^&0!FYeXsjoTCm&FR%U$WTYC~cpqBAL~sI?4LTSE3=iP!Ewo*_Yr@g!;1I|r+-tR&=^6_av6B pEI}z7Y*K2}cKybwZ_0azXK|Cwmmkp<(`PQFd=ukWF^=n8e*@BJSAqZl literal 0 HcmV?d00001 diff --git a/psets/9/finance/env/lib/python3.12/site-packages/flask_session/filesystem/__pycache__/filesystem.cpython-312.pyc b/psets/9/finance/env/lib/python3.12/site-packages/flask_session/filesystem/__pycache__/filesystem.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..b9d9930c67a807c63e104f9e45f0ec76ef790c20 GIT binary patch literal 5217 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 Uj2q$)1tGlh)_czh0-W@J0HMrY5C8xG literal 0 HcmV?d00001 diff --git a/psets/9/finance/env/lib/python3.12/site-packages/flask_session/filesystem/filesystem.py b/psets/9/finance/env/lib/python3.12/site-packages/flask_session/filesystem/filesystem.py new file mode 100644 index 0000000..dd98b37 --- /dev/null +++ b/psets/9/finance/env/lib/python3.12/site-packages/flask_session/filesystem/filesystem.py @@ -0,0 +1,109 @@ +import warnings +from datetime import timedelta as TimeDelta +from typing import Optional + +from cachelib.file import FileSystemCache +from flask import Flask + +from .._utils import total_seconds +from ..base import ServerSideSession, ServerSideSessionInterface +from ..defaults import Defaults + + +class FileSystemSession(ServerSideSession): + pass + + +class FileSystemSessionInterface(ServerSideSessionInterface): + """Uses the :class:`cachelib.file.FileSystemCache` as a session storage. + + :param key_prefix: A prefix that is added to storage keys. + :param use_signer: Whether to sign the session id cookie or not. + :param permanent: Whether to use permanent session or not. + :param sid_length: The length of the generated session id in bytes. + :param serialization_format: The serialization format to use for the session data. + :param cache_dir: the directory where session files are stored. + :param threshold: the maximum number of items the session stores before it + :param mode: the file mode wanted for the session files, default 0600 + + .. versionadded:: 0.7 + The `serialization_format` and `app` parameters were added. + + .. versionadded:: 0.6 + The `sid_length` parameter was added. + + .. versionadded:: 0.2 + The `use_signer` parameter was added. + """ + + session_class = FileSystemSession + ttl = True + + def __init__( + self, + app: Flask, + key_prefix: str = Defaults.SESSION_KEY_PREFIX, + use_signer: bool = Defaults.SESSION_USE_SIGNER, + permanent: bool = Defaults.SESSION_PERMANENT, + sid_length: int = Defaults.SESSION_ID_LENGTH, + serialization_format: str = Defaults.SESSION_SERIALIZATION_FORMAT, + cache_dir: str = Defaults.SESSION_FILE_DIR, + threshold: int = Defaults.SESSION_FILE_THRESHOLD, + mode: int = Defaults.SESSION_FILE_MODE, + ): + + # Deprecation warnings + if cache_dir != Defaults.SESSION_FILE_DIR: + warnings.warn( + "'SESSION_FILE_DIR' is deprecated and will be removed in a future release. Instead pass FileSystemCache(directory, threshold, mode) instance as SESSION_CACHELIB.", + DeprecationWarning, + stacklevel=1, + ) + if threshold != Defaults.SESSION_FILE_THRESHOLD: + warnings.warn( + "'SESSION_FILE_THRESHOLD' is deprecated and will be removed in a future release. Instead pass FileSystemCache(directory, threshold, mode) instance as SESSION_CLIENT.", + DeprecationWarning, + stacklevel=1, + ) + if mode != Defaults.SESSION_FILE_MODE: + warnings.warn( + "'SESSION_FILE_MODE' is deprecated and will be removed in a future release. Instead pass FileSystemCache(directory, threshold, mode) instance as SESSION_CLIENT.", + DeprecationWarning, + stacklevel=1, + ) + + warnings.warn( + "FileSystemSessionInterface is deprecated and will be removed in a future release. Instead use the CacheLib backend directly.", + DeprecationWarning, + stacklevel=1, + ) + + self.cache = FileSystemCache( + cache_dir=cache_dir, threshold=threshold, mode=mode + ) + + super().__init__( + app, key_prefix, use_signer, permanent, sid_length, serialization_format + ) + + def _retrieve_session_data(self, store_id: str) -> Optional[dict]: + # Get the saved session (item) from the database + return self.cache.get(store_id) + + def _delete_session(self, store_id: str) -> None: + self.cache.delete(store_id) + + def _upsert_session( + self, session_lifetime: TimeDelta, session: ServerSideSession, store_id: str + ) -> None: + storage_time_to_live = total_seconds(session_lifetime) + + # Serialize the session data (or just cast into dictionary in this case) + session_data = dict(session) + + # Update existing or create new session in the database + self.cache.set( + key=store_id, + value=session_data, + timeout=storage_time_to_live, + ) diff --git a/psets/9/finance/env/lib/python3.12/site-packages/flask_session/memcached/__init__.py b/psets/9/finance/env/lib/python3.12/site-packages/flask_session/memcached/__init__.py new file mode 100644 index 0000000..4a65c92 --- /dev/null +++ b/psets/9/finance/env/lib/python3.12/site-packages/flask_session/memcached/__init__.py @@ -0,0 +1 @@ +from .memcached import MemcachedSession, MemcachedSessionInterface # noqa: F401 diff --git a/psets/9/finance/env/lib/python3.12/site-packages/flask_session/memcached/__pycache__/__init__.cpython-312.pyc b/psets/9/finance/env/lib/python3.12/site-packages/flask_session/memcached/__pycache__/__init__.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..cde96804b14989a3b35e419323cc07aa96b59e71 GIT binary patch literal 296 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 Optional[Any]: ... + def set(self, key: str, value: Any, timeout: int) -> bool: ... + def delete(self, key: str) -> bool: ... + + +class MemcachedSession(ServerSideSession): + pass + + +class MemcachedSessionInterface(ServerSideSessionInterface): + """A Session interface that uses memcached as session storage. (`pylibmc`, `libmc`, `python-memcached` or `pymemcache` required) + + :param client: A ``memcache.Client`` instance. + :param key_prefix: A prefix that is added to all storage keys. + :param use_signer: Whether to sign the session id cookie or not. + :param permanent: Whether to use permanent session or not. + :param sid_length: The length of the generated session id in bytes. + :param serialization_format: The serialization format to use for the session data. + + .. versionadded:: 0.7 + The `serialization_format` and `app` parameters were added. + + .. versionadded:: 0.6 + The `sid_length` parameter was added. + + .. versionadded:: 0.2 + The `use_signer` parameter was added. + """ + + serializer = ServerSideSessionInterface.serializer + session_class = MemcachedSession + ttl = True + + def __init__( + self, + app: Flask, + client: Optional[MemcacheClientProtocol] = Defaults.SESSION_MEMCACHED, + key_prefix: str = Defaults.SESSION_KEY_PREFIX, + use_signer: bool = Defaults.SESSION_USE_SIGNER, + permanent: bool = Defaults.SESSION_PERMANENT, + sid_length: int = Defaults.SESSION_ID_LENGTH, + serialization_format: str = Defaults.SESSION_SERIALIZATION_FORMAT, + ): + if client is None or not all( + hasattr(client, method) for method in ["get", "set", "delete"] + ): + warnings.warn( + "No valid memcache.Client instance provided, attempting to create a new instance on localhost with default settings.", + RuntimeWarning, + stacklevel=1, + ) + client = self._get_preferred_memcache_client() + self.client = client + super().__init__( + app, key_prefix, use_signer, permanent, sid_length, serialization_format + ) + + def _get_preferred_memcache_client(self): + clients = [ + ("pylibmc", ["127.0.0.1:11211"]), + ("memcache", ["127.0.0.1:11211"]), # python-memcached + ("pymemcache.client.base", "127.0.0.1:11211"), + ("libmc", ["localhost:11211"]), + ] + + for module_name, server in clients: + try: + module = __import__(module_name) + ClientClass = module.Client + return ClientClass(server) + except ImportError: + continue + + raise ImportError("No memcache module found") + + def _get_memcache_timeout(self, timeout: int) -> int: + """ + Memcached deals with long (> 30 days) timeouts in a special + way. Call this function to obtain a safe value for your timeout. + """ + if timeout > 2592000: # 60*60*24*30, 30 days + # Switch to absolute timestamps. + timeout += int(time.time()) + return timeout + + def _retrieve_session_data(self, store_id: str) -> Optional[dict]: + # Get the saved session (item) from the database + serialized_session_data = self.client.get(store_id) + if serialized_session_data: + return self.serializer.decode(serialized_session_data) + return None + + def _delete_session(self, store_id: str) -> None: + self.client.delete(store_id) + + def _upsert_session( + self, session_lifetime: TimeDelta, session: ServerSideSession, store_id: str + ) -> None: + storage_time_to_live = total_seconds(session_lifetime) + + # Serialize the session data + serialized_session_data = self.serializer.encode(session) + + # Update existing or create new session in the database + self.client.set( + store_id, + serialized_session_data, + self._get_memcache_timeout(storage_time_to_live), + ) diff --git a/psets/9/finance/env/lib/python3.12/site-packages/flask_session/mongodb/__init__.py b/psets/9/finance/env/lib/python3.12/site-packages/flask_session/mongodb/__init__.py new file mode 100644 index 0000000..f9aa01d --- /dev/null +++ b/psets/9/finance/env/lib/python3.12/site-packages/flask_session/mongodb/__init__.py @@ -0,0 +1 @@ +from .mongodb import MongoDBSession, MongoDBSessionInterface # noqa: F401 diff --git a/psets/9/finance/env/lib/python3.12/site-packages/flask_session/mongodb/__pycache__/__init__.cpython-312.pyc b/psets/9/finance/env/lib/python3.12/site-packages/flask_session/mongodb/__pycache__/__init__.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..0547a3810bc47d50e77d5f3d8100053447b8e55f GIT binary patch literal 288 zcmX@j%ge<81W#%r)4hT8V-N=hn4pZ$B0$D;h7^Vr#vF!R#wf;IrYI&xhDs()=9i2> zDNUwZe7^a4>G>{B!KuZ?nfZCQ#8LU4c_pbuX^F|Hewxg;*mFT@Q<939fqIKrfW%6M z&p?vlSEhb$UWvX-Vo7SAesX?FW?s5}a$P>2Kl0x8%TU$W@Kc%&tP+b!KR2E$Oiz3*-@VW literal 0 HcmV?d00001 diff --git a/psets/9/finance/env/lib/python3.12/site-packages/flask_session/mongodb/__pycache__/mongodb.cpython-312.pyc b/psets/9/finance/env/lib/python3.12/site-packages/flask_session/mongodb/__pycache__/mongodb.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..b249117a338c035b93f16d16decc4cbbf3cab8d8 GIT binary patch literal 5292 zcmaJFZEO_Bb@o2@&UfeYosEr+?ZtrMlHf}S5aP6e0Ygo|q}WxGtE%<-W^Aw7+r7-L z0b57qN=P+Qt0esp{Ag98Rtgc3N~HeC&;0KnUrFTa7F49Bs`z&ipho@G_jYgZe9k2! z-OPJ$X5PG+_qq4icsxp=eOY>Y{*OsQ{)LFwf;HgDZ2)c(N~oZb9F9IsC9BXwZH(5;7FNf zDL8SVXsL#-XaEOKYl?XZfan!Px8&Jni^M4E3f^KC`!S(fQ-k_>J zpUs@$S$OWk{ z7h>T>u)wVisHv?qLV$`VZD~N=wuJ;JPw4@GvlR76-KTFa8>tLzvFinFj zO+&1chT$i&E*b$m3cog%o=dHfIf2Hm$8+0g9B2vH)s4I60<`^lAlKtkX%g@bz_-&B z>!oSdSEq}#6X-kE$WEz3pD=G3dW)rDM{necoCam8RiL z7nY1UM}m0psG>Ks{t}2?kqF_jp=L`@EBtni&Gm<-l*F+HkYq}|f zI;Dv%opqVu#H<24+>K3Z@`k3dJf7>WZQ%9Qj^ai}q*?@Y)H6CNy*ToUGlSNEqRuqQ zTD!%Jr07(dQHsSG$*~v)5z&;cFwR^(kGSU4iv8g&?CX!ciIsE(%+`_UI~W~kX4J5p zZ(-!z$o7NKcE~kwJKC^VJKA7iN9uNBM;q2)ceZ*9+ec^ZXybwNPP(lH6A?yCY)>vi zSp2PUlazcvOIluf0L;R~_oxT+8_^Q^DVYDOd`X!gp&j3uKvOB9kk|q#<1fH>1*~ z2vv_y5QU7(kj?1}l44n`0Of%`k3Nv+44ha}B%NJptTuE>GxCbIV3?M4MYR?r>gIQF zSqrzCBaiX^SXDp(%wN*jWv1D}2uJNb4nSu|+0~*75dxeKmZcnwjm?3FOtHM7Q!|sW zqpImeP>$NP#VZQek-r^4$WB~b(y_34(uBrPhxA zsrSz5zr6nW&f^bao$sE%alYy!9VdJbk^_~#9nZpnc;ac4Y}@(kpRApJv~9;);1_L` zuD)9*-p}2Rmb;z@Jo;eIzK^^A-2YMkJ@bC%wNJ;&nWOjj9Q$l%dC$qUz~|ynHAEuu zccV9=8{%MD9K0R-tYcjq{9HWwr5L{vE{i>tSo?duw{my3-#fd0eEON+7l}H>jx9RR zF00fIab_)XJzsZPxB}|jaq-^(01i$TVcgml>#o_Dp+ZSe1#_p$2tjA7N+S86YCtGXpS8&R=X^#)U+i%u6ti`ri53DYZeX~|E zNPWv*eE2Qxn|m|9Nqz)Yfi|)*xXJ@7EEt!W9fhwRNW7@VjIW_B6D9Q&(GGFJSyU?m zSN1wlvXus!7ft~a^Hu0pNu{lQqixUM+V)gp$#>7*IJ*(+FUR_CS-0O>9~k)}mVM-r zca~#2Zy&tVvp#g-i`dJq^CW8r%bGgpe6rc$8YPb=9bNBTT~A7ndWR}~2P#9~|0*2lNL8bxqw86_7*A9?NxZ`~ zW3<=$^3LAMz;I>oaAkN5cJyzn`a`fSf!os2c*3#f%mBv^SdJwU$B$M!EXxoZW!d>s zw&R|$J2}$!Tb9PrZtV7{@u{ha3zPEs3zKIqoH}8rJi_baZ_96796vqrR)hAVsd0H~ z;>_guMfgLaw(*Vei|5BC$0w&7q={4Vx$(&}(?76xc&nzyFHVe|o5+n#<6);Sz@F&_ z-`e3aoZs#3@MtG5oI5vua+;%BImR`&F7cZdw*#|=q4E7l#QbgtsG7IG% zdcG1(teynLWnS9Ycf7psc%^q}qxVp`_fVy8*GAvra^GQxaMi7dUuI<$}gkq$# zry55nfwS!hCCT7WwF99Pi6^URggRmN88WXP7ec|#J7$%@aPR78flq$=1i@-D5IlIt zUnMZy3p~N08XE{EDpIEE$MN8}JN|Im86QRB{{ Optional[dict]: + # Get the saved session (document) from the database + document = self.store.find_one({"id": store_id}) + if document: + serialized_session_data = want_bytes(document["val"]) + return self.serializer.decode(serialized_session_data) + return None + + def _delete_session(self, store_id: str) -> None: + if self.use_deprecated_method: + self.store.remove({"id": store_id}) + else: + self.store.delete_one({"id": store_id}) + + def _upsert_session( + self, session_lifetime: TimeDelta, session: ServerSideSession, store_id: str + ) -> None: + storage_expiration_datetime = datetime.utcnow() + session_lifetime + + # Serialize the session data + serialized_session_data = self.serializer.encode(session) + + # Update existing or create new session in the database + if self.use_deprecated_method: + self.store.update( + {"id": store_id}, + { + "id": store_id, + "val": serialized_session_data, + "expiration": storage_expiration_datetime, + }, + True, + ) + else: + self.store.update_one( + {"id": store_id}, + { + "$set": { + "id": store_id, + "val": serialized_session_data, + "expiration": storage_expiration_datetime, + } + }, + True, + ) diff --git a/psets/9/finance/env/lib/python3.12/site-packages/flask_session/redis/__init__.py b/psets/9/finance/env/lib/python3.12/site-packages/flask_session/redis/__init__.py new file mode 100644 index 0000000..65b6323 --- /dev/null +++ b/psets/9/finance/env/lib/python3.12/site-packages/flask_session/redis/__init__.py @@ -0,0 +1 @@ +from .redis import RedisSession, RedisSessionInterface # noqa: F401 diff --git a/psets/9/finance/env/lib/python3.12/site-packages/flask_session/redis/__pycache__/__init__.cpython-312.pyc b/psets/9/finance/env/lib/python3.12/site-packages/flask_session/redis/__pycache__/__init__.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..c2bc887b4e9e736d180966689f9d4a8a2eeac047 GIT binary patch literal 280 zcmYjLyH3O~5VRc-&+FhLQgF*doP>m^prE+|Dz34Ny$RMOPUJO6k@ye3fp4LqPD23= z9ny7FYpPB#eczIL)(uISzL*l9AO literal 0 HcmV?d00001 diff --git a/psets/9/finance/env/lib/python3.12/site-packages/flask_session/redis/__pycache__/redis.cpython-312.pyc b/psets/9/finance/env/lib/python3.12/site-packages/flask_session/redis/__pycache__/redis.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..da2ef4459ce54744ae59bedf18d85528902d7a27 GIT binary patch literal 4115 zcmbVPU2Gf25#A&3$Rouc{aU|`&+<>q+7g|_b`!O6tW>n4CYDoCfg8S@&b*~`^6`$@ zTiKS&6e{4NHjuyxio$*kP#_NM2N&o=AN$@H32rO)YNH0)0QDOK*=W$G&g}6=a^wc+ z0=GLmJ3Bi&^X=^3ACt*Af%4Dl`wPG5Amks|X%?kHY<>d7O=1#LvPl8kkS&!%g|LKl z*p|ymK@qfUN6OJcRM3j8mScq&&=E6g$IBgs4neDSqMR%w%c(+2^ka6q+*#<9NQj&! zX8bBKJ81GwI9R*TCAbOTCTXh0?Ou^GsmCZXlac%wx60I{HaDQ7o~>}pbqpJ5<&q%3clG*3Mbru#$RU`;!mvXW7xxX2VO z8Ot{Jih-FyEj2ou2_S9~N(z!m3L&sHjLRxyefj0NgtOXv>Rx7cEqp-+N(yt2ZQu#~8f@G$mQNljK+cay(u zuW8_7+3bd0|8mQ2O{oy3azQaeg$RunNcW+1Nj8&L<-)Fj zYo?%|hJL@I@sc?W;gJMu93@9VK`4RJ$~QTh_}FF`~^Vx9)v*Si&PUL+6B5Y zcG0kxspfH)QO)o)Lu*7yupoHj+QE4du(8U@yvFDU%NBGq@wf(MqGB+ktQBpGI($N# z)aC=(aiM>HUb7sJBSglxio>#ch0&6A8K(pkSY>d{0s~Bwni_XC!?v3?prPJ270Vvg zJ!`?CY(hJ?NMTD1=O9b$uek}!)QYZq!J?YWG{@!JlvF4y8;-Diiw;n&wMJUr*kQV7 znYvA#1->|;&4Et?T60Unf&~i3!O1aOD!>-Y(ax`Mx_vJmWtL%ER}4%addUT&z?Z0T z+lUs7;5N}j=xy7nX>emah|2i521y08iE!q`gmz^7dm;cBGgLgkO><+-dChQ4ZQiI< z<~0#l3VFxVE>T1VM&*B~KmLsRmTR`C(k>yszD3c?+ZDCr{2WDMM}8QL_9Fod{dgN+ ze!Q)~kF}!e$J?>~!%#I;C3;IA$1E?(b+t-9{th8ksT!`zRizrK zM(;FMlgJ9m$TL^08CQcd4&V#UeDg%YxpObVy<;BM49;m8E-z;R!Bu1wU<--Bp_f|c zS92ZBc8i9+=z3hcWbsAK3~nL-DaWba_+#`4+);5j^2G}_y-4kh>c=gwxgkg!cf?A zmZcU@+9OrzP6L(*8a50w<@RWkT8cKQc3TZKXXXJoUq~|?nN#GFGHGV48=weL>e?|E}A@n$XEBRoH| zv!f?K;s57oJZJ0>OwWV@hk<`=$ehq^`NzZHHocJ61A(RwuIzu#_P2}WK!t}7l~qzx z6E`}pcWkIb>*~<0SO2W;3qaM`xb<|~Dp5RAezd_UZbbnm5`nIdfVfGvB(gSoWI)bV zM1mxirB)IO`dGJ-^PvK>8tJD!4zutWK2soJDOLHd)J}Ymu0r@emGKSgE8<<^hv?;u z!Z1~`F{u0qbr5_FXhQ1AL;^P-MUi7z2|)JZ`GVJrj&9Jo3od~xF$?1!8VHbt5}-1z zFT;D5@o$aCcCoim*J-F$$&(1t#@5DOzrXv$nmSUCki9P=CO1Z3T_1h*_x<-rCjptj zjwLZ{H`3SBwXVThcczx!TaS|1z*8bO@-*WaDZotpkhoA+Kmr{||n&*Wy||D!SO z-Q4V%$(h{DT$?pLrN5J#IX(B5Khl)S=VqrT-jy~Rp4Bt8cxv^B^*GskDDZu4Xmn%f*!s}1+VI|u;p6MW z#|7u;`q0rfvG4H4zUlRS(_eM7V(KJ$>WcTP()KfpKD80A6I)UciQd9OiL4@;8tH Optional[dict]: + # Get the saved session (value) from the database + serialized_session_data = self.client.get(store_id) + if serialized_session_data: + return self.serializer.decode(serialized_session_data) + return None + + def _delete_session(self, store_id: str) -> None: + self.client.delete(store_id) + + def _upsert_session( + self, session_lifetime: TimeDelta, session: ServerSideSession, store_id: str + ) -> None: + storage_time_to_live = total_seconds(session_lifetime) + + # Serialize the session data + serialized_session_data = self.serializer.encode(session) + + # Update existing or create new session in the database + self.client.set( + name=store_id, + value=serialized_session_data, + ex=storage_time_to_live, + ) diff --git a/psets/9/finance/env/lib/python3.12/site-packages/flask_session/sqlalchemy/__init__.py b/psets/9/finance/env/lib/python3.12/site-packages/flask_session/sqlalchemy/__init__.py new file mode 100644 index 0000000..41e033a --- /dev/null +++ b/psets/9/finance/env/lib/python3.12/site-packages/flask_session/sqlalchemy/__init__.py @@ -0,0 +1 @@ +from .sqlalchemy import SqlAlchemySession, SqlAlchemySessionInterface # noqa: F401 diff --git a/psets/9/finance/env/lib/python3.12/site-packages/flask_session/sqlalchemy/__pycache__/__init__.cpython-312.pyc b/psets/9/finance/env/lib/python3.12/site-packages/flask_session/sqlalchemy/__pycache__/__init__.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..0efbb75f2a97f13bdcfe7acd755231d8e8f42519 GIT binary patch literal 300 zcmX@j%ge<81W#%r(?fvtV-N=hn4pZ$B0$D;h7^Vr#vF!R#wf;IrYI&xhDs()=9i2> zDNUwZg29D3jycI0skxQGsl~;a`FXdbFoZnwN>Yo`5|dN?G?{O46&L0tLUa@{0}Ux+ z0TL@2J_AXHUpe}@c_sQTi6yCd`pNkznR)5@$;GAy`US7ZXof2nURt4K7;E82G=5XARhpv_*Xgr literal 0 HcmV?d00001 diff --git a/psets/9/finance/env/lib/python3.12/site-packages/flask_session/sqlalchemy/__pycache__/sqlalchemy.cpython-312.pyc b/psets/9/finance/env/lib/python3.12/site-packages/flask_session/sqlalchemy/__pycache__/sqlalchemy.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..065da6b5d9a633ae15b131bd229213a4350b30cb GIT binary patch literal 9936 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 af$zGzm20}U|AdWeT-kQyJAwck>;D0-sNDGg literal 0 HcmV?d00001 diff --git a/psets/9/finance/env/lib/python3.12/site-packages/flask_session/sqlalchemy/sqlalchemy.py b/psets/9/finance/env/lib/python3.12/site-packages/flask_session/sqlalchemy/sqlalchemy.py new file mode 100644 index 0000000..4841c84 --- /dev/null +++ b/psets/9/finance/env/lib/python3.12/site-packages/flask_session/sqlalchemy/sqlalchemy.py @@ -0,0 +1,189 @@ +import warnings +from datetime import datetime +from datetime import timedelta as TimeDelta +from typing import Any, Optional + +from flask import Flask +from flask_sqlalchemy import SQLAlchemy +from itsdangerous import want_bytes +from sqlalchemy import Column, DateTime, Integer, LargeBinary, Sequence, String + +from .._utils import retry_query +from ..base import ServerSideSession, ServerSideSessionInterface +from ..defaults import Defaults + + +class SqlAlchemySession(ServerSideSession): + pass + + +def create_session_model(db, table_name, schema=None, bind_key=None, sequence=None): + class Session(db.Model): + __tablename__ = table_name + __table_args__ = {"schema": schema} if schema else {} + __bind_key__ = bind_key + + id = ( + Column(Integer, Sequence(sequence), primary_key=True) + if sequence + else Column(Integer, primary_key=True) + ) + session_id = Column(String(255), unique=True) + data = Column(LargeBinary) + expiry = Column(DateTime) + + def __init__(self, session_id: str, data: Any, expiry: datetime): + self.session_id = session_id + self.data = data + self.expiry = expiry + + def __repr__(self): + return f"" + + return Session + + +class SqlAlchemySessionInterface(ServerSideSessionInterface): + """Uses the Flask-SQLAlchemy from a flask app as session storage. + + :param app: A Flask app instance. + :param client: A Flask-SQLAlchemy instance. + :param key_prefix: A prefix that is added to all storage keys. + :param use_signer: Whether to sign the session id cookie or not. + :param permanent: Whether to use permanent session or not. + :param sid_length: The length of the generated session id in bytes. + :param serialization_format: The serialization format to use for the session data. + :param table: The table name you want to use. + :param sequence: The sequence to use for the primary key if needed. + :param schema: The db schema to use. + :param bind_key: The db bind key to use. + :param cleanup_n_requests: Delete expired sessions on average every N requests. + + .. versionadded:: 0.7 + db changed to client to be standard on all session interfaces. + The `cleanup_n_request` parameter was added. + + .. versionadded:: 0.6 + The `sid_length`, `sequence`, `schema` and `bind_key` parameters were added. + + .. versionadded:: 0.2 + The `use_signer` parameter was added. + """ + + session_class = SqlAlchemySession + ttl = False + + def __init__( + self, + app: Optional[Flask], + client: Optional[SQLAlchemy] = Defaults.SESSION_SQLALCHEMY, + key_prefix: str = Defaults.SESSION_KEY_PREFIX, + use_signer: bool = Defaults.SESSION_USE_SIGNER, + permanent: bool = Defaults.SESSION_PERMANENT, + sid_length: int = Defaults.SESSION_ID_LENGTH, + serialization_format: str = Defaults.SESSION_SERIALIZATION_FORMAT, + table: str = Defaults.SESSION_SQLALCHEMY_TABLE, + sequence: Optional[str] = Defaults.SESSION_SQLALCHEMY_SEQUENCE, + schema: Optional[str] = Defaults.SESSION_SQLALCHEMY_SCHEMA, + bind_key: Optional[str] = Defaults.SESSION_SQLALCHEMY_BIND_KEY, + cleanup_n_requests: Optional[int] = Defaults.SESSION_CLEANUP_N_REQUESTS, + ): + self.app = app + + if client is None or not isinstance(client, SQLAlchemy): + warnings.warn( + "No valid SQLAlchemy instance provided, attempting to create a new instance on localhost with default settings.", + RuntimeWarning, + stacklevel=1, + ) + client = SQLAlchemy(app) + self.client = client + + # Create the session model + self.sql_session_model = create_session_model( + client, table, schema, bind_key, sequence + ) + # Create the table if it does not exist + with app.app_context(): + if bind_key: + engine = self.client.get_engine(app, bind=bind_key) + else: + engine = self.client.engine + self.sql_session_model.__table__.create(bind=engine, checkfirst=True) + + super().__init__( + app, + key_prefix, + use_signer, + permanent, + sid_length, + serialization_format, + cleanup_n_requests, + ) + + @retry_query() + def _delete_expired_sessions(self) -> None: + try: + self.client.session.query(self.sql_session_model).filter( + self.sql_session_model.expiry <= datetime.utcnow() + ).delete(synchronize_session=False) + self.client.session.commit() + except Exception: + self.client.session.rollback() + raise + + @retry_query() + def _retrieve_session_data(self, store_id: str) -> Optional[dict]: + # Get the saved session (record) from the database + record = self.sql_session_model.query.filter_by(session_id=store_id).first() + + # "Delete the session record if it is expired as SQL has no TTL ability + if record and (record.expiry is None or record.expiry <= datetime.utcnow()): + try: + self.client.session.delete(record) + self.client.session.commit() + except Exception: + self.client.session.rollback() + raise + record = None + + if record: + serialized_session_data = want_bytes(record.data) + return self.serializer.decode(serialized_session_data) + return None + + @retry_query() + def _delete_session(self, store_id: str) -> None: + try: + self.sql_session_model.query.filter_by(session_id=store_id).delete() + self.client.session.commit() + except Exception: + self.client.session.rollback() + raise + + @retry_query() + def _upsert_session( + self, session_lifetime: TimeDelta, session: ServerSideSession, store_id: str + ) -> None: + storage_expiration_datetime = datetime.utcnow() + session_lifetime + + # Serialize session data + serialized_session_data = self.serializer.encode(session) + + # Update existing or create new session in the database + try: + record = self.sql_session_model.query.filter_by(session_id=store_id).first() + if record: + record.data = serialized_session_data + record.expiry = storage_expiration_datetime + else: + record = self.sql_session_model( + session_id=store_id, + data=serialized_session_data, + expiry=storage_expiration_datetime, + ) + self.client.session.add(record) + self.client.session.commit() + except Exception: + self.client.session.rollback() + raise diff --git a/psets/9/finance/env/lib/python3.12/site-packages/greenlet-3.1.1.dist-info/AUTHORS b/psets/9/finance/env/lib/python3.12/site-packages/greenlet-3.1.1.dist-info/AUTHORS new file mode 100644 index 0000000..42a5c22 --- /dev/null +++ b/psets/9/finance/env/lib/python3.12/site-packages/greenlet-3.1.1.dist-info/AUTHORS @@ -0,0 +1,51 @@ +Original Authors +---------------- +* Armin Rigo +* Christian Tismer + +Contributors +------------ +* Al Stone +* Alexander Schmidt +* Alexey Borzenkov +* Andreas Schwab +* Armin Ronacher +* Bin Wang +* Bob Ippolito +* ChangBo Guo +* Christoph Gohlke +* Denis Bilenko +* Dirk Mueller +* Donovan Preston +* Fantix King +* Floris Bruynooghe +* Fredrik Fornwall +* Gerd Woetzel +* Giel van Schijndel +* Gökhan Karabulut +* Gustavo Niemeyer +* Guy Rozendorn +* Hye-Shik Chang +* Jared Kuolt +* Jason Madden +* Josh Snyder +* Kyle Ambroff +* Laszlo Boszormenyi +* Mao Han +* Marc Abramowitz +* Marc Schlaich +* Marcin Bachry +* Matt Madison +* Matt Turner +* Michael Ellerman +* Michael Matz +* Ralf Schmitt +* Robie Basak +* Ronny Pfannschmidt +* Samual M. Rushing +* Tony Bowles +* Tony Breeds +* Trevor Bowen +* Tulio Magno Quites Machado Filho +* Ulrich Weigand +* Victor Stinner diff --git a/psets/9/finance/env/lib/python3.12/site-packages/greenlet-3.1.1.dist-info/INSTALLER b/psets/9/finance/env/lib/python3.12/site-packages/greenlet-3.1.1.dist-info/INSTALLER new file mode 100644 index 0000000..a1b589e --- /dev/null +++ b/psets/9/finance/env/lib/python3.12/site-packages/greenlet-3.1.1.dist-info/INSTALLER @@ -0,0 +1 @@ +pip diff --git a/psets/9/finance/env/lib/python3.12/site-packages/greenlet-3.1.1.dist-info/LICENSE b/psets/9/finance/env/lib/python3.12/site-packages/greenlet-3.1.1.dist-info/LICENSE new file mode 100644 index 0000000..b73a4a1 --- /dev/null +++ b/psets/9/finance/env/lib/python3.12/site-packages/greenlet-3.1.1.dist-info/LICENSE @@ -0,0 +1,30 @@ +The following files are derived from Stackless Python and are subject to the +same license as Stackless Python: + + src/greenlet/slp_platformselect.h + files in src/greenlet/platform/ directory + +See LICENSE.PSF and http://www.stackless.com/ for details. + +Unless otherwise noted, the files in greenlet have been released under the +following MIT license: + +Copyright (c) Armin Rigo, Christian Tismer and contributors + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. diff --git a/psets/9/finance/env/lib/python3.12/site-packages/greenlet-3.1.1.dist-info/LICENSE.PSF b/psets/9/finance/env/lib/python3.12/site-packages/greenlet-3.1.1.dist-info/LICENSE.PSF new file mode 100644 index 0000000..d3b509a --- /dev/null +++ b/psets/9/finance/env/lib/python3.12/site-packages/greenlet-3.1.1.dist-info/LICENSE.PSF @@ -0,0 +1,47 @@ +PYTHON SOFTWARE FOUNDATION LICENSE VERSION 2 +-------------------------------------------- + +1. This LICENSE AGREEMENT is between the Python Software Foundation +("PSF"), and the Individual or Organization ("Licensee") accessing and +otherwise using this software ("Python") in source or binary form and +its associated documentation. + +2. Subject to the terms and conditions of this License Agreement, PSF hereby +grants Licensee a nonexclusive, royalty-free, world-wide license to reproduce, +analyze, test, perform and/or display publicly, prepare derivative works, +distribute, and otherwise use Python alone or in any derivative version, +provided, however, that PSF's License Agreement and PSF's notice of copyright, +i.e., "Copyright (c) 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010, +2011 Python Software Foundation; All Rights Reserved" are retained in Python +alone or in any derivative version prepared by Licensee. + +3. In the event Licensee prepares a derivative work that is based on +or incorporates Python or any part thereof, and wants to make +the derivative work available to others as provided herein, then +Licensee hereby agrees to include in any such work a brief summary of +the changes made to Python. + +4. PSF is making Python available to Licensee on an "AS IS" +basis. PSF MAKES NO REPRESENTATIONS OR WARRANTIES, EXPRESS OR +IMPLIED. BY WAY OF EXAMPLE, BUT NOT LIMITATION, PSF MAKES NO AND +DISCLAIMS ANY REPRESENTATION OR WARRANTY OF MERCHANTABILITY OR FITNESS +FOR ANY PARTICULAR PURPOSE OR THAT THE USE OF PYTHON WILL NOT +INFRINGE ANY THIRD PARTY RIGHTS. + +5. PSF SHALL NOT BE LIABLE TO LICENSEE OR ANY OTHER USERS OF PYTHON +FOR ANY INCIDENTAL, SPECIAL, OR CONSEQUENTIAL DAMAGES OR LOSS AS +A RESULT OF MODIFYING, DISTRIBUTING, OR OTHERWISE USING PYTHON, +OR ANY DERIVATIVE THEREOF, EVEN IF ADVISED OF THE POSSIBILITY THEREOF. + +6. This License Agreement will automatically terminate upon a material +breach of its terms and conditions. + +7. Nothing in this License Agreement shall be deemed to create any +relationship of agency, partnership, or joint venture between PSF and +Licensee. This License Agreement does not grant permission to use PSF +trademarks or trade name in a trademark sense to endorse or promote +products or services of Licensee, or any third party. + +8. By copying, installing or otherwise using Python, Licensee +agrees to be bound by the terms and conditions of this License +Agreement. diff --git a/psets/9/finance/env/lib/python3.12/site-packages/greenlet-3.1.1.dist-info/METADATA b/psets/9/finance/env/lib/python3.12/site-packages/greenlet-3.1.1.dist-info/METADATA new file mode 100644 index 0000000..1529410 --- /dev/null +++ b/psets/9/finance/env/lib/python3.12/site-packages/greenlet-3.1.1.dist-info/METADATA @@ -0,0 +1,103 @@ +Metadata-Version: 2.1 +Name: greenlet +Version: 3.1.1 +Summary: Lightweight in-process concurrent programming +Home-page: https://greenlet.readthedocs.io/ +Author: Alexey Borzenkov +Author-email: snaury@gmail.com +Maintainer: Jason Madden +Maintainer-email: jason@seecoresoftware.com +License: MIT License +Project-URL: Bug Tracker, https://github.com/python-greenlet/greenlet/issues +Project-URL: Source Code, https://github.com/python-greenlet/greenlet/ +Project-URL: Documentation, https://greenlet.readthedocs.io/ +Keywords: greenlet coroutine concurrency threads cooperative +Platform: any +Classifier: Development Status :: 5 - Production/Stable +Classifier: Intended Audience :: Developers +Classifier: License :: OSI Approved :: MIT License +Classifier: Natural Language :: English +Classifier: Programming Language :: C +Classifier: Programming Language :: Python +Classifier: Programming Language :: Python :: 3 +Classifier: Programming Language :: Python :: 3 :: Only +Classifier: Programming Language :: Python :: 3.7 +Classifier: Programming Language :: Python :: 3.8 +Classifier: Programming Language :: Python :: 3.9 +Classifier: Programming Language :: Python :: 3.10 +Classifier: Programming Language :: Python :: 3.11 +Classifier: Programming Language :: Python :: 3.12 +Classifier: Programming Language :: Python :: 3.13 +Classifier: Operating System :: OS Independent +Classifier: Topic :: Software Development :: Libraries :: Python Modules +Requires-Python: >=3.7 +Description-Content-Type: text/x-rst +License-File: LICENSE +License-File: LICENSE.PSF +License-File: AUTHORS +Provides-Extra: docs +Requires-Dist: Sphinx ; extra == 'docs' +Requires-Dist: furo ; extra == 'docs' +Provides-Extra: test +Requires-Dist: objgraph ; extra == 'test' +Requires-Dist: psutil ; extra == 'test' + +.. This file is included into docs/history.rst + + +Greenlets are lightweight coroutines for in-process concurrent +programming. + +The "greenlet" package is a spin-off of `Stackless`_, a version of +CPython that supports micro-threads called "tasklets". Tasklets run +pseudo-concurrently (typically in a single or a few OS-level threads) +and are synchronized with data exchanges on "channels". + +A "greenlet", on the other hand, is a still more primitive notion of +micro-thread with no implicit scheduling; coroutines, in other words. +This is useful when you want to control exactly when your code runs. +You can build custom scheduled micro-threads on top of greenlet; +however, it seems that greenlets are useful on their own as a way to +make advanced control flow structures. For example, we can recreate +generators; the difference with Python's own generators is that our +generators can call nested functions and the nested functions can +yield values too. (Additionally, you don't need a "yield" keyword. See +the example in `test_generator.py +`_). + +Greenlets are provided as a C extension module for the regular unmodified +interpreter. + +.. _`Stackless`: http://www.stackless.com + + +Who is using Greenlet? +====================== + +There are several libraries that use Greenlet as a more flexible +alternative to Python's built in coroutine support: + + - `Concurrence`_ + - `Eventlet`_ + - `Gevent`_ + +.. _Concurrence: http://opensource.hyves.org/concurrence/ +.. _Eventlet: http://eventlet.net/ +.. _Gevent: http://www.gevent.org/ + +Getting Greenlet +================ + +The easiest way to get Greenlet is to install it with pip:: + + pip install greenlet + + +Source code archives and binary distributions are available on the +python package index at https://pypi.org/project/greenlet + +The source code repository is hosted on github: +https://github.com/python-greenlet/greenlet + +Documentation is available on readthedocs.org: +https://greenlet.readthedocs.io diff --git a/psets/9/finance/env/lib/python3.12/site-packages/greenlet-3.1.1.dist-info/RECORD b/psets/9/finance/env/lib/python3.12/site-packages/greenlet-3.1.1.dist-info/RECORD new file mode 100644 index 0000000..1574c43 --- /dev/null +++ b/psets/9/finance/env/lib/python3.12/site-packages/greenlet-3.1.1.dist-info/RECORD @@ -0,0 +1,122 @@ +../../../include/site/python3.12/greenlet/greenlet.h,sha256=sz5pYRSQqedgOt2AMgxLZdTjO-qcr_JMvgiEJR9IAJ8,4755 +greenlet-3.1.1.dist-info/AUTHORS,sha256=swW28t2knVRxRkaEQNZtO7MP9Sgnompb7B6cNgJM8Gk,849 +greenlet-3.1.1.dist-info/INSTALLER,sha256=zuuue4knoyJ-UwPPXg8fezS7VCrXJQrAP7zeNuwvFQg,4 +greenlet-3.1.1.dist-info/LICENSE,sha256=dpgx1uXfrywggC-sz_H6-0wgJd2PYlPfpH_K1Z1NCXk,1434 +greenlet-3.1.1.dist-info/LICENSE.PSF,sha256=5f88I8EQ5JTNfXNsEP2W1GJFe6_soxCEDbZScpjH1Gs,2424 +greenlet-3.1.1.dist-info/METADATA,sha256=MoOb0T5ZdGbCymjJygO-CkVIAaeI5KcuwE_JPpH1hp4,3830 +greenlet-3.1.1.dist-info/RECORD,, +greenlet-3.1.1.dist-info/WHEEL,sha256=kbc9CtIb3U5F4nd4oqzL_-IwpT6vqgiz5ZydaTuQe_0,152 +greenlet-3.1.1.dist-info/top_level.txt,sha256=YSnRsCRoO61JGlP57o8iKL6rdLWDWuiyKD8ekpWUsDc,9 +greenlet/CObjects.cpp,sha256=OPej1bWBgc4sRrTRQ2aFFML9pzDYKlKhlJSjsI0X_eU,3508 +greenlet/PyGreenlet.cpp,sha256=ogWsQ5VhSdItWRLLpWOgSuqYuM3QwQ4cVCxOQIgHx6E,23441 +greenlet/PyGreenlet.hpp,sha256=2ZQlOxYNoy7QwD7mppFoOXe_At56NIsJ0eNsE_hoSsw,1463 +greenlet/PyGreenletUnswitchable.cpp,sha256=PQE0fSZa_IOyUM44IESHkJoD2KtGW3dkhkmZSYY3WHs,4375 +greenlet/PyModule.cpp,sha256=J2TH06dGcNEarioS6NbWXkdME8hJY05XVbdqLrfO5w4,8587 +greenlet/TBrokenGreenlet.cpp,sha256=smN26uC7ahAbNYiS10rtWPjCeTG4jevM8siA2sjJiXg,1021 +greenlet/TExceptionState.cpp,sha256=U7Ctw9fBdNraS0d174MoQW7bN-ae209Ta0JuiKpcpVI,1359 +greenlet/TGreenlet.cpp,sha256=HGYGKpmKYqQ842tASW-QaaV8wua4a5XV_quYKPDsV_Y,25731 +greenlet/TGreenlet.hpp,sha256=mMHcb_rSuozdDiGJjX3GgyYkWgVM4kuO1UgbUP84BlU,27869 +greenlet/TGreenletGlobals.cpp,sha256=YyEmDjKf1g32bsL-unIUScFLnnA1fzLWf2gOMd-D0Zw,3264 +greenlet/TMainGreenlet.cpp,sha256=fvgb8HHB-FVTPEKjR1s_ifCZSpp5D5YQByik0CnIABg,3276 +greenlet/TPythonState.cpp,sha256=FxRdi76lTGXaQKWwkq82VaCfIRdF2Z-fh-TlRTMjYqg,15359 +greenlet/TStackState.cpp,sha256=V444I8Jj9DhQz-9leVW_9dtiSRjaE1NMlgDG02Xxq-Y,7381 +greenlet/TThreadState.hpp,sha256=2Jgg7DtGggMYR_x3CLAvAFf1mIdIDtQvSSItcdmX4ZQ,19131 +greenlet/TThreadStateCreator.hpp,sha256=uYTexDWooXSSgUc5uh-Mhm5BQi3-kR6CqpizvNynBFQ,2610 +greenlet/TThreadStateDestroy.cpp,sha256=wt7lQwLI0mi_JtnZB_jB4bUmfCa5b6nQhA7XOmnI1yk,9568 +greenlet/TUserGreenlet.cpp,sha256=uemg0lwKXtYB0yzmvyYdIIAsKnNkifXM1OJ2OlrFP1A,23553 +greenlet/__init__.py,sha256=OOmvT6_vn_SekdPzkj4qm6hjfikXMmdNZYDmGTOaRNo,1723 +greenlet/__pycache__/__init__.cpython-312.pyc,, +greenlet/_greenlet.cpython-312-x86_64-linux-gnu.so,sha256=qJ2uNRkRvJ2QWGGj33mM0fMxULTqwARAX2w9a20m2VE,1429296 +greenlet/greenlet.cpp,sha256=WdItb1yWL9WNsTqJNf0Iw8ZwDHD49pkDP0rIRGBg2pw,10996 +greenlet/greenlet.h,sha256=sz5pYRSQqedgOt2AMgxLZdTjO-qcr_JMvgiEJR9IAJ8,4755 +greenlet/greenlet_allocator.hpp,sha256=kxyWW4Qdwlrc7ufgdb5vd6Y7jhauQ699Kod0mqiO1iM,1582 +greenlet/greenlet_compiler_compat.hpp,sha256=nRxpLN9iNbnLVyFDeVmOwyeeNm6scQrOed1l7JQYMCM,4346 +greenlet/greenlet_cpython_add_pending.hpp,sha256=apAwIhGlgYrnYn03zWL6Sxy68kltDeb1e0QupZfb3DQ,6043 +greenlet/greenlet_cpython_compat.hpp,sha256=L_jig3dm2bsJWRazrhlokma2NfnwixoQ0cydshh6ce4,3964 +greenlet/greenlet_exceptions.hpp,sha256=06Bx81DtVaJTa6RtiMcV141b-XHv4ppEgVItkblcLWY,4503 +greenlet/greenlet_internal.hpp,sha256=Ajc-_09W4xWzm9XfyXHAeQAFUgKGKsnJwYsTCoNy3ns,2709 +greenlet/greenlet_refs.hpp,sha256=OnbA91yZf3QHH6-eJccvoNDAaN-pQBMMrclFU1Ot3J4,34436 +greenlet/greenlet_slp_switch.hpp,sha256=kM1QHA2iV-gH4cFyN6lfIagHQxvJZjWOVJdIxRE3TlQ,3198 +greenlet/greenlet_thread_support.hpp,sha256=XUJ6ljWjf9OYyuOILiz8e_yHvT3fbaUiHdhiPNQUV4s,867 +greenlet/platform/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0 +greenlet/platform/__pycache__/__init__.cpython-312.pyc,, +greenlet/platform/setup_switch_x64_masm.cmd,sha256=ZpClUJeU0ujEPSTWNSepP0W2f9XiYQKA8QKSoVou8EU,143 +greenlet/platform/switch_aarch64_gcc.h,sha256=GKC0yWNXnbK2X--X6aguRCMj2Tg7hDU1Zkl3RljDvC8,4307 +greenlet/platform/switch_alpha_unix.h,sha256=Z-SvF8JQV3oxWT8JRbL9RFu4gRFxPdJ7cviM8YayMmw,671 +greenlet/platform/switch_amd64_unix.h,sha256=EcSFCBlodEBhqhKjcJqY_5Dn_jn7pKpkJlOvp7gFXLI,2748 +greenlet/platform/switch_arm32_gcc.h,sha256=Z3KkHszdgq6uU4YN3BxvKMG2AdDnovwCCNrqGWZ1Lyo,2479 +greenlet/platform/switch_arm32_ios.h,sha256=mm5_R9aXB92hyxzFRwB71M60H6AlvHjrpTrc72Pz3l8,1892 +greenlet/platform/switch_arm64_masm.asm,sha256=4kpTtfy7rfcr8j1CpJLAK21EtZpGDAJXWRU68HEy5A8,1245 +greenlet/platform/switch_arm64_masm.obj,sha256=DmLnIB_icoEHAz1naue_pJPTZgR9ElM7-Nmztr-o9_U,746 +greenlet/platform/switch_arm64_msvc.h,sha256=RqK5MHLmXI3Q-FQ7tm32KWnbDNZKnkJdq8CR89cz640,398 +greenlet/platform/switch_csky_gcc.h,sha256=kDikyiPpewP71KoBZQO_MukDTXTXBiC7x-hF0_2DL0w,1331 +greenlet/platform/switch_loongarch64_linux.h,sha256=7M-Dhc4Q8tRbJCJhalDLwU6S9Mx8MjmN1RbTDgIvQTM,779 +greenlet/platform/switch_m68k_gcc.h,sha256=VSa6NpZhvyyvF-Q58CTIWSpEDo4FKygOyTz00whctlw,928 +greenlet/platform/switch_mips_unix.h,sha256=E0tYsqc5anDY1BhenU1l8DW-nVHC_BElzLgJw3TGtPk,1426 +greenlet/platform/switch_ppc64_aix.h,sha256=_BL0iyRr3ZA5iPlr3uk9SJ5sNRWGYLrXcZ5z-CE9anE,3860 +greenlet/platform/switch_ppc64_linux.h,sha256=0rriT5XyxPb0GqsSSn_bP9iQsnjsPbBmu0yqo5goSyQ,3815 +greenlet/platform/switch_ppc_aix.h,sha256=pHA4slEjUFP3J3SYm1TAlNPhgb2G_PAtax5cO8BEe1A,2941 +greenlet/platform/switch_ppc_linux.h,sha256=YwrlKUzxlXuiKMQqr6MFAV1bPzWnmvk6X1AqJZEpOWU,2759 +greenlet/platform/switch_ppc_macosx.h,sha256=Z6KN_ud0n6nC3ltJrNz2qtvER6vnRAVRNH9mdIDpMxY,2624 +greenlet/platform/switch_ppc_unix.h,sha256=-ZG7MSSPEA5N4qO9PQChtyEJ-Fm6qInhyZm_ZBHTtMg,2652 +greenlet/platform/switch_riscv_unix.h,sha256=Xg0wBen8Je21LWzFtLNLvUUYq6p9n_WY7AUQbiBVyyk,865 +greenlet/platform/switch_s390_unix.h,sha256=RRlGu957ybmq95qNNY4Qw1mcaoT3eBnW5KbVwu48KX8,2763 +greenlet/platform/switch_sh_gcc.h,sha256=mcRJBTu-2UBf4kZtX601qofwuDuy-Y-hnxJtrcaB7do,901 +greenlet/platform/switch_sparc_sun_gcc.h,sha256=xZish9GsMHBienUbUMsX1-ZZ-as7hs36sVhYIE3ew8Y,2797 +greenlet/platform/switch_x32_unix.h,sha256=nM98PKtzTWc1lcM7TRMUZJzskVdR1C69U1UqZRWX0GE,1509 +greenlet/platform/switch_x64_masm.asm,sha256=nu6n2sWyXuXfpPx40d9YmLfHXUc1sHgeTvX1kUzuvEM,1841 +greenlet/platform/switch_x64_masm.obj,sha256=GNtTNxYdo7idFUYsQv-mrXWgyT5EJ93-9q90lN6svtQ,1078 +greenlet/platform/switch_x64_msvc.h,sha256=LIeasyKo_vHzspdMzMHbosRhrBfKI4BkQOh4qcTHyJw,1805 +greenlet/platform/switch_x86_msvc.h,sha256=TtGOwinbFfnn6clxMNkCz8i6OmgB6kVRrShoF5iT9to,12838 +greenlet/platform/switch_x86_unix.h,sha256=VplW9H0FF0cZHw1DhJdIUs5q6YLS4cwb2nYwjF83R1s,3059 +greenlet/slp_platformselect.h,sha256=s-U-BrZ3qwwfI-6W9zWw2rb404OksZYbxYC2w5kSMXM,3841 +greenlet/tests/__init__.py,sha256=cj2-qpMXnlVRLbMLX-rPNNMVJ42ZssdxHd84NSQ3YXw,9246 +greenlet/tests/__pycache__/__init__.cpython-312.pyc,, +greenlet/tests/__pycache__/fail_clearing_run_switches.cpython-312.pyc,, +greenlet/tests/__pycache__/fail_cpp_exception.cpython-312.pyc,, +greenlet/tests/__pycache__/fail_initialstub_already_started.cpython-312.pyc,, +greenlet/tests/__pycache__/fail_slp_switch.cpython-312.pyc,, +greenlet/tests/__pycache__/fail_switch_three_greenlets.cpython-312.pyc,, +greenlet/tests/__pycache__/fail_switch_three_greenlets2.cpython-312.pyc,, +greenlet/tests/__pycache__/fail_switch_two_greenlets.cpython-312.pyc,, +greenlet/tests/__pycache__/leakcheck.cpython-312.pyc,, +greenlet/tests/__pycache__/test_contextvars.cpython-312.pyc,, +greenlet/tests/__pycache__/test_cpp.cpython-312.pyc,, +greenlet/tests/__pycache__/test_extension_interface.cpython-312.pyc,, +greenlet/tests/__pycache__/test_gc.cpython-312.pyc,, +greenlet/tests/__pycache__/test_generator.cpython-312.pyc,, +greenlet/tests/__pycache__/test_generator_nested.cpython-312.pyc,, +greenlet/tests/__pycache__/test_greenlet.cpython-312.pyc,, +greenlet/tests/__pycache__/test_greenlet_trash.cpython-312.pyc,, +greenlet/tests/__pycache__/test_leaks.cpython-312.pyc,, +greenlet/tests/__pycache__/test_stack_saved.cpython-312.pyc,, +greenlet/tests/__pycache__/test_throw.cpython-312.pyc,, +greenlet/tests/__pycache__/test_tracing.cpython-312.pyc,, +greenlet/tests/__pycache__/test_version.cpython-312.pyc,, +greenlet/tests/__pycache__/test_weakref.cpython-312.pyc,, +greenlet/tests/_test_extension.c,sha256=vkeGA-6oeJcGILsD7oIrT1qZop2GaTOHXiNT7mcSl-0,5773 +greenlet/tests/_test_extension.cpython-312-x86_64-linux-gnu.so,sha256=OcUSkiCS4G35zlL3jz5K6Xsvurgf6lyAlv2J_EpfXns,37168 +greenlet/tests/_test_extension_cpp.cpp,sha256=e0kVnaB8CCaEhE9yHtNyfqTjevsPDKKx-zgxk7PPK48,6565 +greenlet/tests/_test_extension_cpp.cpython-312-x86_64-linux-gnu.so,sha256=WNTdn6rjiT8hKKgi5viliSiFim1uKnTC6ENTIFZp4m8,57800 +greenlet/tests/fail_clearing_run_switches.py,sha256=o433oA_nUCtOPaMEGc8VEhZIKa71imVHXFw7TsXaP8M,1263 +greenlet/tests/fail_cpp_exception.py,sha256=o_ZbipWikok8Bjc-vjiQvcb5FHh2nVW-McGKMLcMzh0,985 +greenlet/tests/fail_initialstub_already_started.py,sha256=txENn5IyzGx2p-XR1XB7qXmC8JX_4mKDEA8kYBXUQKc,1961 +greenlet/tests/fail_slp_switch.py,sha256=rJBZcZfTWR3e2ERQtPAud6YKShiDsP84PmwOJbp4ey0,524 +greenlet/tests/fail_switch_three_greenlets.py,sha256=zSitV7rkNnaoHYVzAGGLnxz-yPtohXJJzaE8ehFDQ0M,956 +greenlet/tests/fail_switch_three_greenlets2.py,sha256=FPJensn2EJxoropl03JSTVP3kgP33k04h6aDWWozrOk,1285 +greenlet/tests/fail_switch_two_greenlets.py,sha256=1CaI8s3504VbbF1vj1uBYuy-zxBHVzHPIAd1LIc8ONg,817 +greenlet/tests/leakcheck.py,sha256=inbfM7_oVzd8jIKGxCgo4JqpFZaDAnWPkSULJ8vIE1s,11964 +greenlet/tests/test_contextvars.py,sha256=0n5pR_lbpAppc5wFfK0e1SwYLM-fsSFp72B5_ArLPGE,10348 +greenlet/tests/test_cpp.py,sha256=hpxhFAdKJTpAVZP8CBGs1ZcrKdscI9BaDZk4btkI5d4,2736 +greenlet/tests/test_extension_interface.py,sha256=eJ3cwLacdK2WbsrC-4DgeyHdwLRcG4zx7rrkRtqSzC4,3829 +greenlet/tests/test_gc.py,sha256=PCOaRpIyjNnNlDogGL3FZU_lrdXuM-pv1rxeE5TP5mc,2923 +greenlet/tests/test_generator.py,sha256=tONXiTf98VGm347o1b-810daPiwdla5cbpFg6QI1R1g,1240 +greenlet/tests/test_generator_nested.py,sha256=7v4HOYrf1XZP39dk5IUMubdZ8yc3ynwZcqj9GUJyMSA,3718 +greenlet/tests/test_greenlet.py,sha256=zoAy56MtEyz5P93Iknpt2pPjNO3ePYrgM7SDE8Cw_uI,45990 +greenlet/tests/test_greenlet_trash.py,sha256=n2dBlQfOoEO1ODatFi8QdhboH3fB86YtqzcYMYOXxbw,7947 +greenlet/tests/test_leaks.py,sha256=wskLqCAvqZ3qTZkam_wXzd-E5zelUjlXS5Ss8KshtZY,17465 +greenlet/tests/test_stack_saved.py,sha256=eyzqNY2VCGuGlxhT_In6TvZ6Okb0AXFZVyBEnK1jDwA,446 +greenlet/tests/test_throw.py,sha256=u2TQ_WvvCd6N6JdXWIxVEcXkKu5fepDlz9dktYdmtng,3712 +greenlet/tests/test_tracing.py,sha256=VlwzMU0C1noospZhuUMyB7MHw200emIvGCN_6G2p2ZU,8250 +greenlet/tests/test_version.py,sha256=O9DpAITsOFgiRcjd4odQ7ejmwx_N9Q1zQENVcbtFHIc,1339 +greenlet/tests/test_weakref.py,sha256=F8M23btEF87bIbpptLNBORosbQqNZGiYeKMqYjWrsak,883 diff --git a/psets/9/finance/env/lib/python3.12/site-packages/greenlet-3.1.1.dist-info/WHEEL b/psets/9/finance/env/lib/python3.12/site-packages/greenlet-3.1.1.dist-info/WHEEL new file mode 100644 index 0000000..a23e9fa --- /dev/null +++ b/psets/9/finance/env/lib/python3.12/site-packages/greenlet-3.1.1.dist-info/WHEEL @@ -0,0 +1,6 @@ +Wheel-Version: 1.0 +Generator: setuptools (75.1.0) +Root-Is-Purelib: false +Tag: cp312-cp312-manylinux_2_24_x86_64 +Tag: cp312-cp312-manylinux_2_28_x86_64 + diff --git a/psets/9/finance/env/lib/python3.12/site-packages/greenlet-3.1.1.dist-info/top_level.txt b/psets/9/finance/env/lib/python3.12/site-packages/greenlet-3.1.1.dist-info/top_level.txt new file mode 100644 index 0000000..46725be --- /dev/null +++ b/psets/9/finance/env/lib/python3.12/site-packages/greenlet-3.1.1.dist-info/top_level.txt @@ -0,0 +1 @@ +greenlet diff --git a/psets/9/finance/env/lib/python3.12/site-packages/greenlet/CObjects.cpp b/psets/9/finance/env/lib/python3.12/site-packages/greenlet/CObjects.cpp new file mode 100644 index 0000000..c135995 --- /dev/null +++ b/psets/9/finance/env/lib/python3.12/site-packages/greenlet/CObjects.cpp @@ -0,0 +1,157 @@ +#ifndef COBJECTS_CPP +#define COBJECTS_CPP +/***************************************************************************** + * C interface + * + * These are exported using the CObject API + */ +#ifdef __clang__ +# pragma clang diagnostic push +# pragma clang diagnostic ignored "-Wunused-function" +#endif + +#include "greenlet_exceptions.hpp" + +#include "greenlet_internal.hpp" +#include "greenlet_refs.hpp" + + +#include "TThreadStateDestroy.cpp" + +#include "PyGreenlet.hpp" + +using greenlet::PyErrOccurred; +using greenlet::Require; + + + +extern "C" { +static PyGreenlet* +PyGreenlet_GetCurrent(void) +{ + return GET_THREAD_STATE().state().get_current().relinquish_ownership(); +} + +static int +PyGreenlet_SetParent(PyGreenlet* g, PyGreenlet* nparent) +{ + return green_setparent((PyGreenlet*)g, (PyObject*)nparent, NULL); +} + +static PyGreenlet* +PyGreenlet_New(PyObject* run, PyGreenlet* parent) +{ + using greenlet::refs::NewDictReference; + // In the past, we didn't use green_new and green_init, but that + // was a maintenance issue because we duplicated code. This way is + // much safer, but slightly slower. If that's a problem, we could + // refactor green_init to separate argument parsing from initialization. + OwnedGreenlet g = OwnedGreenlet::consuming(green_new(&PyGreenlet_Type, nullptr, nullptr)); + if (!g) { + return NULL; + } + + try { + NewDictReference kwargs; + if (run) { + kwargs.SetItem(mod_globs->str_run, run); + } + if (parent) { + kwargs.SetItem("parent", (PyObject*)parent); + } + + Require(green_init(g.borrow(), mod_globs->empty_tuple, kwargs.borrow())); + } + catch (const PyErrOccurred&) { + return nullptr; + } + + return g.relinquish_ownership(); +} + +static PyObject* +PyGreenlet_Switch(PyGreenlet* self, PyObject* args, PyObject* kwargs) +{ + if (!PyGreenlet_Check(self)) { + PyErr_BadArgument(); + return NULL; + } + + if (args == NULL) { + args = mod_globs->empty_tuple; + } + + if (kwargs == NULL || !PyDict_Check(kwargs)) { + kwargs = NULL; + } + + return green_switch(self, args, kwargs); +} + +static PyObject* +PyGreenlet_Throw(PyGreenlet* self, PyObject* typ, PyObject* val, PyObject* tb) +{ + if (!PyGreenlet_Check(self)) { + PyErr_BadArgument(); + return nullptr; + } + try { + PyErrPieces err_pieces(typ, val, tb); + return internal_green_throw(self, err_pieces).relinquish_ownership(); + } + catch (const PyErrOccurred&) { + return nullptr; + } +} + + + +static int +Extern_PyGreenlet_MAIN(PyGreenlet* self) +{ + if (!PyGreenlet_Check(self)) { + PyErr_BadArgument(); + return -1; + } + return self->pimpl->main(); +} + +static int +Extern_PyGreenlet_ACTIVE(PyGreenlet* self) +{ + if (!PyGreenlet_Check(self)) { + PyErr_BadArgument(); + return -1; + } + return self->pimpl->active(); +} + +static int +Extern_PyGreenlet_STARTED(PyGreenlet* self) +{ + if (!PyGreenlet_Check(self)) { + PyErr_BadArgument(); + return -1; + } + return self->pimpl->started(); +} + +static PyGreenlet* +Extern_PyGreenlet_GET_PARENT(PyGreenlet* self) +{ + if (!PyGreenlet_Check(self)) { + PyErr_BadArgument(); + return NULL; + } + // This can return NULL even if there is no exception + return self->pimpl->parent().acquire(); +} +} // extern C. + +/** End C API ****************************************************************/ +#ifdef __clang__ +# pragma clang diagnostic pop +#endif + + +#endif diff --git a/psets/9/finance/env/lib/python3.12/site-packages/greenlet/PyGreenlet.cpp b/psets/9/finance/env/lib/python3.12/site-packages/greenlet/PyGreenlet.cpp new file mode 100644 index 0000000..29c0bba --- /dev/null +++ b/psets/9/finance/env/lib/python3.12/site-packages/greenlet/PyGreenlet.cpp @@ -0,0 +1,738 @@ +/* -*- indent-tabs-mode: nil; tab-width: 4; -*- */ +#ifndef PYGREENLET_CPP +#define PYGREENLET_CPP +/***************** +The Python slot functions for TGreenlet. + */ + + +#define PY_SSIZE_T_CLEAN +#include +#include "structmember.h" // PyMemberDef + +#include "greenlet_internal.hpp" +#include "TThreadStateDestroy.cpp" +#include "TGreenlet.hpp" +// #include "TUserGreenlet.cpp" +// #include "TMainGreenlet.cpp" +// #include "TBrokenGreenlet.cpp" + + +#include "greenlet_refs.hpp" +#include "greenlet_slp_switch.hpp" + +#include "greenlet_thread_support.hpp" +#include "TGreenlet.hpp" + +#include "TGreenletGlobals.cpp" +#include "TThreadStateDestroy.cpp" +#include "PyGreenlet.hpp" +// #include "TGreenlet.cpp" + +// #include "TExceptionState.cpp" +// #include "TPythonState.cpp" +// #include "TStackState.cpp" + +using greenlet::LockGuard; +using greenlet::LockInitError; +using greenlet::PyErrOccurred; +using greenlet::Require; + +using greenlet::g_handle_exit; +using greenlet::single_result; + +using greenlet::Greenlet; +using greenlet::UserGreenlet; +using greenlet::MainGreenlet; +using greenlet::BrokenGreenlet; +using greenlet::ThreadState; +using greenlet::PythonState; + + + +static PyGreenlet* +green_new(PyTypeObject* type, PyObject* UNUSED(args), PyObject* UNUSED(kwds)) +{ + PyGreenlet* o = + (PyGreenlet*)PyBaseObject_Type.tp_new(type, mod_globs->empty_tuple, mod_globs->empty_dict); + if (o) { + new UserGreenlet(o, GET_THREAD_STATE().state().borrow_current()); + assert(Py_REFCNT(o) == 1); + } + return o; +} + + +// green_init is used in the tp_init slot. So it's important that +// it can be called directly from CPython. Thus, we don't use +// BorrowedGreenlet and BorrowedObject --- although in theory +// these should be binary layout compatible, that may not be +// guaranteed to be the case (32-bit linux ppc possibly). +static int +green_init(PyGreenlet* self, PyObject* args, PyObject* kwargs) +{ + PyArgParseParam run; + PyArgParseParam nparent; + static const char* kwlist[] = { + "run", + "parent", + NULL + }; + + // recall: The O specifier does NOT increase the reference count. + if (!PyArg_ParseTupleAndKeywords( + args, kwargs, "|OO:green", (char**)kwlist, &run, &nparent)) { + return -1; + } + + if (run) { + if (green_setrun(self, run, NULL)) { + return -1; + } + } + if (nparent && !nparent.is_None()) { + return green_setparent(self, nparent, NULL); + } + return 0; +} + + + +static int +green_traverse(PyGreenlet* self, visitproc visit, void* arg) +{ + // We must only visit referenced objects, i.e. only objects + // Py_INCREF'ed by this greenlet (directly or indirectly): + // + // - stack_prev is not visited: holds previous stack pointer, but it's not + // referenced + // - frames are not visited as we don't strongly reference them; + // alive greenlets are not garbage collected + // anyway. This can be a problem, however, if this greenlet is + // never allowed to finish, and is referenced from the frame: we + // have an uncollectible cycle in that case. Note that the + // frame object itself is also frequently not even tracked by the GC + // starting with Python 3.7 (frames are allocated by the + // interpreter untracked, and only become tracked when their + // evaluation is finished if they have a refcount > 1). All of + // this is to say that we should probably strongly reference + // the frame object. Doing so, while always allowing GC on a + // greenlet, solves several leaks for us. + + Py_VISIT(self->dict); + if (!self->pimpl) { + // Hmm. I have seen this at interpreter shutdown time, + // I think. That's very odd because this doesn't go away until + // we're ``green_dealloc()``, at which point we shouldn't be + // traversed anymore. + return 0; + } + + return self->pimpl->tp_traverse(visit, arg); +} + +static int +green_is_gc(PyObject* _self) +{ + BorrowedGreenlet self(_self); + int result = 0; + /* Main greenlet can be garbage collected since it can only + become unreachable if the underlying thread exited. + Active greenlets --- including those that are suspended --- + cannot be garbage collected, however. + */ + if (self->main() || !self->active()) { + result = 1; + } + // The main greenlet pointer will eventually go away after the thread dies. + if (self->was_running_in_dead_thread()) { + // Our thread is dead! We can never run again. Might as well + // GC us. Note that if a tuple containing only us and other + // immutable objects had been scanned before this, when we + // would have returned 0, the tuple will take itself out of GC + // tracking and never be investigated again. So that could + // result in both us and the tuple leaking due to an + // unreachable/uncollectible reference. The same goes for + // dictionaries. + // + // It's not a great idea to be changing our GC state on the + // fly. + result = 1; + } + return result; +} + + +static int +green_clear(PyGreenlet* self) +{ + /* Greenlet is only cleared if it is about to be collected. + Since active greenlets are not garbage collectable, we can + be sure that, even if they are deallocated during clear, + nothing they reference is in unreachable or finalizers, + so even if it switches we are relatively safe. */ + // XXX: Are we responsible for clearing weakrefs here? + Py_CLEAR(self->dict); + return self->pimpl->tp_clear(); +} + +/** + * Returns 0 on failure (the object was resurrected) or 1 on success. + **/ +static int +_green_dealloc_kill_started_non_main_greenlet(BorrowedGreenlet self) +{ + /* Hacks hacks hacks copied from instance_dealloc() */ + /* Temporarily resurrect the greenlet. */ + assert(self.REFCNT() == 0); + Py_SET_REFCNT(self.borrow(), 1); + /* Save the current exception, if any. */ + PyErrPieces saved_err; + try { + // BY THE TIME WE GET HERE, the state may actually be going + // away + // if we're shutting down the interpreter and freeing thread + // entries, + // this could result in freeing greenlets that were leaked. So + // we can't try to read the state. + self->deallocing_greenlet_in_thread( + self->thread_state() + ? static_cast(GET_THREAD_STATE()) + : nullptr); + } + catch (const PyErrOccurred&) { + PyErr_WriteUnraisable(self.borrow_o()); + /* XXX what else should we do? */ + } + /* Check for no resurrection must be done while we keep + * our internal reference, otherwise PyFile_WriteObject + * causes recursion if using Py_INCREF/Py_DECREF + */ + if (self.REFCNT() == 1 && self->active()) { + /* Not resurrected, but still not dead! + XXX what else should we do? we complain. */ + PyObject* f = PySys_GetObject("stderr"); + Py_INCREF(self.borrow_o()); /* leak! */ + if (f != NULL) { + PyFile_WriteString("GreenletExit did not kill ", f); + PyFile_WriteObject(self.borrow_o(), f, 0); + PyFile_WriteString("\n", f); + } + } + /* Restore the saved exception. */ + saved_err.PyErrRestore(); + /* Undo the temporary resurrection; can't use DECREF here, + * it would cause a recursive call. + */ + assert(self.REFCNT() > 0); + + Py_ssize_t refcnt = self.REFCNT() - 1; + Py_SET_REFCNT(self.borrow_o(), refcnt); + if (refcnt != 0) { + /* Resurrected! */ + _Py_NewReference(self.borrow_o()); + Py_SET_REFCNT(self.borrow_o(), refcnt); + /* Better to use tp_finalizer slot (PEP 442) + * and call ``PyObject_CallFinalizerFromDealloc``, + * but that's only supported in Python 3.4+; see + * Modules/_io/iobase.c for an example. + * + * The following approach is copied from iobase.c in CPython 2.7. + * (along with much of this function in general). Here's their + * comment: + * + * When called from a heap type's dealloc, the type will be + * decref'ed on return (see e.g. subtype_dealloc in typeobject.c). */ + if (PyType_HasFeature(self.TYPE(), Py_TPFLAGS_HEAPTYPE)) { + Py_INCREF(self.TYPE()); + } + + PyObject_GC_Track((PyObject*)self); + + _Py_DEC_REFTOTAL; +#ifdef COUNT_ALLOCS + --Py_TYPE(self)->tp_frees; + --Py_TYPE(self)->tp_allocs; +#endif /* COUNT_ALLOCS */ + return 0; + } + return 1; +} + + +static void +green_dealloc(PyGreenlet* self) +{ + PyObject_GC_UnTrack(self); + BorrowedGreenlet me(self); + if (me->active() + && me->started() + && !me->main()) { + if (!_green_dealloc_kill_started_non_main_greenlet(me)) { + return; + } + } + + if (self->weakreflist != NULL) { + PyObject_ClearWeakRefs((PyObject*)self); + } + Py_CLEAR(self->dict); + + if (self->pimpl) { + // In case deleting this, which frees some memory, + // somehow winds up calling back into us. That's usually a + //bug in our code. + Greenlet* p = self->pimpl; + self->pimpl = nullptr; + delete p; + } + // and finally we're done. self is now invalid. + Py_TYPE(self)->tp_free((PyObject*)self); +} + + + +static OwnedObject +internal_green_throw(BorrowedGreenlet self, PyErrPieces& err_pieces) +{ + PyObject* result = nullptr; + err_pieces.PyErrRestore(); + assert(PyErr_Occurred()); + if (self->started() && !self->active()) { + /* dead greenlet: turn GreenletExit into a regular return */ + result = g_handle_exit(OwnedObject()).relinquish_ownership(); + } + self->args() <<= result; + + return single_result(self->g_switch()); +} + + + +PyDoc_STRVAR( + green_switch_doc, + "switch(*args, **kwargs)\n" + "\n" + "Switch execution to this greenlet.\n" + "\n" + "If this greenlet has never been run, then this greenlet\n" + "will be switched to using the body of ``self.run(*args, **kwargs)``.\n" + "\n" + "If the greenlet is active (has been run, but was switch()'ed\n" + "out before leaving its run function), then this greenlet will\n" + "be resumed and the return value to its switch call will be\n" + "None if no arguments are given, the given argument if one\n" + "argument is given, or the args tuple and keyword args dict if\n" + "multiple arguments are given.\n" + "\n" + "If the greenlet is dead, or is the current greenlet then this\n" + "function will simply return the arguments using the same rules as\n" + "above.\n"); + +static PyObject* +green_switch(PyGreenlet* self, PyObject* args, PyObject* kwargs) +{ + using greenlet::SwitchingArgs; + SwitchingArgs switch_args(OwnedObject::owning(args), OwnedObject::owning(kwargs)); + self->pimpl->may_switch_away(); + self->pimpl->args() <<= switch_args; + + // If we're switching out of a greenlet, and that switch is the + // last thing the greenlet does, the greenlet ought to be able to + // go ahead and die at that point. Currently, someone else must + // manually switch back to the greenlet so that we "fall off the + // end" and can perform cleanup. You'd think we'd be able to + // figure out that this is happening using the frame's ``f_lasti`` + // member, which is supposed to be an index into + // ``frame->f_code->co_code``, the bytecode string. However, in + // recent interpreters, ``f_lasti`` tends not to be updated thanks + // to things like the PREDICT() macros in ceval.c. So it doesn't + // really work to do that in many cases. For example, the Python + // code: + // def run(): + // greenlet.getcurrent().parent.switch() + // produces bytecode of len 16, with the actual call to switch() + // being at index 10 (in Python 3.10). However, the reported + // ``f_lasti`` we actually see is...5! (Which happens to be the + // second byte of the CALL_METHOD op for ``getcurrent()``). + + try { + //OwnedObject result = single_result(self->pimpl->g_switch()); + OwnedObject result(single_result(self->pimpl->g_switch())); +#ifndef NDEBUG + // Note that the current greenlet isn't necessarily self. If self + // finished, we went to one of its parents. + assert(!self->pimpl->args()); + + const BorrowedGreenlet& current = GET_THREAD_STATE().state().borrow_current(); + // It's possible it's never been switched to. + assert(!current->args()); +#endif + PyObject* p = result.relinquish_ownership(); + + if (!p && !PyErr_Occurred()) { + // This shouldn't be happening anymore, so the asserts + // are there for debug builds. Non-debug builds + // crash "gracefully" in this case, although there is an + // argument to be made for killing the process in all + // cases --- for this to be the case, our switches + // probably nested in an incorrect way, so the state is + // suspicious. Nothing should be corrupt though, just + // confused at the Python level. Letting this propagate is + // probably good enough. + assert(p || PyErr_Occurred()); + throw PyErrOccurred( + mod_globs->PyExc_GreenletError, + "Greenlet.switch() returned NULL without an exception set." + ); + } + return p; + } + catch(const PyErrOccurred&) { + return nullptr; + } +} + +PyDoc_STRVAR( + green_throw_doc, + "Switches execution to this greenlet, but immediately raises the\n" + "given exception in this greenlet. If no argument is provided, the " + "exception\n" + "defaults to `greenlet.GreenletExit`. The normal exception\n" + "propagation rules apply, as described for `switch`. Note that calling " + "this\n" + "method is almost equivalent to the following::\n" + "\n" + " def raiser():\n" + " raise typ, val, tb\n" + " g_raiser = greenlet(raiser, parent=g)\n" + " g_raiser.switch()\n" + "\n" + "except that this trick does not work for the\n" + "`greenlet.GreenletExit` exception, which would not propagate\n" + "from ``g_raiser`` to ``g``.\n"); + +static PyObject* +green_throw(PyGreenlet* self, PyObject* args) +{ + PyArgParseParam typ(mod_globs->PyExc_GreenletExit); + PyArgParseParam val; + PyArgParseParam tb; + + if (!PyArg_ParseTuple(args, "|OOO:throw", &typ, &val, &tb)) { + return nullptr; + } + + assert(typ.borrow() || val.borrow()); + + self->pimpl->may_switch_away(); + try { + // Both normalizing the error and the actual throw_greenlet + // could throw PyErrOccurred. + PyErrPieces err_pieces(typ.borrow(), val.borrow(), tb.borrow()); + + return internal_green_throw(self, err_pieces).relinquish_ownership(); + } + catch (const PyErrOccurred&) { + return nullptr; + } +} + +static int +green_bool(PyGreenlet* self) +{ + return self->pimpl->active(); +} + +/** + * CAUTION: Allocates memory, may run GC and arbitrary Python code. + */ +static PyObject* +green_getdict(PyGreenlet* self, void* UNUSED(context)) +{ + if (self->dict == NULL) { + self->dict = PyDict_New(); + if (self->dict == NULL) { + return NULL; + } + } + Py_INCREF(self->dict); + return self->dict; +} + +static int +green_setdict(PyGreenlet* self, PyObject* val, void* UNUSED(context)) +{ + PyObject* tmp; + + if (val == NULL) { + PyErr_SetString(PyExc_TypeError, "__dict__ may not be deleted"); + return -1; + } + if (!PyDict_Check(val)) { + PyErr_SetString(PyExc_TypeError, "__dict__ must be a dictionary"); + return -1; + } + tmp = self->dict; + Py_INCREF(val); + self->dict = val; + Py_XDECREF(tmp); + return 0; +} + +static bool +_green_not_dead(BorrowedGreenlet self) +{ + // XXX: Where else should we do this? + // Probably on entry to most Python-facing functions? + if (self->was_running_in_dead_thread()) { + self->deactivate_and_free(); + return false; + } + return self->active() || !self->started(); +} + + +static PyObject* +green_getdead(PyGreenlet* self, void* UNUSED(context)) +{ + if (_green_not_dead(self)) { + Py_RETURN_FALSE; + } + else { + Py_RETURN_TRUE; + } +} + +static PyObject* +green_get_stack_saved(PyGreenlet* self, void* UNUSED(context)) +{ + return PyLong_FromSsize_t(self->pimpl->stack_saved()); +} + + +static PyObject* +green_getrun(PyGreenlet* self, void* UNUSED(context)) +{ + try { + OwnedObject result(BorrowedGreenlet(self)->run()); + return result.relinquish_ownership(); + } + catch(const PyErrOccurred&) { + return nullptr; + } +} + + +static int +green_setrun(PyGreenlet* self, PyObject* nrun, void* UNUSED(context)) +{ + try { + BorrowedGreenlet(self)->run(nrun); + return 0; + } + catch(const PyErrOccurred&) { + return -1; + } +} + +static PyObject* +green_getparent(PyGreenlet* self, void* UNUSED(context)) +{ + return BorrowedGreenlet(self)->parent().acquire_or_None(); +} + + +static int +green_setparent(PyGreenlet* self, PyObject* nparent, void* UNUSED(context)) +{ + try { + BorrowedGreenlet(self)->parent(nparent); + } + catch(const PyErrOccurred&) { + return -1; + } + return 0; +} + + +static PyObject* +green_getcontext(const PyGreenlet* self, void* UNUSED(context)) +{ + const Greenlet *const g = self->pimpl; + try { + OwnedObject result(g->context()); + return result.relinquish_ownership(); + } + catch(const PyErrOccurred&) { + return nullptr; + } +} + +static int +green_setcontext(PyGreenlet* self, PyObject* nctx, void* UNUSED(context)) +{ + try { + BorrowedGreenlet(self)->context(nctx); + return 0; + } + catch(const PyErrOccurred&) { + return -1; + } +} + + +static PyObject* +green_getframe(PyGreenlet* self, void* UNUSED(context)) +{ + const PythonState::OwnedFrame& top_frame = BorrowedGreenlet(self)->top_frame(); + return top_frame.acquire_or_None(); +} + + +static PyObject* +green_getstate(PyGreenlet* self) +{ + PyErr_Format(PyExc_TypeError, + "cannot serialize '%s' object", + Py_TYPE(self)->tp_name); + return nullptr; +} + +static PyObject* +green_repr(PyGreenlet* _self) +{ + BorrowedGreenlet self(_self); + /* + Return a string like + + + The handling of greenlets across threads is not super good. + We mostly use the internal definitions of these terms, but they + generally should make sense to users as well. + */ + PyObject* result; + int never_started = !self->started() && !self->active(); + + const char* const tp_name = Py_TYPE(self)->tp_name; + + if (_green_not_dead(self)) { + /* XXX: The otid= is almost useless because you can't correlate it to + any thread identifier exposed to Python. We could use + PyThreadState_GET()->thread_id, but we'd need to save that in the + greenlet, or save the whole PyThreadState object itself. + + As it stands, its only useful for identifying greenlets from the same thread. + */ + const char* state_in_thread; + if (self->was_running_in_dead_thread()) { + // The thread it was running in is dead! + // This can happen, especially at interpreter shut down. + // It complicates debugging output because it may be + // impossible to access the current thread state at that + // time. Thus, don't access the current thread state. + state_in_thread = " (thread exited)"; + } + else { + state_in_thread = GET_THREAD_STATE().state().is_current(self) + ? " current" + : (self->started() ? " suspended" : ""); + } + result = PyUnicode_FromFormat( + "<%s object at %p (otid=%p)%s%s%s%s>", + tp_name, + self.borrow_o(), + self->thread_state(), + state_in_thread, + self->active() ? " active" : "", + never_started ? " pending" : " started", + self->main() ? " main" : "" + ); + } + else { + result = PyUnicode_FromFormat( + "<%s object at %p (otid=%p) %sdead>", + tp_name, + self.borrow_o(), + self->thread_state(), + self->was_running_in_dead_thread() + ? "(thread exited) " + : "" + ); + } + + return result; +} + + +static PyMethodDef green_methods[] = { + { + .ml_name="switch", + .ml_meth=reinterpret_cast(green_switch), + .ml_flags=METH_VARARGS | METH_KEYWORDS, + .ml_doc=green_switch_doc + }, + {.ml_name="throw", .ml_meth=(PyCFunction)green_throw, .ml_flags=METH_VARARGS, .ml_doc=green_throw_doc}, + {.ml_name="__getstate__", .ml_meth=(PyCFunction)green_getstate, .ml_flags=METH_NOARGS, .ml_doc=NULL}, + {.ml_name=NULL, .ml_meth=NULL} /* sentinel */ +}; + +static PyGetSetDef green_getsets[] = { + /* name, getter, setter, doc, context pointer */ + {.name="__dict__", .get=(getter)green_getdict, .set=(setter)green_setdict}, + {.name="run", .get=(getter)green_getrun, .set=(setter)green_setrun}, + {.name="parent", .get=(getter)green_getparent, .set=(setter)green_setparent}, + {.name="gr_frame", .get=(getter)green_getframe }, + { + .name="gr_context", + .get=(getter)green_getcontext, + .set=(setter)green_setcontext + }, + {.name="dead", .get=(getter)green_getdead}, + {.name="_stack_saved", .get=(getter)green_get_stack_saved}, + {.name=NULL} +}; + +static PyMemberDef green_members[] = { + {.name=NULL} +}; + +static PyNumberMethods green_as_number = { + .nb_bool=(inquiry)green_bool, +}; + + +PyTypeObject PyGreenlet_Type = { + .ob_base=PyVarObject_HEAD_INIT(NULL, 0) + .tp_name="greenlet.greenlet", /* tp_name */ + .tp_basicsize=sizeof(PyGreenlet), /* tp_basicsize */ + /* methods */ + .tp_dealloc=(destructor)green_dealloc, /* tp_dealloc */ + .tp_repr=(reprfunc)green_repr, /* tp_repr */ + .tp_as_number=&green_as_number, /* tp_as _number*/ + .tp_flags=G_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /* tp_flags */ + .tp_doc="greenlet(run=None, parent=None) -> greenlet\n\n" + "Creates a new greenlet object (without running it).\n\n" + " - *run* -- The callable to invoke.\n" + " - *parent* -- The parent greenlet. The default is the current " + "greenlet.", /* tp_doc */ + .tp_traverse=(traverseproc)green_traverse, /* tp_traverse */ + .tp_clear=(inquiry)green_clear, /* tp_clear */ + .tp_weaklistoffset=offsetof(PyGreenlet, weakreflist), /* tp_weaklistoffset */ + + .tp_methods=green_methods, /* tp_methods */ + .tp_members=green_members, /* tp_members */ + .tp_getset=green_getsets, /* tp_getset */ + .tp_dictoffset=offsetof(PyGreenlet, dict), /* tp_dictoffset */ + .tp_init=(initproc)green_init, /* tp_init */ + .tp_alloc=PyType_GenericAlloc, /* tp_alloc */ + .tp_new=(newfunc)green_new, /* tp_new */ + .tp_free=PyObject_GC_Del, /* tp_free */ + .tp_is_gc=(inquiry)green_is_gc, /* tp_is_gc */ +}; + +#endif + +// Local Variables: +// flycheck-clang-include-path: ("/opt/local/Library/Frameworks/Python.framework/Versions/3.8/include/python3.8") +// End: diff --git a/psets/9/finance/env/lib/python3.12/site-packages/greenlet/PyGreenlet.hpp b/psets/9/finance/env/lib/python3.12/site-packages/greenlet/PyGreenlet.hpp new file mode 100644 index 0000000..df6cd80 --- /dev/null +++ b/psets/9/finance/env/lib/python3.12/site-packages/greenlet/PyGreenlet.hpp @@ -0,0 +1,35 @@ +#ifndef PYGREENLET_HPP +#define PYGREENLET_HPP + + +#include "greenlet.h" +#include "greenlet_compiler_compat.hpp" +#include "greenlet_refs.hpp" + + +using greenlet::refs::OwnedGreenlet; +using greenlet::refs::BorrowedGreenlet; +using greenlet::refs::BorrowedObject;; +using greenlet::refs::OwnedObject; +using greenlet::refs::PyErrPieces; + + +// XXX: These doesn't really belong here, it's not a Python slot. +static OwnedObject internal_green_throw(BorrowedGreenlet self, PyErrPieces& err_pieces); + +static PyGreenlet* green_new(PyTypeObject* type, PyObject* UNUSED(args), PyObject* UNUSED(kwds)); +static int green_clear(PyGreenlet* self); +static int green_init(PyGreenlet* self, PyObject* args, PyObject* kwargs); +static int green_setparent(PyGreenlet* self, PyObject* nparent, void* UNUSED(context)); +static int green_setrun(PyGreenlet* self, PyObject* nrun, void* UNUSED(context)); +static int green_traverse(PyGreenlet* self, visitproc visit, void* arg); +static void green_dealloc(PyGreenlet* self); +static PyObject* green_getparent(PyGreenlet* self, void* UNUSED(context)); + +static int green_is_gc(PyObject* self); +static PyObject* green_getdead(PyGreenlet* self, void* UNUSED(context)); +static PyObject* green_getrun(PyGreenlet* self, void* UNUSED(context)); +static int green_setcontext(PyGreenlet* self, PyObject* nctx, void* UNUSED(context)); +static PyObject* green_getframe(PyGreenlet* self, void* UNUSED(context)); +static PyObject* green_repr(PyGreenlet* self); +#endif diff --git a/psets/9/finance/env/lib/python3.12/site-packages/greenlet/PyGreenletUnswitchable.cpp b/psets/9/finance/env/lib/python3.12/site-packages/greenlet/PyGreenletUnswitchable.cpp new file mode 100644 index 0000000..1b768ee --- /dev/null +++ b/psets/9/finance/env/lib/python3.12/site-packages/greenlet/PyGreenletUnswitchable.cpp @@ -0,0 +1,147 @@ +/* -*- indent-tabs-mode: nil; tab-width: 4; -*- */ +/** + Implementation of the Python slots for PyGreenletUnswitchable_Type +*/ +#ifndef PY_GREENLET_UNSWITCHABLE_CPP +#define PY_GREENLET_UNSWITCHABLE_CPP + + + +#define PY_SSIZE_T_CLEAN +#include +#include "structmember.h" // PyMemberDef + +#include "greenlet_internal.hpp" +// Code after this point can assume access to things declared in stdint.h, +// including the fixed-width types. This goes for the platform-specific switch functions +// as well. +#include "greenlet_refs.hpp" +#include "greenlet_slp_switch.hpp" + +#include "greenlet_thread_support.hpp" +#include "TGreenlet.hpp" + +#include "TGreenlet.cpp" +#include "TGreenletGlobals.cpp" +#include "TThreadStateDestroy.cpp" + + +using greenlet::LockGuard; +using greenlet::LockInitError; +using greenlet::PyErrOccurred; +using greenlet::Require; + +using greenlet::g_handle_exit; +using greenlet::single_result; + +using greenlet::Greenlet; +using greenlet::UserGreenlet; +using greenlet::MainGreenlet; +using greenlet::BrokenGreenlet; +using greenlet::ThreadState; +using greenlet::PythonState; + + +#include "PyGreenlet.hpp" + +static PyGreenlet* +green_unswitchable_new(PyTypeObject* type, PyObject* UNUSED(args), PyObject* UNUSED(kwds)) +{ + PyGreenlet* o = + (PyGreenlet*)PyBaseObject_Type.tp_new(type, mod_globs->empty_tuple, mod_globs->empty_dict); + if (o) { + new BrokenGreenlet(o, GET_THREAD_STATE().state().borrow_current()); + assert(Py_REFCNT(o) == 1); + } + return o; +} + +static PyObject* +green_unswitchable_getforce(PyGreenlet* self, void* UNUSED(context)) +{ + BrokenGreenlet* broken = dynamic_cast(self->pimpl); + return PyBool_FromLong(broken->_force_switch_error); +} + +static int +green_unswitchable_setforce(PyGreenlet* self, PyObject* nforce, void* UNUSED(context)) +{ + if (!nforce) { + PyErr_SetString( + PyExc_AttributeError, + "Cannot delete force_switch_error" + ); + return -1; + } + BrokenGreenlet* broken = dynamic_cast(self->pimpl); + int is_true = PyObject_IsTrue(nforce); + if (is_true == -1) { + return -1; + } + broken->_force_switch_error = is_true; + return 0; +} + +static PyObject* +green_unswitchable_getforceslp(PyGreenlet* self, void* UNUSED(context)) +{ + BrokenGreenlet* broken = dynamic_cast(self->pimpl); + return PyBool_FromLong(broken->_force_slp_switch_error); +} + +static int +green_unswitchable_setforceslp(PyGreenlet* self, PyObject* nforce, void* UNUSED(context)) +{ + if (!nforce) { + PyErr_SetString( + PyExc_AttributeError, + "Cannot delete force_slp_switch_error" + ); + return -1; + } + BrokenGreenlet* broken = dynamic_cast(self->pimpl); + int is_true = PyObject_IsTrue(nforce); + if (is_true == -1) { + return -1; + } + broken->_force_slp_switch_error = is_true; + return 0; +} + +static PyGetSetDef green_unswitchable_getsets[] = { + /* name, getter, setter, doc, closure (context pointer) */ + { + .name="force_switch_error", + .get=(getter)green_unswitchable_getforce, + .set=(setter)green_unswitchable_setforce, + .doc=NULL + }, + { + .name="force_slp_switch_error", + .get=(getter)green_unswitchable_getforceslp, + .set=(setter)green_unswitchable_setforceslp, + .doc=nullptr + }, + {.name=nullptr} +}; + +PyTypeObject PyGreenletUnswitchable_Type = { + .ob_base=PyVarObject_HEAD_INIT(NULL, 0) + .tp_name="greenlet._greenlet.UnswitchableGreenlet", + .tp_dealloc= (destructor)green_dealloc, /* tp_dealloc */ + .tp_flags=G_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /* tp_flags */ + .tp_doc="Undocumented internal class", /* tp_doc */ + .tp_traverse=(traverseproc)green_traverse, /* tp_traverse */ + .tp_clear=(inquiry)green_clear, /* tp_clear */ + + .tp_getset=green_unswitchable_getsets, /* tp_getset */ + .tp_base=&PyGreenlet_Type, /* tp_base */ + .tp_init=(initproc)green_init, /* tp_init */ + .tp_alloc=PyType_GenericAlloc, /* tp_alloc */ + .tp_new=(newfunc)green_unswitchable_new, /* tp_new */ + .tp_free=PyObject_GC_Del, /* tp_free */ + .tp_is_gc=(inquiry)green_is_gc, /* tp_is_gc */ +}; + + +#endif diff --git a/psets/9/finance/env/lib/python3.12/site-packages/greenlet/PyModule.cpp b/psets/9/finance/env/lib/python3.12/site-packages/greenlet/PyModule.cpp new file mode 100644 index 0000000..6adcb5c --- /dev/null +++ b/psets/9/finance/env/lib/python3.12/site-packages/greenlet/PyModule.cpp @@ -0,0 +1,292 @@ +#ifndef PY_MODULE_CPP +#define PY_MODULE_CPP + +#include "greenlet_internal.hpp" + + +#include "TGreenletGlobals.cpp" +#include "TMainGreenlet.cpp" +#include "TThreadStateDestroy.cpp" + +using greenlet::LockGuard; +using greenlet::ThreadState; + +#ifdef __clang__ +# pragma clang diagnostic push +# pragma clang diagnostic ignored "-Wunused-function" +# pragma clang diagnostic ignored "-Wunused-variable" +#endif + +PyDoc_STRVAR(mod_getcurrent_doc, + "getcurrent() -> greenlet\n" + "\n" + "Returns the current greenlet (i.e. the one which called this " + "function).\n"); + +static PyObject* +mod_getcurrent(PyObject* UNUSED(module)) +{ + return GET_THREAD_STATE().state().get_current().relinquish_ownership_o(); +} + +PyDoc_STRVAR(mod_settrace_doc, + "settrace(callback) -> object\n" + "\n" + "Sets a new tracing function and returns the previous one.\n"); +static PyObject* +mod_settrace(PyObject* UNUSED(module), PyObject* args) +{ + PyArgParseParam tracefunc; + if (!PyArg_ParseTuple(args, "O", &tracefunc)) { + return NULL; + } + ThreadState& state = GET_THREAD_STATE(); + OwnedObject previous = state.get_tracefunc(); + if (!previous) { + previous = Py_None; + } + + state.set_tracefunc(tracefunc); + + return previous.relinquish_ownership(); +} + +PyDoc_STRVAR(mod_gettrace_doc, + "gettrace() -> object\n" + "\n" + "Returns the currently set tracing function, or None.\n"); + +static PyObject* +mod_gettrace(PyObject* UNUSED(module)) +{ + OwnedObject tracefunc = GET_THREAD_STATE().state().get_tracefunc(); + if (!tracefunc) { + tracefunc = Py_None; + } + return tracefunc.relinquish_ownership(); +} + + + +PyDoc_STRVAR(mod_set_thread_local_doc, + "set_thread_local(key, value) -> None\n" + "\n" + "Set a value in the current thread-local dictionary. Debugging only.\n"); + +static PyObject* +mod_set_thread_local(PyObject* UNUSED(module), PyObject* args) +{ + PyArgParseParam key; + PyArgParseParam value; + PyObject* result = NULL; + + if (PyArg_UnpackTuple(args, "set_thread_local", 2, 2, &key, &value)) { + if(PyDict_SetItem( + PyThreadState_GetDict(), // borrow + key, + value) == 0 ) { + // success + Py_INCREF(Py_None); + result = Py_None; + } + } + return result; +} + +PyDoc_STRVAR(mod_get_pending_cleanup_count_doc, + "get_pending_cleanup_count() -> Integer\n" + "\n" + "Get the number of greenlet cleanup operations pending. Testing only.\n"); + + +static PyObject* +mod_get_pending_cleanup_count(PyObject* UNUSED(module)) +{ + LockGuard cleanup_lock(*mod_globs->thread_states_to_destroy_lock); + return PyLong_FromSize_t(mod_globs->thread_states_to_destroy.size()); +} + +PyDoc_STRVAR(mod_get_total_main_greenlets_doc, + "get_total_main_greenlets() -> Integer\n" + "\n" + "Quickly return the number of main greenlets that exist. Testing only.\n"); + +static PyObject* +mod_get_total_main_greenlets(PyObject* UNUSED(module)) +{ + return PyLong_FromSize_t(G_TOTAL_MAIN_GREENLETS); +} + + + +PyDoc_STRVAR(mod_get_clocks_used_doing_optional_cleanup_doc, + "get_clocks_used_doing_optional_cleanup() -> Integer\n" + "\n" + "Get the number of clock ticks the program has used doing optional " + "greenlet cleanup.\n" + "Beginning in greenlet 2.0, greenlet tries to find and dispose of greenlets\n" + "that leaked after a thread exited. This requires invoking Python's garbage collector,\n" + "which may have a performance cost proportional to the number of live objects.\n" + "This function returns the amount of processor time\n" + "greenlet has used to do this. In programs that run with very large amounts of live\n" + "objects, this metric can be used to decide whether the cost of doing this cleanup\n" + "is worth the memory leak being corrected. If not, you can disable the cleanup\n" + "using ``enable_optional_cleanup(False)``.\n" + "The units are arbitrary and can only be compared to themselves (similarly to ``time.clock()``);\n" + "for example, to see how it scales with your heap. You can attempt to convert them into seconds\n" + "by dividing by the value of CLOCKS_PER_SEC." + "If cleanup has been disabled, returns None." + "\n" + "This is an implementation specific, provisional API. It may be changed or removed\n" + "in the future.\n" + ".. versionadded:: 2.0" + ); +static PyObject* +mod_get_clocks_used_doing_optional_cleanup(PyObject* UNUSED(module)) +{ + std::clock_t& clocks = ThreadState::clocks_used_doing_gc(); + + if (clocks == std::clock_t(-1)) { + Py_RETURN_NONE; + } + // This might not actually work on some implementations; clock_t + // is an opaque type. + return PyLong_FromSsize_t(clocks); +} + +PyDoc_STRVAR(mod_enable_optional_cleanup_doc, + "mod_enable_optional_cleanup(bool) -> None\n" + "\n" + "Enable or disable optional cleanup operations.\n" + "See ``get_clocks_used_doing_optional_cleanup()`` for details.\n" + ); +static PyObject* +mod_enable_optional_cleanup(PyObject* UNUSED(module), PyObject* flag) +{ + int is_true = PyObject_IsTrue(flag); + if (is_true == -1) { + return nullptr; + } + + std::clock_t& clocks = ThreadState::clocks_used_doing_gc(); + if (is_true) { + // If we already have a value, we don't want to lose it. + if (clocks == std::clock_t(-1)) { + clocks = 0; + } + } + else { + clocks = std::clock_t(-1); + } + Py_RETURN_NONE; +} + + + + +#if !GREENLET_PY313 +PyDoc_STRVAR(mod_get_tstate_trash_delete_nesting_doc, + "get_tstate_trash_delete_nesting() -> Integer\n" + "\n" + "Return the 'trash can' nesting level. Testing only.\n"); +static PyObject* +mod_get_tstate_trash_delete_nesting(PyObject* UNUSED(module)) +{ + PyThreadState* tstate = PyThreadState_GET(); + +#if GREENLET_PY312 + return PyLong_FromLong(tstate->trash.delete_nesting); +#else + return PyLong_FromLong(tstate->trash_delete_nesting); +#endif +} +#endif + + + + +static PyMethodDef GreenMethods[] = { + { + .ml_name="getcurrent", + .ml_meth=(PyCFunction)mod_getcurrent, + .ml_flags=METH_NOARGS, + .ml_doc=mod_getcurrent_doc + }, + { + .ml_name="settrace", + .ml_meth=(PyCFunction)mod_settrace, + .ml_flags=METH_VARARGS, + .ml_doc=mod_settrace_doc + }, + { + .ml_name="gettrace", + .ml_meth=(PyCFunction)mod_gettrace, + .ml_flags=METH_NOARGS, + .ml_doc=mod_gettrace_doc + }, + { + .ml_name="set_thread_local", + .ml_meth=(PyCFunction)mod_set_thread_local, + .ml_flags=METH_VARARGS, + .ml_doc=mod_set_thread_local_doc + }, + { + .ml_name="get_pending_cleanup_count", + .ml_meth=(PyCFunction)mod_get_pending_cleanup_count, + .ml_flags=METH_NOARGS, + .ml_doc=mod_get_pending_cleanup_count_doc + }, + { + .ml_name="get_total_main_greenlets", + .ml_meth=(PyCFunction)mod_get_total_main_greenlets, + .ml_flags=METH_NOARGS, + .ml_doc=mod_get_total_main_greenlets_doc + }, + { + .ml_name="get_clocks_used_doing_optional_cleanup", + .ml_meth=(PyCFunction)mod_get_clocks_used_doing_optional_cleanup, + .ml_flags=METH_NOARGS, + .ml_doc=mod_get_clocks_used_doing_optional_cleanup_doc + }, + { + .ml_name="enable_optional_cleanup", + .ml_meth=(PyCFunction)mod_enable_optional_cleanup, + .ml_flags=METH_O, + .ml_doc=mod_enable_optional_cleanup_doc + }, +#if !GREENLET_PY313 + { + .ml_name="get_tstate_trash_delete_nesting", + .ml_meth=(PyCFunction)mod_get_tstate_trash_delete_nesting, + .ml_flags=METH_NOARGS, + .ml_doc=mod_get_tstate_trash_delete_nesting_doc + }, +#endif + {.ml_name=NULL, .ml_meth=NULL} /* Sentinel */ +}; + +static const char* const copy_on_greentype[] = { + "getcurrent", + "error", + "GreenletExit", + "settrace", + "gettrace", + NULL +}; + +static struct PyModuleDef greenlet_module_def = { + .m_base=PyModuleDef_HEAD_INIT, + .m_name="greenlet._greenlet", + .m_doc=NULL, + .m_size=-1, + .m_methods=GreenMethods, +}; + + +#endif + +#ifdef __clang__ +# pragma clang diagnostic pop +#elif defined(__GNUC__) +# pragma GCC diagnostic pop +#endif diff --git a/psets/9/finance/env/lib/python3.12/site-packages/greenlet/TBrokenGreenlet.cpp b/psets/9/finance/env/lib/python3.12/site-packages/greenlet/TBrokenGreenlet.cpp new file mode 100644 index 0000000..7e9ab5b --- /dev/null +++ b/psets/9/finance/env/lib/python3.12/site-packages/greenlet/TBrokenGreenlet.cpp @@ -0,0 +1,45 @@ +/* -*- indent-tabs-mode: nil; tab-width: 4; -*- */ +/** + * Implementation of greenlet::UserGreenlet. + * + * Format with: + * clang-format -i --style=file src/greenlet/greenlet.c + * + * + * Fix missing braces with: + * clang-tidy src/greenlet/greenlet.c -fix -checks="readability-braces-around-statements" +*/ + +#include "TGreenlet.hpp" + +namespace greenlet { + +void* BrokenGreenlet::operator new(size_t UNUSED(count)) +{ + return allocator.allocate(1); +} + + +void BrokenGreenlet::operator delete(void* ptr) +{ + return allocator.deallocate(static_cast(ptr), + 1); +} + +greenlet::PythonAllocator greenlet::BrokenGreenlet::allocator; + +bool +BrokenGreenlet::force_slp_switch_error() const noexcept +{ + return this->_force_slp_switch_error; +} + +UserGreenlet::switchstack_result_t BrokenGreenlet::g_switchstack(void) +{ + if (this->_force_switch_error) { + return switchstack_result_t(-1); + } + return UserGreenlet::g_switchstack(); +} + +}; //namespace greenlet diff --git a/psets/9/finance/env/lib/python3.12/site-packages/greenlet/TExceptionState.cpp b/psets/9/finance/env/lib/python3.12/site-packages/greenlet/TExceptionState.cpp new file mode 100644 index 0000000..08a94ae --- /dev/null +++ b/psets/9/finance/env/lib/python3.12/site-packages/greenlet/TExceptionState.cpp @@ -0,0 +1,62 @@ +#ifndef GREENLET_EXCEPTION_STATE_CPP +#define GREENLET_EXCEPTION_STATE_CPP + +#include +#include "TGreenlet.hpp" + +namespace greenlet { + + +ExceptionState::ExceptionState() +{ + this->clear(); +} + +void ExceptionState::operator<<(const PyThreadState *const tstate) noexcept +{ + this->exc_info = tstate->exc_info; + this->exc_state = tstate->exc_state; +} + +void ExceptionState::operator>>(PyThreadState *const tstate) noexcept +{ + tstate->exc_state = this->exc_state; + tstate->exc_info = + this->exc_info ? this->exc_info : &tstate->exc_state; + this->clear(); +} + +void ExceptionState::clear() noexcept +{ + this->exc_info = nullptr; + this->exc_state.exc_value = nullptr; +#if !GREENLET_PY311 + this->exc_state.exc_type = nullptr; + this->exc_state.exc_traceback = nullptr; +#endif + this->exc_state.previous_item = nullptr; +} + +int ExceptionState::tp_traverse(visitproc visit, void* arg) noexcept +{ + Py_VISIT(this->exc_state.exc_value); +#if !GREENLET_PY311 + Py_VISIT(this->exc_state.exc_type); + Py_VISIT(this->exc_state.exc_traceback); +#endif + return 0; +} + +void ExceptionState::tp_clear() noexcept +{ + Py_CLEAR(this->exc_state.exc_value); +#if !GREENLET_PY311 + Py_CLEAR(this->exc_state.exc_type); + Py_CLEAR(this->exc_state.exc_traceback); +#endif +} + + +}; // namespace greenlet + +#endif // GREENLET_EXCEPTION_STATE_CPP diff --git a/psets/9/finance/env/lib/python3.12/site-packages/greenlet/TGreenlet.cpp b/psets/9/finance/env/lib/python3.12/site-packages/greenlet/TGreenlet.cpp new file mode 100644 index 0000000..4698a17 --- /dev/null +++ b/psets/9/finance/env/lib/python3.12/site-packages/greenlet/TGreenlet.cpp @@ -0,0 +1,718 @@ +/* -*- indent-tabs-mode: nil; tab-width: 4; -*- */ +/** + * Implementation of greenlet::Greenlet. + * + * Format with: + * clang-format -i --style=file src/greenlet/greenlet.c + * + * + * Fix missing braces with: + * clang-tidy src/greenlet/greenlet.c -fix -checks="readability-braces-around-statements" +*/ +#ifndef TGREENLET_CPP +#define TGREENLET_CPP +#include "greenlet_internal.hpp" +#include "TGreenlet.hpp" + + +#include "TGreenletGlobals.cpp" +#include "TThreadStateDestroy.cpp" + +namespace greenlet { + +Greenlet::Greenlet(PyGreenlet* p) + : Greenlet(p, StackState()) +{ +} + +Greenlet::Greenlet(PyGreenlet* p, const StackState& initial_stack) + : _self(p), stack_state(initial_stack) +{ + assert(p->pimpl == nullptr); + p->pimpl = this; +} + +Greenlet::~Greenlet() +{ + // XXX: Can't do this. tp_clear is a virtual function, and by the + // time we're here, we've sliced off our child classes. + //this->tp_clear(); + this->_self->pimpl = nullptr; +} + +bool +Greenlet::force_slp_switch_error() const noexcept +{ + return false; +} + +void +Greenlet::release_args() +{ + this->switch_args.CLEAR(); +} + +/** + * CAUTION: This will allocate memory and may trigger garbage + * collection and arbitrary Python code. + */ +OwnedObject +Greenlet::throw_GreenletExit_during_dealloc(const ThreadState& UNUSED(current_thread_state)) +{ + // If we're killed because we lost all references in the + // middle of a switch, that's ok. Don't reset the args/kwargs, + // we still want to pass them to the parent. + PyErr_SetString(mod_globs->PyExc_GreenletExit, + "Killing the greenlet because all references have vanished."); + // To get here it had to have run before + return this->g_switch(); +} + +inline void +Greenlet::slp_restore_state() noexcept +{ +#ifdef SLP_BEFORE_RESTORE_STATE + SLP_BEFORE_RESTORE_STATE(); +#endif + this->stack_state.copy_heap_to_stack( + this->thread_state()->borrow_current()->stack_state); +} + + +inline int +Greenlet::slp_save_state(char *const stackref) noexcept +{ + // XXX: This used to happen in the middle, before saving, but + // after finding the next owner. Does that matter? This is + // only defined for Sparc/GCC where it flushes register + // windows to the stack (I think) +#ifdef SLP_BEFORE_SAVE_STATE + SLP_BEFORE_SAVE_STATE(); +#endif + return this->stack_state.copy_stack_to_heap(stackref, + this->thread_state()->borrow_current()->stack_state); +} + +/** + * CAUTION: This will allocate memory and may trigger garbage + * collection and arbitrary Python code. + */ +OwnedObject +Greenlet::on_switchstack_or_initialstub_failure( + Greenlet* target, + const Greenlet::switchstack_result_t& err, + const bool target_was_me, + const bool was_initial_stub) +{ + // If we get here, either g_initialstub() + // failed, or g_switchstack() failed. Either one of those + // cases SHOULD leave us in the original greenlet with a valid stack. + if (!PyErr_Occurred()) { + PyErr_SetString( + PyExc_SystemError, + was_initial_stub + ? "Failed to switch stacks into a greenlet for the first time." + : "Failed to switch stacks into a running greenlet."); + } + this->release_args(); + + if (target && !target_was_me) { + target->murder_in_place(); + } + + assert(!err.the_new_current_greenlet); + assert(!err.origin_greenlet); + return OwnedObject(); + +} + +OwnedGreenlet +Greenlet::g_switchstack_success() noexcept +{ + PyThreadState* tstate = PyThreadState_GET(); + // restore the saved state + this->python_state >> tstate; + this->exception_state >> tstate; + + // The thread state hasn't been changed yet. + ThreadState* thread_state = this->thread_state(); + OwnedGreenlet result(thread_state->get_current()); + thread_state->set_current(this->self()); + //assert(thread_state->borrow_current().borrow() == this->_self); + return result; +} + +Greenlet::switchstack_result_t +Greenlet::g_switchstack(void) +{ + // if any of these assertions fail, it's likely because we + // switched away and tried to switch back to us. Early stages of + // switching are not reentrant because we re-use ``this->args()``. + // Switching away would happen if we trigger a garbage collection + // (by just using some Python APIs that happen to allocate Python + // objects) and some garbage had weakref callbacks or __del__ that + // switches (people don't write code like that by hand, but with + // gevent it's possible without realizing it) + assert(this->args() || PyErr_Occurred()); + { /* save state */ + if (this->thread_state()->is_current(this->self())) { + // Hmm, nothing to do. + // TODO: Does this bypass trace events that are + // important? + return switchstack_result_t(0, + this, this->thread_state()->borrow_current()); + } + BorrowedGreenlet current = this->thread_state()->borrow_current(); + PyThreadState* tstate = PyThreadState_GET(); + + current->python_state << tstate; + current->exception_state << tstate; + this->python_state.will_switch_from(tstate); + switching_thread_state = this; + current->expose_frames(); + } + assert(this->args() || PyErr_Occurred()); + // If this is the first switch into a greenlet, this will + // return twice, once with 1 in the new greenlet, once with 0 + // in the origin. + int err; + if (this->force_slp_switch_error()) { + err = -1; + } + else { + err = slp_switch(); + } + + if (err < 0) { /* error */ + // Tested by + // test_greenlet.TestBrokenGreenlets.test_failed_to_slp_switch_into_running + // + // It's not clear if it's worth trying to clean up and + // continue here. Failing to switch stacks is a big deal which + // may not be recoverable (who knows what state the stack is in). + // Also, we've stolen references in preparation for calling + // ``g_switchstack_success()`` and we don't have a clean + // mechanism for backing that all out. + Py_FatalError("greenlet: Failed low-level slp_switch(). The stack is probably corrupt."); + } + + // No stack-based variables are valid anymore. + + // But the global is volatile so we can reload it without the + // compiler caching it from earlier. + Greenlet* greenlet_that_switched_in = switching_thread_state; // aka this + switching_thread_state = nullptr; + // except that no stack variables are valid, we would: + // assert(this == greenlet_that_switched_in); + + // switchstack success is where we restore the exception state, + // etc. It returns the origin greenlet because its convenient. + + OwnedGreenlet origin = greenlet_that_switched_in->g_switchstack_success(); + assert(greenlet_that_switched_in->args() || PyErr_Occurred()); + return switchstack_result_t(err, greenlet_that_switched_in, origin); +} + + +inline void +Greenlet::check_switch_allowed() const +{ + // TODO: Make this take a parameter of the current greenlet, + // or current main greenlet, to make the check for + // cross-thread switching cheaper. Surely somewhere up the + // call stack we've already accessed the thread local variable. + + // We expect to always have a main greenlet now; accessing the thread state + // created it. However, if we get here and cleanup has already + // begun because we're a greenlet that was running in a + // (now dead) thread, these invariants will not hold true. In + // fact, accessing `this->thread_state` may not even be possible. + + // If the thread this greenlet was running in is dead, + // we'll still have a reference to a main greenlet, but the + // thread state pointer we have is bogus. + // TODO: Give the objects an API to determine if they belong + // to a dead thread. + + const BorrowedMainGreenlet main_greenlet = this->find_main_greenlet_in_lineage(); + + if (!main_greenlet) { + throw PyErrOccurred(mod_globs->PyExc_GreenletError, + "cannot switch to a garbage collected greenlet"); + } + + if (!main_greenlet->thread_state()) { + throw PyErrOccurred(mod_globs->PyExc_GreenletError, + "cannot switch to a different thread (which happens to have exited)"); + } + + // The main greenlet we found was from the .parent lineage. + // That may or may not have any relationship to the main + // greenlet of the running thread. We can't actually access + // our this->thread_state members to try to check that, + // because it could be in the process of getting destroyed, + // but setting the main_greenlet->thread_state member to NULL + // may not be visible yet. So we need to check against the + // current thread state (once the cheaper checks are out of + // the way) + const BorrowedMainGreenlet current_main_greenlet = GET_THREAD_STATE().state().borrow_main_greenlet(); + if ( + // lineage main greenlet is not this thread's greenlet + current_main_greenlet != main_greenlet + || ( + // atteched to some thread + this->main_greenlet() + // XXX: Same condition as above. Was this supposed to be + // this->main_greenlet()? + && current_main_greenlet != main_greenlet) + // switching into a known dead thread (XXX: which, if we get here, + // is bad, because we just accessed the thread state, which is + // gone!) + || (!current_main_greenlet->thread_state())) { + // CAUTION: This may trigger memory allocations, gc, and + // arbitrary Python code. + throw PyErrOccurred( + mod_globs->PyExc_GreenletError, + "Cannot switch to a different thread\n\tCurrent: %R\n\tExpected: %R", + current_main_greenlet, main_greenlet); + } +} + +const OwnedObject +Greenlet::context() const +{ + using greenlet::PythonStateContext; + OwnedObject result; + + if (this->is_currently_running_in_some_thread()) { + /* Currently running greenlet: context is stored in the thread state, + not the greenlet object. */ + if (GET_THREAD_STATE().state().is_current(this->self())) { + result = PythonStateContext::context(PyThreadState_GET()); + } + else { + throw ValueError( + "cannot get context of a " + "greenlet that is running in a different thread"); + } + } + else { + /* Greenlet is not running: just return context. */ + result = this->python_state.context(); + } + if (!result) { + result = OwnedObject::None(); + } + return result; +} + + +void +Greenlet::context(BorrowedObject given) +{ + using greenlet::PythonStateContext; + if (!given) { + throw AttributeError("can't delete context attribute"); + } + if (given.is_None()) { + /* "Empty context" is stored as NULL, not None. */ + given = nullptr; + } + + //checks type, incrs refcnt + greenlet::refs::OwnedContext context(given); + PyThreadState* tstate = PyThreadState_GET(); + + if (this->is_currently_running_in_some_thread()) { + if (!GET_THREAD_STATE().state().is_current(this->self())) { + throw ValueError("cannot set context of a greenlet" + " that is running in a different thread"); + } + + /* Currently running greenlet: context is stored in the thread state, + not the greenlet object. */ + OwnedObject octx = OwnedObject::consuming(PythonStateContext::context(tstate)); + PythonStateContext::context(tstate, context.relinquish_ownership()); + } + else { + /* Greenlet is not running: just set context. Note that the + greenlet may be dead.*/ + this->python_state.context() = context; + } +} + +/** + * CAUTION: May invoke arbitrary Python code. + * + * Figure out what the result of ``greenlet.switch(arg, kwargs)`` + * should be and transfers ownership of it to the left-hand-side. + * + * If switch() was just passed an arg tuple, then we'll just return that. + * If only keyword arguments were passed, then we'll pass the keyword + * argument dict. Otherwise, we'll create a tuple of (args, kwargs) and + * return both. + * + * CAUTION: This may allocate a new tuple object, which may + * cause the Python garbage collector to run, which in turn may + * run arbitrary Python code that switches. + */ +OwnedObject& operator<<=(OwnedObject& lhs, greenlet::SwitchingArgs& rhs) noexcept +{ + // Because this may invoke arbitrary Python code, which could + // result in switching back to us, we need to get the + // arguments locally on the stack. + assert(rhs); + OwnedObject args = rhs.args(); + OwnedObject kwargs = rhs.kwargs(); + rhs.CLEAR(); + // We shouldn't be called twice for the same switch. + assert(args || kwargs); + assert(!rhs); + + if (!kwargs) { + lhs = args; + } + else if (!PyDict_Size(kwargs.borrow())) { + lhs = args; + } + else if (!PySequence_Length(args.borrow())) { + lhs = kwargs; + } + else { + // PyTuple_Pack allocates memory, may GC, may run arbitrary + // Python code. + lhs = OwnedObject::consuming(PyTuple_Pack(2, args.borrow(), kwargs.borrow())); + } + return lhs; +} + +static OwnedObject +g_handle_exit(const OwnedObject& greenlet_result) +{ + if (!greenlet_result && mod_globs->PyExc_GreenletExit.PyExceptionMatches()) { + /* catch and ignore GreenletExit */ + PyErrFetchParam val; + PyErr_Fetch(PyErrFetchParam(), val, PyErrFetchParam()); + if (!val) { + return OwnedObject::None(); + } + return OwnedObject(val); + } + + if (greenlet_result) { + // package the result into a 1-tuple + // PyTuple_Pack increments the reference of its arguments, + // so we always need to decref the greenlet result; + // the owner will do that. + return OwnedObject::consuming(PyTuple_Pack(1, greenlet_result.borrow())); + } + + return OwnedObject(); +} + + + +/** + * May run arbitrary Python code. + */ +OwnedObject +Greenlet::g_switch_finish(const switchstack_result_t& err) +{ + assert(err.the_new_current_greenlet == this); + + ThreadState& state = *this->thread_state(); + // Because calling the trace function could do arbitrary things, + // including switching away from this greenlet and then maybe + // switching back, we need to capture the arguments now so that + // they don't change. + OwnedObject result; + if (this->args()) { + result <<= this->args(); + } + else { + assert(PyErr_Occurred()); + } + assert(!this->args()); + try { + // Our only caller handles the bad error case + assert(err.status >= 0); + assert(state.borrow_current() == this->self()); + if (OwnedObject tracefunc = state.get_tracefunc()) { + assert(result || PyErr_Occurred()); + g_calltrace(tracefunc, + result ? mod_globs->event_switch : mod_globs->event_throw, + err.origin_greenlet, + this->self()); + } + // The above could have invoked arbitrary Python code, but + // it couldn't switch back to this object and *also* + // throw an exception, so the args won't have changed. + + if (PyErr_Occurred()) { + // We get here if we fell of the end of the run() function + // raising an exception. The switch itself was + // successful, but the function raised. + // valgrind reports that memory allocated here can still + // be reached after a test run. + throw PyErrOccurred::from_current(); + } + return result; + } + catch (const PyErrOccurred&) { + /* Turn switch errors into switch throws */ + /* Turn trace errors into switch throws */ + this->release_args(); + throw; + } +} + +void +Greenlet::g_calltrace(const OwnedObject& tracefunc, + const greenlet::refs::ImmortalEventName& event, + const BorrowedGreenlet& origin, + const BorrowedGreenlet& target) +{ + PyErrPieces saved_exc; + try { + TracingGuard tracing_guard; + // TODO: We have saved the active exception (if any) that's + // about to be raised. In the 'throw' case, we could provide + // the exception to the tracefunction, which seems very helpful. + tracing_guard.CallTraceFunction(tracefunc, event, origin, target); + } + catch (const PyErrOccurred&) { + // In case of exceptions trace function is removed, + // and any existing exception is replaced with the tracing + // exception. + GET_THREAD_STATE().state().set_tracefunc(Py_None); + throw; + } + + saved_exc.PyErrRestore(); + assert( + (event == mod_globs->event_throw && PyErr_Occurred()) + || (event == mod_globs->event_switch && !PyErr_Occurred()) + ); +} + +void +Greenlet::murder_in_place() +{ + if (this->active()) { + assert(!this->is_currently_running_in_some_thread()); + this->deactivate_and_free(); + } +} + +inline void +Greenlet::deactivate_and_free() +{ + if (!this->active()) { + return; + } + // Throw away any saved stack. + this->stack_state = StackState(); + assert(!this->stack_state.active()); + // Throw away any Python references. + // We're holding a borrowed reference to the last + // frame we executed. Since we borrowed it, the + // normal traversal, clear, and dealloc functions + // ignore it, meaning it leaks. (The thread state + // object can't find it to clear it when that's + // deallocated either, because by definition if we + // got an object on this list, it wasn't + // running and the thread state doesn't have + // this frame.) + // So here, we *do* clear it. + this->python_state.tp_clear(true); +} + +bool +Greenlet::belongs_to_thread(const ThreadState* thread_state) const +{ + if (!this->thread_state() // not running anywhere, or thread + // exited + || !thread_state) { // same, or there is no thread state. + return false; + } + return true; +} + + +void +Greenlet::deallocing_greenlet_in_thread(const ThreadState* current_thread_state) +{ + /* Cannot raise an exception to kill the greenlet if + it is not running in the same thread! */ + if (this->belongs_to_thread(current_thread_state)) { + assert(current_thread_state); + // To get here it had to have run before + /* Send the greenlet a GreenletExit exception. */ + + // We don't care about the return value, only whether an + // exception happened. + this->throw_GreenletExit_during_dealloc(*current_thread_state); + return; + } + + // Not the same thread! Temporarily save the greenlet + // into its thread's deleteme list, *if* it exists. + // If that thread has already exited, and processed its pending + // cleanup, we'll never be able to clean everything up: we won't + // be able to raise an exception. + // That's mostly OK! Since we can't add it to a list, our refcount + // won't increase, and we'll go ahead with the DECREFs later. + ThreadState *const thread_state = this->thread_state(); + if (thread_state) { + thread_state->delete_when_thread_running(this->self()); + } + else { + // The thread is dead, we can't raise an exception. + // We need to make it look non-active, though, so that dealloc + // finishes killing it. + this->deactivate_and_free(); + } + return; +} + + +int +Greenlet::tp_traverse(visitproc visit, void* arg) +{ + + int result; + if ((result = this->exception_state.tp_traverse(visit, arg)) != 0) { + return result; + } + //XXX: This is ugly. But so is handling everything having to do + //with the top frame. + bool visit_top_frame = this->was_running_in_dead_thread(); + // When true, the thread is dead. Our implicit weak reference to the + // frame is now all that's left; we consider ourselves to + // strongly own it now. + if ((result = this->python_state.tp_traverse(visit, arg, visit_top_frame)) != 0) { + return result; + } + return 0; +} + +int +Greenlet::tp_clear() +{ + bool own_top_frame = this->was_running_in_dead_thread(); + this->exception_state.tp_clear(); + this->python_state.tp_clear(own_top_frame); + return 0; +} + +bool Greenlet::is_currently_running_in_some_thread() const +{ + return this->stack_state.active() && !this->python_state.top_frame(); +} + +#if GREENLET_PY312 +void GREENLET_NOINLINE(Greenlet::expose_frames)() +{ + if (!this->python_state.top_frame()) { + return; + } + + _PyInterpreterFrame* last_complete_iframe = nullptr; + _PyInterpreterFrame* iframe = this->python_state.top_frame()->f_frame; + while (iframe) { + // We must make a copy before looking at the iframe contents, + // since iframe might point to a portion of the greenlet's C stack + // that was spilled when switching greenlets. + _PyInterpreterFrame iframe_copy; + this->stack_state.copy_from_stack(&iframe_copy, iframe, sizeof(*iframe)); + if (!_PyFrame_IsIncomplete(&iframe_copy)) { + // If the iframe were OWNED_BY_CSTACK then it would always be + // incomplete. Since it's not incomplete, it's not on the C stack + // and we can access it through the original `iframe` pointer + // directly. This is important since GetFrameObject might + // lazily _create_ the frame object and we don't want the + // interpreter to lose track of it. + assert(iframe_copy.owner != FRAME_OWNED_BY_CSTACK); + + // We really want to just write: + // PyFrameObject* frame = _PyFrame_GetFrameObject(iframe); + // but _PyFrame_GetFrameObject calls _PyFrame_MakeAndSetFrameObject + // which is not a visible symbol in libpython. The easiest + // way to get a public function to call it is using + // PyFrame_GetBack, which is defined as follows: + // assert(frame != NULL); + // assert(!_PyFrame_IsIncomplete(frame->f_frame)); + // PyFrameObject *back = frame->f_back; + // if (back == NULL) { + // _PyInterpreterFrame *prev = frame->f_frame->previous; + // prev = _PyFrame_GetFirstComplete(prev); + // if (prev) { + // back = _PyFrame_GetFrameObject(prev); + // } + // } + // return (PyFrameObject*)Py_XNewRef(back); + if (!iframe->frame_obj) { + PyFrameObject dummy_frame; + _PyInterpreterFrame dummy_iframe; + dummy_frame.f_back = nullptr; + dummy_frame.f_frame = &dummy_iframe; + // force the iframe to be considered complete without + // needing to check its code object: + dummy_iframe.owner = FRAME_OWNED_BY_GENERATOR; + dummy_iframe.previous = iframe; + assert(!_PyFrame_IsIncomplete(&dummy_iframe)); + // Drop the returned reference immediately; the iframe + // continues to hold a strong reference + Py_XDECREF(PyFrame_GetBack(&dummy_frame)); + assert(iframe->frame_obj); + } + + // This is a complete frame, so make the last one of those we saw + // point at it, bypassing any incomplete frames (which may have + // been on the C stack) in between the two. We're overwriting + // last_complete_iframe->previous and need that to be reversible, + // so we store the original previous ptr in the frame object + // (which we must have created on a previous iteration through + // this loop). The frame object has a bunch of storage that is + // only used when its iframe is OWNED_BY_FRAME_OBJECT, which only + // occurs when the frame object outlives the frame's execution, + // which can't have happened yet because the frame is currently + // executing as far as the interpreter is concerned. So, we can + // reuse it for our own purposes. + assert(iframe->owner == FRAME_OWNED_BY_THREAD + || iframe->owner == FRAME_OWNED_BY_GENERATOR); + if (last_complete_iframe) { + assert(last_complete_iframe->frame_obj); + memcpy(&last_complete_iframe->frame_obj->_f_frame_data[0], + &last_complete_iframe->previous, sizeof(void *)); + last_complete_iframe->previous = iframe; + } + last_complete_iframe = iframe; + } + // Frames that are OWNED_BY_FRAME_OBJECT are linked via the + // frame's f_back while all others are linked via the iframe's + // previous ptr. Since all the frames we traverse are running + // as far as the interpreter is concerned, we don't have to + // worry about the OWNED_BY_FRAME_OBJECT case. + iframe = iframe_copy.previous; + } + + // Give the outermost complete iframe a null previous pointer to + // account for any potential incomplete/C-stack iframes between it + // and the actual top-of-stack + if (last_complete_iframe) { + assert(last_complete_iframe->frame_obj); + memcpy(&last_complete_iframe->frame_obj->_f_frame_data[0], + &last_complete_iframe->previous, sizeof(void *)); + last_complete_iframe->previous = nullptr; + } +} +#else +void Greenlet::expose_frames() +{ + +} +#endif + +}; // namespace greenlet +#endif diff --git a/psets/9/finance/env/lib/python3.12/site-packages/greenlet/TGreenlet.hpp b/psets/9/finance/env/lib/python3.12/site-packages/greenlet/TGreenlet.hpp new file mode 100644 index 0000000..512f7fb --- /dev/null +++ b/psets/9/finance/env/lib/python3.12/site-packages/greenlet/TGreenlet.hpp @@ -0,0 +1,813 @@ +#ifndef GREENLET_GREENLET_HPP +#define GREENLET_GREENLET_HPP +/* + * Declarations of the core data structures. +*/ + +#define PY_SSIZE_T_CLEAN +#include + +#include "greenlet_compiler_compat.hpp" +#include "greenlet_refs.hpp" +#include "greenlet_cpython_compat.hpp" +#include "greenlet_allocator.hpp" + +using greenlet::refs::OwnedObject; +using greenlet::refs::OwnedGreenlet; +using greenlet::refs::OwnedMainGreenlet; +using greenlet::refs::BorrowedGreenlet; + +#if PY_VERSION_HEX < 0x30B00A6 +# define _PyCFrame CFrame +# define _PyInterpreterFrame _interpreter_frame +#endif + +#if GREENLET_PY312 +# define Py_BUILD_CORE +# include "internal/pycore_frame.h" +#endif + +// XXX: TODO: Work to remove all virtual functions +// for speed of calling and size of objects (no vtable). +// One pattern is the Curiously Recurring Template +namespace greenlet +{ + class ExceptionState + { + private: + G_NO_COPIES_OF_CLS(ExceptionState); + + // Even though these are borrowed objects, we actually own + // them, when they're not null. + // XXX: Express that in the API. + private: + _PyErr_StackItem* exc_info; + _PyErr_StackItem exc_state; + public: + ExceptionState(); + void operator<<(const PyThreadState *const tstate) noexcept; + void operator>>(PyThreadState* tstate) noexcept; + void clear() noexcept; + + int tp_traverse(visitproc visit, void* arg) noexcept; + void tp_clear() noexcept; + }; + + template + void operator<<(const PyThreadState *const tstate, T& exc); + + class PythonStateContext + { + protected: + greenlet::refs::OwnedContext _context; + public: + inline const greenlet::refs::OwnedContext& context() const + { + return this->_context; + } + inline greenlet::refs::OwnedContext& context() + { + return this->_context; + } + + inline void tp_clear() + { + this->_context.CLEAR(); + } + + template + inline static PyObject* context(T* tstate) + { + return tstate->context; + } + + template + inline static void context(T* tstate, PyObject* new_context) + { + tstate->context = new_context; + tstate->context_ver++; + } + }; + class SwitchingArgs; + class PythonState : public PythonStateContext + { + public: + typedef greenlet::refs::OwnedReference OwnedFrame; + private: + G_NO_COPIES_OF_CLS(PythonState); + // We own this if we're suspended (although currently we don't + // tp_traverse into it; that's a TODO). If we're running, it's + // empty. If we get deallocated and *still* have a frame, it + // won't be reachable from the place that normally decref's + // it, so we need to do it (hence owning it). + OwnedFrame _top_frame; +#if GREENLET_USE_CFRAME + _PyCFrame* cframe; + int use_tracing; +#endif +#if GREENLET_PY312 + int py_recursion_depth; + int c_recursion_depth; +#else + int recursion_depth; +#endif +#if GREENLET_PY313 + PyObject *delete_later; +#else + int trash_delete_nesting; +#endif +#if GREENLET_PY311 + _PyInterpreterFrame* current_frame; + _PyStackChunk* datastack_chunk; + PyObject** datastack_top; + PyObject** datastack_limit; +#endif + // The PyInterpreterFrame list on 3.12+ contains some entries that are + // on the C stack, which can't be directly accessed while a greenlet is + // suspended. In order to keep greenlet gr_frame introspection working, + // we adjust stack switching to rewrite the interpreter frame list + // to skip these C-stack frames; we call this "exposing" the greenlet's + // frames because it makes them valid to work with in Python. Then when + // the greenlet is resumed we need to remember to reverse the operation + // we did. The C-stack frames are "entry frames" which are a low-level + // interpreter detail; they're not needed for introspection, but do + // need to be present for the eval loop to work. + void unexpose_frames(); + + public: + + PythonState(); + // You can use this for testing whether we have a frame + // or not. It returns const so they can't modify it. + const OwnedFrame& top_frame() const noexcept; + + inline void operator<<(const PyThreadState *const tstate) noexcept; + inline void operator>>(PyThreadState* tstate) noexcept; + void clear() noexcept; + + int tp_traverse(visitproc visit, void* arg, bool visit_top_frame) noexcept; + void tp_clear(bool own_top_frame) noexcept; + void set_initial_state(const PyThreadState* const tstate) noexcept; +#if GREENLET_USE_CFRAME + void set_new_cframe(_PyCFrame& frame) noexcept; +#endif + + void may_switch_away() noexcept; + inline void will_switch_from(PyThreadState *const origin_tstate) noexcept; + void did_finish(PyThreadState* tstate) noexcept; + }; + + class StackState + { + // By having only plain C (POD) members, no virtual functions + // or bases, we get a trivial assignment operator generated + // for us. However, that's not safe since we do manage memory. + // So we declare an assignment operator that only works if we + // don't have any memory allocated. (We don't use + // std::shared_ptr for reference counting just to keep this + // object small) + private: + char* _stack_start; + char* stack_stop; + char* stack_copy; + intptr_t _stack_saved; + StackState* stack_prev; + inline int copy_stack_to_heap_up_to(const char* const stop) noexcept; + inline void free_stack_copy() noexcept; + + public: + /** + * Creates a started, but inactive, state, using *current* + * as the previous. + */ + StackState(void* mark, StackState& current); + /** + * Creates an inactive, unstarted, state. + */ + StackState(); + ~StackState(); + StackState(const StackState& other); + StackState& operator=(const StackState& other); + inline void copy_heap_to_stack(const StackState& current) noexcept; + inline int copy_stack_to_heap(char* const stackref, const StackState& current) noexcept; + inline bool started() const noexcept; + inline bool main() const noexcept; + inline bool active() const noexcept; + inline void set_active() noexcept; + inline void set_inactive() noexcept; + inline intptr_t stack_saved() const noexcept; + inline char* stack_start() const noexcept; + static inline StackState make_main() noexcept; +#ifdef GREENLET_USE_STDIO + friend std::ostream& operator<<(std::ostream& os, const StackState& s); +#endif + + // Fill in [dest, dest + n) with the values that would be at + // [src, src + n) while this greenlet is running. This is like memcpy + // except that if the greenlet is suspended it accounts for the portion + // of the greenlet's stack that was spilled to the heap. `src` may + // be on this greenlet's stack, or on the heap, but not on a different + // greenlet's stack. + void copy_from_stack(void* dest, const void* src, size_t n) const; + }; +#ifdef GREENLET_USE_STDIO + std::ostream& operator<<(std::ostream& os, const StackState& s); +#endif + + class SwitchingArgs + { + private: + G_NO_ASSIGNMENT_OF_CLS(SwitchingArgs); + // If args and kwargs are both false (NULL), this is a *throw*, not a + // switch. PyErr_... must have been called already. + OwnedObject _args; + OwnedObject _kwargs; + public: + + SwitchingArgs() + {} + + SwitchingArgs(const OwnedObject& args, const OwnedObject& kwargs) + : _args(args), + _kwargs(kwargs) + {} + + SwitchingArgs(const SwitchingArgs& other) + : _args(other._args), + _kwargs(other._kwargs) + {} + + const OwnedObject& args() + { + return this->_args; + } + + const OwnedObject& kwargs() + { + return this->_kwargs; + } + + /** + * Moves ownership from the argument to this object. + */ + SwitchingArgs& operator<<=(SwitchingArgs& other) + { + if (this != &other) { + this->_args = other._args; + this->_kwargs = other._kwargs; + other.CLEAR(); + } + return *this; + } + + /** + * Acquires ownership of the argument (consumes the reference). + */ + SwitchingArgs& operator<<=(PyObject* args) + { + this->_args = OwnedObject::consuming(args); + this->_kwargs.CLEAR(); + return *this; + } + + /** + * Acquires ownership of the argument. + * + * Sets the args to be the given value; clears the kwargs. + */ + SwitchingArgs& operator<<=(OwnedObject& args) + { + assert(&args != &this->_args); + this->_args = args; + this->_kwargs.CLEAR(); + args.CLEAR(); + + return *this; + } + + explicit operator bool() const noexcept + { + return this->_args || this->_kwargs; + } + + inline void CLEAR() + { + this->_args.CLEAR(); + this->_kwargs.CLEAR(); + } + + const std::string as_str() const noexcept + { + return PyUnicode_AsUTF8( + OwnedObject::consuming( + PyUnicode_FromFormat( + "SwitchingArgs(args=%R, kwargs=%R)", + this->_args.borrow(), + this->_kwargs.borrow() + ) + ).borrow() + ); + } + }; + + class ThreadState; + + class UserGreenlet; + class MainGreenlet; + + class Greenlet + { + private: + G_NO_COPIES_OF_CLS(Greenlet); + PyGreenlet* const _self; + private: + // XXX: Work to remove these. + friend class ThreadState; + friend class UserGreenlet; + friend class MainGreenlet; + protected: + ExceptionState exception_state; + SwitchingArgs switch_args; + StackState stack_state; + PythonState python_state; + Greenlet(PyGreenlet* p, const StackState& initial_state); + public: + // This constructor takes ownership of the PyGreenlet, by + // setting ``p->pimpl = this;``. + Greenlet(PyGreenlet* p); + virtual ~Greenlet(); + + const OwnedObject context() const; + + // You MUST call this _very_ early in the switching process to + // prepare anything that may need prepared. This might perform + // garbage collections or otherwise run arbitrary Python code. + // + // One specific use of it is for Python 3.11+, preventing + // running arbitrary code at unsafe times. See + // PythonState::may_switch_away(). + inline void may_switch_away() + { + this->python_state.may_switch_away(); + } + + inline void context(refs::BorrowedObject new_context); + + inline SwitchingArgs& args() + { + return this->switch_args; + } + + virtual const refs::BorrowedMainGreenlet main_greenlet() const = 0; + + inline intptr_t stack_saved() const noexcept + { + return this->stack_state.stack_saved(); + } + + // This is used by the macro SLP_SAVE_STATE to compute the + // difference in stack sizes. It might be nice to handle the + // computation ourself, but the type of the result + // varies by platform, so doing it in the macro is the + // simplest way. + inline const char* stack_start() const noexcept + { + return this->stack_state.stack_start(); + } + + virtual OwnedObject throw_GreenletExit_during_dealloc(const ThreadState& current_thread_state); + virtual OwnedObject g_switch() = 0; + /** + * Force the greenlet to appear dead. Used when it's not + * possible to throw an exception into a greenlet anymore. + * + * This losses access to the thread state and the main greenlet. + */ + virtual void murder_in_place(); + + /** + * Called when somebody notices we were running in a dead + * thread to allow cleaning up resources (because we can't + * raise GreenletExit into it anymore). + * This is very similar to ``murder_in_place()``, except that + * it DOES NOT lose the main greenlet or thread state. + */ + inline void deactivate_and_free(); + + + // Called when some thread wants to deallocate a greenlet + // object. + // The thread may or may not be the same thread the greenlet + // was running in. + // The thread state will be null if the thread the greenlet + // was running in was known to have exited. + void deallocing_greenlet_in_thread(const ThreadState* current_state); + + // Must be called on 3.12+ before exposing a suspended greenlet's + // frames to user code. This rewrites the linked list of interpreter + // frames to skip the ones that are being stored on the C stack (which + // can't be safely accessed while the greenlet is suspended because + // that stack space might be hosting a different greenlet), and + // sets PythonState::frames_were_exposed so we remember to restore + // the original list before resuming the greenlet. The C-stack frames + // are a low-level interpreter implementation detail; while they're + // important to the bytecode eval loop, they're superfluous for + // introspection purposes. + void expose_frames(); + + + // TODO: Figure out how to make these non-public. + inline void slp_restore_state() noexcept; + inline int slp_save_state(char *const stackref) noexcept; + + inline bool is_currently_running_in_some_thread() const; + virtual bool belongs_to_thread(const ThreadState* state) const; + + inline bool started() const + { + return this->stack_state.started(); + } + inline bool active() const + { + return this->stack_state.active(); + } + inline bool main() const + { + return this->stack_state.main(); + } + virtual refs::BorrowedMainGreenlet find_main_greenlet_in_lineage() const = 0; + + virtual const OwnedGreenlet parent() const = 0; + virtual void parent(const refs::BorrowedObject new_parent) = 0; + + inline const PythonState::OwnedFrame& top_frame() + { + return this->python_state.top_frame(); + } + + virtual const OwnedObject& run() const = 0; + virtual void run(const refs::BorrowedObject nrun) = 0; + + + virtual int tp_traverse(visitproc visit, void* arg); + virtual int tp_clear(); + + + // Return the thread state that the greenlet is running in, or + // null if the greenlet is not running or the thread is known + // to have exited. + virtual ThreadState* thread_state() const noexcept = 0; + + // Return true if the greenlet is known to have been running + // (active) in a thread that has now exited. + virtual bool was_running_in_dead_thread() const noexcept = 0; + + // Return a borrowed greenlet that is the Python object + // this object represents. + inline BorrowedGreenlet self() const noexcept + { + return BorrowedGreenlet(this->_self); + } + + // For testing. If this returns true, we should pretend that + // slp_switch() failed. + virtual bool force_slp_switch_error() const noexcept; + + protected: + inline void release_args(); + + // The functions that must not be inlined are declared virtual. + // We also mark them as protected, not private, so that the + // compiler is forced to call them through a function pointer. + // (A sufficiently smart compiler could directly call a private + // virtual function since it can never be overridden in a + // subclass). + + // Also TODO: Switch away from integer error codes and to enums, + // or throw exceptions when possible. + struct switchstack_result_t + { + int status; + Greenlet* the_new_current_greenlet; + OwnedGreenlet origin_greenlet; + + switchstack_result_t() + : status(0), + the_new_current_greenlet(nullptr) + {} + + switchstack_result_t(int err) + : status(err), + the_new_current_greenlet(nullptr) + {} + + switchstack_result_t(int err, Greenlet* state, OwnedGreenlet& origin) + : status(err), + the_new_current_greenlet(state), + origin_greenlet(origin) + { + } + + switchstack_result_t(int err, Greenlet* state, const BorrowedGreenlet& origin) + : status(err), + the_new_current_greenlet(state), + origin_greenlet(origin) + { + } + + switchstack_result_t(const switchstack_result_t& other) + : status(other.status), + the_new_current_greenlet(other.the_new_current_greenlet), + origin_greenlet(other.origin_greenlet) + {} + + switchstack_result_t& operator=(const switchstack_result_t& other) + { + this->status = other.status; + this->the_new_current_greenlet = other.the_new_current_greenlet; + this->origin_greenlet = other.origin_greenlet; + return *this; + } + }; + + OwnedObject on_switchstack_or_initialstub_failure( + Greenlet* target, + const switchstack_result_t& err, + const bool target_was_me=false, + const bool was_initial_stub=false); + + // Returns the previous greenlet we just switched away from. + virtual OwnedGreenlet g_switchstack_success() noexcept; + + + // Check the preconditions for switching to this greenlet; if they + // aren't met, throws PyErrOccurred. Most callers will want to + // catch this and clear the arguments + inline void check_switch_allowed() const; + class GreenletStartedWhileInPython : public std::runtime_error + { + public: + GreenletStartedWhileInPython() : std::runtime_error("") + {} + }; + + protected: + + + /** + Perform a stack switch into this greenlet. + + This temporarily sets the global variable + ``switching_thread_state`` to this greenlet; as soon as the + call to ``slp_switch`` completes, this is reset to NULL. + Consequently, this depends on the GIL. + + TODO: Adopt the stackman model and pass ``slp_switch`` a + callback function and context pointer; this eliminates the + need for global variables altogether. + + Because the stack switch happens in this function, this + function can't use its own stack (local) variables, set + before the switch, and then accessed after the switch. + + Further, you con't even access ``g_thread_state_global`` + before and after the switch from the global variable. + Because it is thread local some compilers cache it in a + register/on the stack, notably new versions of MSVC; this + breaks with strange crashes sometime later, because writing + to anything in ``g_thread_state_global`` after the switch + is actually writing to random memory. For this reason, we + call a non-inlined function to finish the operation. (XXX: + The ``/GT`` MSVC compiler argument probably fixes that.) + + It is very important that stack switch is 'atomic', i.e. no + calls into other Python code allowed (except very few that + are safe), because global variables are very fragile. (This + should no longer be the case with thread-local variables.) + + */ + // Made virtual to facilitate subclassing UserGreenlet for testing. + virtual switchstack_result_t g_switchstack(void); + +class TracingGuard +{ +private: + PyThreadState* tstate; +public: + TracingGuard() + : tstate(PyThreadState_GET()) + { + PyThreadState_EnterTracing(this->tstate); + } + + ~TracingGuard() + { + PyThreadState_LeaveTracing(this->tstate); + this->tstate = nullptr; + } + + inline void CallTraceFunction(const OwnedObject& tracefunc, + const greenlet::refs::ImmortalEventName& event, + const BorrowedGreenlet& origin, + const BorrowedGreenlet& target) + { + // TODO: This calls tracefunc(event, (origin, target)). Add a shortcut + // function for that that's specialized to avoid the Py_BuildValue + // string parsing, or start with just using "ON" format with PyTuple_Pack(2, + // origin, target). That seems like what the N format is meant + // for. + // XXX: Why does event not automatically cast back to a PyObject? + // It tries to call the "deleted constructor ImmortalEventName + // const" instead. + assert(tracefunc); + assert(event); + assert(origin); + assert(target); + greenlet::refs::NewReference retval( + PyObject_CallFunction( + tracefunc.borrow(), + "O(OO)", + event.borrow(), + origin.borrow(), + target.borrow() + )); + if (!retval) { + throw PyErrOccurred::from_current(); + } + } +}; + + static void + g_calltrace(const OwnedObject& tracefunc, + const greenlet::refs::ImmortalEventName& event, + const greenlet::refs::BorrowedGreenlet& origin, + const BorrowedGreenlet& target); + private: + OwnedObject g_switch_finish(const switchstack_result_t& err); + + }; + + class UserGreenlet : public Greenlet + { + private: + static greenlet::PythonAllocator allocator; + OwnedMainGreenlet _main_greenlet; + OwnedObject _run_callable; + OwnedGreenlet _parent; + public: + static void* operator new(size_t UNUSED(count)); + static void operator delete(void* ptr); + + UserGreenlet(PyGreenlet* p, BorrowedGreenlet the_parent); + virtual ~UserGreenlet(); + + virtual refs::BorrowedMainGreenlet find_main_greenlet_in_lineage() const; + virtual bool was_running_in_dead_thread() const noexcept; + virtual ThreadState* thread_state() const noexcept; + virtual OwnedObject g_switch(); + virtual const OwnedObject& run() const + { + if (this->started() || !this->_run_callable) { + throw AttributeError("run"); + } + return this->_run_callable; + } + virtual void run(const refs::BorrowedObject nrun); + + virtual const OwnedGreenlet parent() const; + virtual void parent(const refs::BorrowedObject new_parent); + + virtual const refs::BorrowedMainGreenlet main_greenlet() const; + + virtual void murder_in_place(); + virtual bool belongs_to_thread(const ThreadState* state) const; + virtual int tp_traverse(visitproc visit, void* arg); + virtual int tp_clear(); + class ParentIsCurrentGuard + { + private: + OwnedGreenlet oldparent; + UserGreenlet* greenlet; + G_NO_COPIES_OF_CLS(ParentIsCurrentGuard); + public: + ParentIsCurrentGuard(UserGreenlet* p, const ThreadState& thread_state); + ~ParentIsCurrentGuard(); + }; + virtual OwnedObject throw_GreenletExit_during_dealloc(const ThreadState& current_thread_state); + protected: + virtual switchstack_result_t g_initialstub(void* mark); + private: + // This function isn't meant to return. + // This accepts raw pointers and the ownership of them at the + // same time. The caller should use ``inner_bootstrap(origin.relinquish_ownership())``. + void inner_bootstrap(PyGreenlet* origin_greenlet, PyObject* run); + }; + + class BrokenGreenlet : public UserGreenlet + { + private: + static greenlet::PythonAllocator allocator; + public: + bool _force_switch_error = false; + bool _force_slp_switch_error = false; + + static void* operator new(size_t UNUSED(count)); + static void operator delete(void* ptr); + BrokenGreenlet(PyGreenlet* p, BorrowedGreenlet the_parent) + : UserGreenlet(p, the_parent) + {} + virtual ~BrokenGreenlet() + {} + + virtual switchstack_result_t g_switchstack(void); + virtual bool force_slp_switch_error() const noexcept; + + }; + + class MainGreenlet : public Greenlet + { + private: + static greenlet::PythonAllocator allocator; + refs::BorrowedMainGreenlet _self; + ThreadState* _thread_state; + G_NO_COPIES_OF_CLS(MainGreenlet); + public: + static void* operator new(size_t UNUSED(count)); + static void operator delete(void* ptr); + + MainGreenlet(refs::BorrowedMainGreenlet::PyType*, ThreadState*); + virtual ~MainGreenlet(); + + + virtual const OwnedObject& run() const; + virtual void run(const refs::BorrowedObject nrun); + + virtual const OwnedGreenlet parent() const; + virtual void parent(const refs::BorrowedObject new_parent); + + virtual const refs::BorrowedMainGreenlet main_greenlet() const; + + virtual refs::BorrowedMainGreenlet find_main_greenlet_in_lineage() const; + virtual bool was_running_in_dead_thread() const noexcept; + virtual ThreadState* thread_state() const noexcept; + void thread_state(ThreadState*) noexcept; + virtual OwnedObject g_switch(); + virtual int tp_traverse(visitproc visit, void* arg); + }; + + // Instantiate one on the stack to save the GC state, + // and then disable GC. When it goes out of scope, GC will be + // restored to its original state. Sadly, these APIs are only + // available on 3.10+; luckily, we only need them on 3.11+. +#if GREENLET_PY310 + class GCDisabledGuard + { + private: + int was_enabled = 0; + public: + GCDisabledGuard() + : was_enabled(PyGC_IsEnabled()) + { + PyGC_Disable(); + } + + ~GCDisabledGuard() + { + if (this->was_enabled) { + PyGC_Enable(); + } + } + }; +#endif + + OwnedObject& operator<<=(OwnedObject& lhs, greenlet::SwitchingArgs& rhs) noexcept; + + //TODO: Greenlet::g_switch() should call this automatically on its + //return value. As it is, the module code is calling it. + static inline OwnedObject + single_result(const OwnedObject& results) + { + if (results + && PyTuple_Check(results.borrow()) + && PyTuple_GET_SIZE(results.borrow()) == 1) { + PyObject* result = PyTuple_GET_ITEM(results.borrow(), 0); + assert(result); + return OwnedObject::owning(result); + } + return results; + } + + + static OwnedObject + g_handle_exit(const OwnedObject& greenlet_result); + + + template + void operator<<(const PyThreadState *const lhs, T& rhs) + { + rhs.operator<<(lhs); + } + +} // namespace greenlet ; + +#endif diff --git a/psets/9/finance/env/lib/python3.12/site-packages/greenlet/TGreenletGlobals.cpp b/psets/9/finance/env/lib/python3.12/site-packages/greenlet/TGreenletGlobals.cpp new file mode 100644 index 0000000..0087d2f --- /dev/null +++ b/psets/9/finance/env/lib/python3.12/site-packages/greenlet/TGreenletGlobals.cpp @@ -0,0 +1,94 @@ +/* -*- indent-tabs-mode: nil; tab-width: 4; -*- */ +/** + * Implementation of GreenletGlobals. + * + * Format with: + * clang-format -i --style=file src/greenlet/greenlet.c + * + * + * Fix missing braces with: + * clang-tidy src/greenlet/greenlet.c -fix -checks="readability-braces-around-statements" +*/ +#ifndef T_GREENLET_GLOBALS +#define T_GREENLET_GLOBALS + +#include "greenlet_refs.hpp" +#include "greenlet_exceptions.hpp" +#include "greenlet_thread_support.hpp" +#include "greenlet_internal.hpp" + +namespace greenlet { + +// This encapsulates what were previously module global "constants" +// established at init time. +// This is a step towards Python3 style module state that allows +// reloading. +// +// In an earlier iteration of this code, we used placement new to be +// able to allocate this object statically still, so that references +// to its members don't incur an extra pointer indirection. +// But under some scenarios, that could result in crashes at +// shutdown because apparently the destructor was getting run twice? +class GreenletGlobals +{ + +public: + const greenlet::refs::ImmortalEventName event_switch; + const greenlet::refs::ImmortalEventName event_throw; + const greenlet::refs::ImmortalException PyExc_GreenletError; + const greenlet::refs::ImmortalException PyExc_GreenletExit; + const greenlet::refs::ImmortalObject empty_tuple; + const greenlet::refs::ImmortalObject empty_dict; + const greenlet::refs::ImmortalString str_run; + Mutex* const thread_states_to_destroy_lock; + greenlet::cleanup_queue_t thread_states_to_destroy; + + GreenletGlobals() : + event_switch("switch"), + event_throw("throw"), + PyExc_GreenletError("greenlet.error"), + PyExc_GreenletExit("greenlet.GreenletExit", PyExc_BaseException), + empty_tuple(Require(PyTuple_New(0))), + empty_dict(Require(PyDict_New())), + str_run("run"), + thread_states_to_destroy_lock(new Mutex()) + {} + + ~GreenletGlobals() + { + // This object is (currently) effectively immortal, and not + // just because of those placement new tricks; if we try to + // deallocate the static object we allocated, and overwrote, + // we would be doing so at C++ teardown time, which is after + // the final Python GIL is released, and we can't use the API + // then. + // (The members will still be destructed, but they also don't + // do any deallocation.) + } + + void queue_to_destroy(ThreadState* ts) const + { + // we're currently accessed through a static const object, + // implicitly marking our members as const, so code can't just + // call push_back (or pop_back) without casting away the + // const. + // + // Do that for callers. + greenlet::cleanup_queue_t& q = const_cast(this->thread_states_to_destroy); + q.push_back(ts); + } + + ThreadState* take_next_to_destroy() const + { + greenlet::cleanup_queue_t& q = const_cast(this->thread_states_to_destroy); + ThreadState* result = q.back(); + q.pop_back(); + return result; + } +}; + +}; // namespace greenlet + +static const greenlet::GreenletGlobals* mod_globs; + +#endif // T_GREENLET_GLOBALS diff --git a/psets/9/finance/env/lib/python3.12/site-packages/greenlet/TMainGreenlet.cpp b/psets/9/finance/env/lib/python3.12/site-packages/greenlet/TMainGreenlet.cpp new file mode 100644 index 0000000..a2a9cfe --- /dev/null +++ b/psets/9/finance/env/lib/python3.12/site-packages/greenlet/TMainGreenlet.cpp @@ -0,0 +1,153 @@ +/* -*- indent-tabs-mode: nil; tab-width: 4; -*- */ +/** + * Implementation of greenlet::MainGreenlet. + * + * Format with: + * clang-format -i --style=file src/greenlet/greenlet.c + * + * + * Fix missing braces with: + * clang-tidy src/greenlet/greenlet.c -fix -checks="readability-braces-around-statements" +*/ +#ifndef T_MAIN_GREENLET_CPP +#define T_MAIN_GREENLET_CPP + +#include "TGreenlet.hpp" + + + +// Protected by the GIL. Incremented when we create a main greenlet, +// in a new thread, decremented when it is destroyed. +static Py_ssize_t G_TOTAL_MAIN_GREENLETS; + +namespace greenlet { +greenlet::PythonAllocator MainGreenlet::allocator; + +void* MainGreenlet::operator new(size_t UNUSED(count)) +{ + return allocator.allocate(1); +} + + +void MainGreenlet::operator delete(void* ptr) +{ + return allocator.deallocate(static_cast(ptr), + 1); +} + + +MainGreenlet::MainGreenlet(PyGreenlet* p, ThreadState* state) + : Greenlet(p, StackState::make_main()), + _self(p), + _thread_state(state) +{ + G_TOTAL_MAIN_GREENLETS++; +} + +MainGreenlet::~MainGreenlet() +{ + G_TOTAL_MAIN_GREENLETS--; + this->tp_clear(); +} + +ThreadState* +MainGreenlet::thread_state() const noexcept +{ + return this->_thread_state; +} + +void +MainGreenlet::thread_state(ThreadState* t) noexcept +{ + assert(!t); + this->_thread_state = t; +} + + +const BorrowedMainGreenlet +MainGreenlet::main_greenlet() const +{ + return this->_self; +} + +BorrowedMainGreenlet +MainGreenlet::find_main_greenlet_in_lineage() const +{ + return BorrowedMainGreenlet(this->_self); +} + +bool +MainGreenlet::was_running_in_dead_thread() const noexcept +{ + return !this->_thread_state; +} + +OwnedObject +MainGreenlet::g_switch() +{ + try { + this->check_switch_allowed(); + } + catch (const PyErrOccurred&) { + this->release_args(); + throw; + } + + switchstack_result_t err = this->g_switchstack(); + if (err.status < 0) { + // XXX: This code path is untested, but it is shared + // with the UserGreenlet path that is tested. + return this->on_switchstack_or_initialstub_failure( + this, + err, + true, // target was me + false // was initial stub + ); + } + + return err.the_new_current_greenlet->g_switch_finish(err); +} + +int +MainGreenlet::tp_traverse(visitproc visit, void* arg) +{ + if (this->_thread_state) { + // we've already traversed main, (self), don't do it again. + int result = this->_thread_state->tp_traverse(visit, arg, false); + if (result) { + return result; + } + } + return Greenlet::tp_traverse(visit, arg); +} + +const OwnedObject& +MainGreenlet::run() const +{ + throw AttributeError("Main greenlets do not have a run attribute."); +} + +void +MainGreenlet::run(const BorrowedObject UNUSED(nrun)) +{ + throw AttributeError("Main greenlets do not have a run attribute."); +} + +void +MainGreenlet::parent(const BorrowedObject raw_new_parent) +{ + if (!raw_new_parent) { + throw AttributeError("can't delete attribute"); + } + throw AttributeError("cannot set the parent of a main greenlet"); +} + +const OwnedGreenlet +MainGreenlet::parent() const +{ + return OwnedGreenlet(); // null becomes None +} + +}; // namespace greenlet + +#endif diff --git a/psets/9/finance/env/lib/python3.12/site-packages/greenlet/TPythonState.cpp b/psets/9/finance/env/lib/python3.12/site-packages/greenlet/TPythonState.cpp new file mode 100644 index 0000000..cc5dff5 --- /dev/null +++ b/psets/9/finance/env/lib/python3.12/site-packages/greenlet/TPythonState.cpp @@ -0,0 +1,393 @@ +#ifndef GREENLET_PYTHON_STATE_CPP +#define GREENLET_PYTHON_STATE_CPP + +#include +#include "TGreenlet.hpp" + +namespace greenlet { + +PythonState::PythonState() + : _top_frame() +#if GREENLET_USE_CFRAME + ,cframe(nullptr) + ,use_tracing(0) +#endif +#if GREENLET_PY312 + ,py_recursion_depth(0) + ,c_recursion_depth(0) +#else + ,recursion_depth(0) +#endif +#if GREENLET_PY313 + ,delete_later(nullptr) +#else + ,trash_delete_nesting(0) +#endif +#if GREENLET_PY311 + ,current_frame(nullptr) + ,datastack_chunk(nullptr) + ,datastack_top(nullptr) + ,datastack_limit(nullptr) +#endif +{ +#if GREENLET_USE_CFRAME + /* + The PyThreadState->cframe pointer usually points to memory on + the stack, alloceted in a call into PyEval_EvalFrameDefault. + + Initially, before any evaluation begins, it points to the + initial PyThreadState object's ``root_cframe`` object, which is + statically allocated for the lifetime of the thread. + + A greenlet can last for longer than a call to + PyEval_EvalFrameDefault, so we can't set its ``cframe`` pointer + to be the current ``PyThreadState->cframe``; nor could we use + one from the greenlet parent for the same reason. Yet a further + no: we can't allocate one scoped to the greenlet and then + destroy it when the greenlet is deallocated, because inside the + interpreter the _PyCFrame objects form a linked list, and that too + can result in accessing memory beyond its dynamic lifetime (if + the greenlet doesn't actually finish before it dies, its entry + could still be in the list). + + Using the ``root_cframe`` is problematic, though, because its + members are never modified by the interpreter and are set to 0, + meaning that its ``use_tracing`` flag is never updated. We don't + want to modify that value in the ``root_cframe`` ourself: it + *shouldn't* matter much because we should probably never get + back to the point where that's the only cframe on the stack; + even if it did matter, the major consequence of an incorrect + value for ``use_tracing`` is that if its true the interpreter + does some extra work --- however, it's just good code hygiene. + + Our solution: before a greenlet runs, after its initial + creation, it uses the ``root_cframe`` just to have something to + put there. However, once the greenlet is actually switched to + for the first time, ``g_initialstub`` (which doesn't actually + "return" while the greenlet is running) stores a new _PyCFrame on + its local stack, and copies the appropriate values from the + currently running _PyCFrame; this is then made the _PyCFrame for the + newly-minted greenlet. ``g_initialstub`` then proceeds to call + ``glet.run()``, which results in ``PyEval_...`` adding the + _PyCFrame to the list. Switches continue as normal. Finally, when + the greenlet finishes, the call to ``glet.run()`` returns and + the _PyCFrame is taken out of the linked list and the stack value + is now unused and free to expire. + + XXX: I think we can do better. If we're deallocing in the same + thread, can't we traverse the list and unlink our frame? + Can we just keep a reference to the thread state in case we + dealloc in another thread? (Is that even possible if we're still + running and haven't returned from g_initialstub?) + */ + this->cframe = &PyThreadState_GET()->root_cframe; +#endif +} + + +inline void PythonState::may_switch_away() noexcept +{ +#if GREENLET_PY311 + // PyThreadState_GetFrame is probably going to have to allocate a + // new frame object. That may trigger garbage collection. Because + // we call this during the early phases of a switch (it doesn't + // matter to which greenlet, as this has a global effect), if a GC + // triggers a switch away, two things can happen, both bad: + // - We might not get switched back to, halting forward progress. + // this is pathological, but possible. + // - We might get switched back to with a different set of + // arguments or a throw instead of a switch. That would corrupt + // our state (specifically, PyErr_Occurred() and this->args() + // would no longer agree). + // + // Thus, when we call this API, we need to have GC disabled. + // This method serves as a bottleneck we call when maybe beginning + // a switch. In this way, it is always safe -- no risk of GC -- to + // use ``_GetFrame()`` whenever we need to, just as it was in + // <=3.10 (because subsequent calls will be cached and not + // allocate memory). + + GCDisabledGuard no_gc; + Py_XDECREF(PyThreadState_GetFrame(PyThreadState_GET())); +#endif +} + +void PythonState::operator<<(const PyThreadState *const tstate) noexcept +{ + this->_context.steal(tstate->context); +#if GREENLET_USE_CFRAME + /* + IMPORTANT: ``cframe`` is a pointer into the STACK. Thus, because + the call to ``slp_switch()`` changes the contents of the stack, + you cannot read from ``ts_current->cframe`` after that call and + necessarily get the same values you get from reading it here. + Anything you need to restore from now to then must be saved in a + global/threadlocal variable (because we can't use stack + variables here either). For things that need to persist across + the switch, use `will_switch_from`. + */ + this->cframe = tstate->cframe; + #if !GREENLET_PY312 + this->use_tracing = tstate->cframe->use_tracing; + #endif +#endif // GREENLET_USE_CFRAME +#if GREENLET_PY311 + #if GREENLET_PY312 + this->py_recursion_depth = tstate->py_recursion_limit - tstate->py_recursion_remaining; + this->c_recursion_depth = Py_C_RECURSION_LIMIT - tstate->c_recursion_remaining; + #else // not 312 + this->recursion_depth = tstate->recursion_limit - tstate->recursion_remaining; + #endif // GREENLET_PY312 + #if GREENLET_PY313 + this->current_frame = tstate->current_frame; + #elif GREENLET_USE_CFRAME + this->current_frame = tstate->cframe->current_frame; + #endif + this->datastack_chunk = tstate->datastack_chunk; + this->datastack_top = tstate->datastack_top; + this->datastack_limit = tstate->datastack_limit; + + PyFrameObject *frame = PyThreadState_GetFrame((PyThreadState *)tstate); + Py_XDECREF(frame); // PyThreadState_GetFrame gives us a new + // reference. + this->_top_frame.steal(frame); + #if GREENLET_PY313 + this->delete_later = Py_XNewRef(tstate->delete_later); + #elif GREENLET_PY312 + this->trash_delete_nesting = tstate->trash.delete_nesting; + #else // not 312 + this->trash_delete_nesting = tstate->trash_delete_nesting; + #endif // GREENLET_PY312 +#else // Not 311 + this->recursion_depth = tstate->recursion_depth; + this->_top_frame.steal(tstate->frame); + this->trash_delete_nesting = tstate->trash_delete_nesting; +#endif // GREENLET_PY311 +} + +#if GREENLET_PY312 +void GREENLET_NOINLINE(PythonState::unexpose_frames)() +{ + if (!this->top_frame()) { + return; + } + + // See GreenletState::expose_frames() and the comment on frames_were_exposed + // for more information about this logic. + _PyInterpreterFrame *iframe = this->_top_frame->f_frame; + while (iframe != nullptr) { + _PyInterpreterFrame *prev_exposed = iframe->previous; + assert(iframe->frame_obj); + memcpy(&iframe->previous, &iframe->frame_obj->_f_frame_data[0], + sizeof(void *)); + iframe = prev_exposed; + } +} +#else +void PythonState::unexpose_frames() +{} +#endif + +void PythonState::operator>>(PyThreadState *const tstate) noexcept +{ + tstate->context = this->_context.relinquish_ownership(); + /* Incrementing this value invalidates the contextvars cache, + which would otherwise remain valid across switches */ + tstate->context_ver++; +#if GREENLET_USE_CFRAME + tstate->cframe = this->cframe; + /* + If we were tracing, we need to keep tracing. + There should never be the possibility of hitting the + root_cframe here. See note above about why we can't + just copy this from ``origin->cframe->use_tracing``. + */ + #if !GREENLET_PY312 + tstate->cframe->use_tracing = this->use_tracing; + #endif +#endif // GREENLET_USE_CFRAME +#if GREENLET_PY311 + #if GREENLET_PY312 + tstate->py_recursion_remaining = tstate->py_recursion_limit - this->py_recursion_depth; + tstate->c_recursion_remaining = Py_C_RECURSION_LIMIT - this->c_recursion_depth; + this->unexpose_frames(); + #else // \/ 3.11 + tstate->recursion_remaining = tstate->recursion_limit - this->recursion_depth; + #endif // GREENLET_PY312 + #if GREENLET_PY313 + tstate->current_frame = this->current_frame; + #elif GREENLET_USE_CFRAME + tstate->cframe->current_frame = this->current_frame; + #endif + tstate->datastack_chunk = this->datastack_chunk; + tstate->datastack_top = this->datastack_top; + tstate->datastack_limit = this->datastack_limit; + this->_top_frame.relinquish_ownership(); + #if GREENLET_PY313 + Py_XDECREF(tstate->delete_later); + tstate->delete_later = this->delete_later; + Py_CLEAR(this->delete_later); + #elif GREENLET_PY312 + tstate->trash.delete_nesting = this->trash_delete_nesting; + #else // not 3.12 + tstate->trash_delete_nesting = this->trash_delete_nesting; + #endif // GREENLET_PY312 +#else // not 3.11 + tstate->frame = this->_top_frame.relinquish_ownership(); + tstate->recursion_depth = this->recursion_depth; + tstate->trash_delete_nesting = this->trash_delete_nesting; +#endif // GREENLET_PY311 +} + +inline void PythonState::will_switch_from(PyThreadState *const origin_tstate) noexcept +{ +#if GREENLET_USE_CFRAME && !GREENLET_PY312 + // The weird thing is, we don't actually save this for an + // effect on the current greenlet, it's saved for an + // effect on the target greenlet. That is, we want + // continuity of this setting across the greenlet switch. + this->use_tracing = origin_tstate->cframe->use_tracing; +#endif +} + +void PythonState::set_initial_state(const PyThreadState* const tstate) noexcept +{ + this->_top_frame = nullptr; +#if GREENLET_PY312 + this->py_recursion_depth = tstate->py_recursion_limit - tstate->py_recursion_remaining; + // XXX: TODO: Comment from a reviewer: + // Should this be ``Py_C_RECURSION_LIMIT - tstate->c_recursion_remaining``? + // But to me it looks more like that might not be the right + // initialization either? + this->c_recursion_depth = tstate->py_recursion_limit - tstate->py_recursion_remaining; +#elif GREENLET_PY311 + this->recursion_depth = tstate->recursion_limit - tstate->recursion_remaining; +#else + this->recursion_depth = tstate->recursion_depth; +#endif +} +// TODO: Better state management about when we own the top frame. +int PythonState::tp_traverse(visitproc visit, void* arg, bool own_top_frame) noexcept +{ + Py_VISIT(this->_context.borrow()); + if (own_top_frame) { + Py_VISIT(this->_top_frame.borrow()); + } + return 0; +} + +void PythonState::tp_clear(bool own_top_frame) noexcept +{ + PythonStateContext::tp_clear(); + // If we get here owning a frame, + // we got dealloc'd without being finished. We may or may not be + // in the same thread. + if (own_top_frame) { + this->_top_frame.CLEAR(); + } +} + +#if GREENLET_USE_CFRAME +void PythonState::set_new_cframe(_PyCFrame& frame) noexcept +{ + frame = *PyThreadState_GET()->cframe; + /* Make the target greenlet refer to the stack value. */ + this->cframe = &frame; + /* + And restore the link to the previous frame so this one gets + unliked appropriately. + */ + this->cframe->previous = &PyThreadState_GET()->root_cframe; +} +#endif + +const PythonState::OwnedFrame& PythonState::top_frame() const noexcept +{ + return this->_top_frame; +} + +void PythonState::did_finish(PyThreadState* tstate) noexcept +{ +#if GREENLET_PY311 + // See https://github.com/gevent/gevent/issues/1924 and + // https://github.com/python-greenlet/greenlet/issues/328. In + // short, Python 3.11 allocates memory for frames as a sort of + // linked list that's kept as part of PyThreadState in the + // ``datastack_chunk`` member and friends. These are saved and + // restored as part of switching greenlets. + // + // When we initially switch to a greenlet, we set those to NULL. + // That causes the frame management code to treat this like a + // brand new thread and start a fresh list of chunks, beginning + // with a new "root" chunk. As we make calls in this greenlet, + // those chunks get added, and as calls return, they get popped. + // But the frame code (pystate.c) is careful to make sure that the + // root chunk never gets popped. + // + // Thus, when a greenlet exits for the last time, there will be at + // least a single root chunk that we must be responsible for + // deallocating. + // + // The complex part is that these chunks are allocated and freed + // using ``_PyObject_VirtualAlloc``/``Free``. Those aren't public + // functions, and they aren't exported for linking. It so happens + // that we know they are just thin wrappers around the Arena + // allocator, so we can use that directly to deallocate in a + // compatible way. + // + // CAUTION: Check this implementation detail on every major version. + // + // It might be nice to be able to do this in our destructor, but + // can we be sure that no one else is using that memory? Plus, as + // described below, our pointers may not even be valid anymore. As + // a special case, there is one time that we know we can do this, + // and that's from the destructor of the associated UserGreenlet + // (NOT main greenlet) + PyObjectArenaAllocator alloc; + _PyStackChunk* chunk = nullptr; + if (tstate) { + // We really did finish, we can never be switched to again. + chunk = tstate->datastack_chunk; + // Unfortunately, we can't do much sanity checking. Our + // this->datastack_chunk pointer is out of date (evaluation may + // have popped down through it already) so we can't verify that + // we deallocate it. I don't think we can even check datastack_top + // for the same reason. + + PyObject_GetArenaAllocator(&alloc); + tstate->datastack_chunk = nullptr; + tstate->datastack_limit = nullptr; + tstate->datastack_top = nullptr; + + } + else if (this->datastack_chunk) { + // The UserGreenlet (NOT the main greenlet!) is being deallocated. If we're + // still holding a stack chunk, it's garbage because we know + // we can never switch back to let cPython clean it up. + // Because the last time we got switched away from, and we + // haven't run since then, we know our chain is valid and can + // be dealloced. + chunk = this->datastack_chunk; + PyObject_GetArenaAllocator(&alloc); + } + + if (alloc.free && chunk) { + // In case the arena mechanism has been torn down already. + while (chunk) { + _PyStackChunk *prev = chunk->previous; + chunk->previous = nullptr; + alloc.free(alloc.ctx, chunk, chunk->size); + chunk = prev; + } + } + + this->datastack_chunk = nullptr; + this->datastack_limit = nullptr; + this->datastack_top = nullptr; +#endif +} + + +}; // namespace greenlet + +#endif // GREENLET_PYTHON_STATE_CPP diff --git a/psets/9/finance/env/lib/python3.12/site-packages/greenlet/TStackState.cpp b/psets/9/finance/env/lib/python3.12/site-packages/greenlet/TStackState.cpp new file mode 100644 index 0000000..9743ab5 --- /dev/null +++ b/psets/9/finance/env/lib/python3.12/site-packages/greenlet/TStackState.cpp @@ -0,0 +1,265 @@ +#ifndef GREENLET_STACK_STATE_CPP +#define GREENLET_STACK_STATE_CPP + +#include "TGreenlet.hpp" + +namespace greenlet { + +#ifdef GREENLET_USE_STDIO +#include +using std::cerr; +using std::endl; + +std::ostream& operator<<(std::ostream& os, const StackState& s) +{ + os << "StackState(stack_start=" << (void*)s._stack_start + << ", stack_stop=" << (void*)s.stack_stop + << ", stack_copy=" << (void*)s.stack_copy + << ", stack_saved=" << s._stack_saved + << ", stack_prev=" << s.stack_prev + << ", addr=" << &s + << ")"; + return os; +} +#endif + +StackState::StackState(void* mark, StackState& current) + : _stack_start(nullptr), + stack_stop((char*)mark), + stack_copy(nullptr), + _stack_saved(0), + /* Skip a dying greenlet */ + stack_prev(current._stack_start + ? ¤t + : current.stack_prev) +{ +} + +StackState::StackState() + : _stack_start(nullptr), + stack_stop(nullptr), + stack_copy(nullptr), + _stack_saved(0), + stack_prev(nullptr) +{ +} + +StackState::StackState(const StackState& other) +// can't use a delegating constructor because of +// MSVC for Python 2.7 + : _stack_start(nullptr), + stack_stop(nullptr), + stack_copy(nullptr), + _stack_saved(0), + stack_prev(nullptr) +{ + this->operator=(other); +} + +StackState& StackState::operator=(const StackState& other) +{ + if (&other == this) { + return *this; + } + if (other._stack_saved) { + throw std::runtime_error("Refusing to steal memory."); + } + + //If we have memory allocated, dispose of it + this->free_stack_copy(); + + this->_stack_start = other._stack_start; + this->stack_stop = other.stack_stop; + this->stack_copy = other.stack_copy; + this->_stack_saved = other._stack_saved; + this->stack_prev = other.stack_prev; + return *this; +} + +inline void StackState::free_stack_copy() noexcept +{ + PyMem_Free(this->stack_copy); + this->stack_copy = nullptr; + this->_stack_saved = 0; +} + +inline void StackState::copy_heap_to_stack(const StackState& current) noexcept +{ + + /* Restore the heap copy back into the C stack */ + if (this->_stack_saved != 0) { + memcpy(this->_stack_start, this->stack_copy, this->_stack_saved); + this->free_stack_copy(); + } + StackState* owner = const_cast(¤t); + if (!owner->_stack_start) { + owner = owner->stack_prev; /* greenlet is dying, skip it */ + } + while (owner && owner->stack_stop <= this->stack_stop) { + // cerr << "\tOwner: " << owner << endl; + owner = owner->stack_prev; /* find greenlet with more stack */ + } + this->stack_prev = owner; + // cerr << "\tFinished with: " << *this << endl; +} + +inline int StackState::copy_stack_to_heap_up_to(const char* const stop) noexcept +{ + /* Save more of g's stack into the heap -- at least up to 'stop' + g->stack_stop |________| + | | + | __ stop . . . . . + | | ==> . . + |________| _______ + | | | | + | | | | + g->stack_start | | |_______| g->stack_copy + */ + intptr_t sz1 = this->_stack_saved; + intptr_t sz2 = stop - this->_stack_start; + assert(this->_stack_start); + if (sz2 > sz1) { + char* c = (char*)PyMem_Realloc(this->stack_copy, sz2); + if (!c) { + PyErr_NoMemory(); + return -1; + } + memcpy(c + sz1, this->_stack_start + sz1, sz2 - sz1); + this->stack_copy = c; + this->_stack_saved = sz2; + } + return 0; +} + +inline int StackState::copy_stack_to_heap(char* const stackref, + const StackState& current) noexcept +{ + /* must free all the C stack up to target_stop */ + const char* const target_stop = this->stack_stop; + + StackState* owner = const_cast(¤t); + assert(owner->_stack_saved == 0); // everything is present on the stack + if (!owner->_stack_start) { + owner = owner->stack_prev; /* not saved if dying */ + } + else { + owner->_stack_start = stackref; + } + + while (owner->stack_stop < target_stop) { + /* ts_current is entierely within the area to free */ + if (owner->copy_stack_to_heap_up_to(owner->stack_stop)) { + return -1; /* XXX */ + } + owner = owner->stack_prev; + } + if (owner != this) { + if (owner->copy_stack_to_heap_up_to(target_stop)) { + return -1; /* XXX */ + } + } + return 0; +} + +inline bool StackState::started() const noexcept +{ + return this->stack_stop != nullptr; +} + +inline bool StackState::main() const noexcept +{ + return this->stack_stop == (char*)-1; +} + +inline bool StackState::active() const noexcept +{ + return this->_stack_start != nullptr; +} + +inline void StackState::set_active() noexcept +{ + assert(this->_stack_start == nullptr); + this->_stack_start = (char*)1; +} + +inline void StackState::set_inactive() noexcept +{ + this->_stack_start = nullptr; + // XXX: What if we still have memory out there? + // That case is actually triggered by + // test_issue251_issue252_explicit_reference_not_collectable (greenlet.tests.test_leaks.TestLeaks) + // and + // test_issue251_issue252_need_to_collect_in_background + // (greenlet.tests.test_leaks.TestLeaks) + // + // Those objects never get deallocated, so the destructor never + // runs. + // It *seems* safe to clean up the memory here? + if (this->_stack_saved) { + this->free_stack_copy(); + } +} + +inline intptr_t StackState::stack_saved() const noexcept +{ + return this->_stack_saved; +} + +inline char* StackState::stack_start() const noexcept +{ + return this->_stack_start; +} + + +inline StackState StackState::make_main() noexcept +{ + StackState s; + s._stack_start = (char*)1; + s.stack_stop = (char*)-1; + return s; +} + +StackState::~StackState() +{ + if (this->_stack_saved != 0) { + this->free_stack_copy(); + } +} + +void StackState::copy_from_stack(void* vdest, const void* vsrc, size_t n) const +{ + char* dest = static_cast(vdest); + const char* src = static_cast(vsrc); + if (src + n <= this->_stack_start + || src >= this->_stack_start + this->_stack_saved + || this->_stack_saved == 0) { + // Nothing we're copying was spilled from the stack + memcpy(dest, src, n); + return; + } + + if (src < this->_stack_start) { + // Copy the part before the saved stack. + // We know src + n > _stack_start due to the test above. + const size_t nbefore = this->_stack_start - src; + memcpy(dest, src, nbefore); + dest += nbefore; + src += nbefore; + n -= nbefore; + } + // We know src >= _stack_start after the before-copy, and + // src < _stack_start + _stack_saved due to the first if condition + size_t nspilled = std::min(n, this->_stack_start + this->_stack_saved - src); + memcpy(dest, this->stack_copy + (src - this->_stack_start), nspilled); + dest += nspilled; + src += nspilled; + n -= nspilled; + if (n > 0) { + // Copy the part after the saved stack + memcpy(dest, src, n); + } +} + +}; // namespace greenlet + +#endif // GREENLET_STACK_STATE_CPP diff --git a/psets/9/finance/env/lib/python3.12/site-packages/greenlet/TThreadState.hpp b/psets/9/finance/env/lib/python3.12/site-packages/greenlet/TThreadState.hpp new file mode 100644 index 0000000..e4e6f6c --- /dev/null +++ b/psets/9/finance/env/lib/python3.12/site-packages/greenlet/TThreadState.hpp @@ -0,0 +1,497 @@ +#ifndef GREENLET_THREAD_STATE_HPP +#define GREENLET_THREAD_STATE_HPP + +#include +#include + +#include "greenlet_internal.hpp" +#include "greenlet_refs.hpp" +#include "greenlet_thread_support.hpp" + +using greenlet::refs::BorrowedObject; +using greenlet::refs::BorrowedGreenlet; +using greenlet::refs::BorrowedMainGreenlet; +using greenlet::refs::OwnedMainGreenlet; +using greenlet::refs::OwnedObject; +using greenlet::refs::OwnedGreenlet; +using greenlet::refs::OwnedList; +using greenlet::refs::PyErrFetchParam; +using greenlet::refs::PyArgParseParam; +using greenlet::refs::ImmortalString; +using greenlet::refs::CreatedModule; +using greenlet::refs::PyErrPieces; +using greenlet::refs::NewReference; + +namespace greenlet { +/** + * Thread-local state of greenlets. + * + * Each native thread will get exactly one of these objects, + * automatically accessed through the best available thread-local + * mechanism the compiler supports (``thread_local`` for C++11 + * compilers or ``__thread``/``declspec(thread)`` for older GCC/clang + * or MSVC, respectively.) + * + * Previously, we kept thread-local state mostly in a bunch of + * ``static volatile`` variables in the main greenlet file.. This had + * the problem of requiring extra checks, loops, and great care + * accessing these variables if we potentially invoked any Python code + * that could release the GIL, because the state could change out from + * under us. Making the variables thread-local solves this problem. + * + * When we detected that a greenlet API accessing the current greenlet + * was invoked from a different thread than the greenlet belonged to, + * we stored a reference to the greenlet in the Python thread + * dictionary for the thread the greenlet belonged to. This could lead + * to memory leaks if the thread then exited (because of a reference + * cycle, as greenlets referred to the thread dictionary, and deleting + * non-current greenlets leaked their frame plus perhaps arguments on + * the C stack). If a thread exited while still having running + * greenlet objects (perhaps that had just switched back to the main + * greenlet), and did not invoke one of the greenlet APIs *in that + * thread, immediately before it exited, without some other thread + * then being invoked*, such a leak was guaranteed. + * + * This can be partly solved by using compiler thread-local variables + * instead of the Python thread dictionary, thus avoiding a cycle. + * + * To fully solve this problem, we need a reliable way to know that a + * thread is done and we should clean up the main greenlet. On POSIX, + * we can use the destructor function of ``pthread_key_create``, but + * there's nothing similar on Windows; a C++11 thread local object + * reliably invokes its destructor when the thread it belongs to exits + * (non-C++11 compilers offer ``__thread`` or ``declspec(thread)`` to + * create thread-local variables, but they can't hold C++ objects that + * invoke destructors; the C++11 version is the most portable solution + * I found). When the thread exits, we can drop references and + * otherwise manipulate greenlets and frames that we know can no + * longer be switched to. For compilers that don't support C++11 + * thread locals, we have a solution that uses the python thread + * dictionary, though it may not collect everything as promptly as + * other compilers do, if some other library is using the thread + * dictionary and has a cycle or extra reference. + * + * There are two small wrinkles. The first is that when the thread + * exits, it is too late to actually invoke Python APIs: the Python + * thread state is gone, and the GIL is released. To solve *this* + * problem, our destructor uses ``Py_AddPendingCall`` to transfer the + * destruction work to the main thread. (This is not an issue for the + * dictionary solution.) + * + * The second is that once the thread exits, the thread local object + * is invalid and we can't even access a pointer to it, so we can't + * pass it to ``Py_AddPendingCall``. This is handled by actually using + * a second object that's thread local (ThreadStateCreator) and having + * it dynamically allocate this object so it can live until the + * pending call runs. + */ + + + +class ThreadState { +private: + // As of commit 08ad1dd7012b101db953f492e0021fb08634afad + // this class needed 56 bytes in o Py_DEBUG build + // on 64-bit macOS 11. + // Adding the vector takes us up to 80 bytes () + + /* Strong reference to the main greenlet */ + OwnedMainGreenlet main_greenlet; + + /* Strong reference to the current greenlet. */ + OwnedGreenlet current_greenlet; + + /* Strong reference to the trace function, if any. */ + OwnedObject tracefunc; + + typedef std::vector > deleteme_t; + /* A vector of raw PyGreenlet pointers representing things that need + deleted when this thread is running. The vector owns the + references, but you need to manually INCREF/DECREF as you use + them. We don't use a vector because we + make copy of this vector, and that would become O(n) as all the + refcounts are incremented in the copy. + */ + deleteme_t deleteme; + +#ifdef GREENLET_NEEDS_EXCEPTION_STATE_SAVED + void* exception_state; +#endif + + static std::clock_t _clocks_used_doing_gc; + static ImmortalString get_referrers_name; + static PythonAllocator allocator; + + G_NO_COPIES_OF_CLS(ThreadState); + + + // Allocates a main greenlet for the thread state. If this fails, + // exits the process. Called only during constructing a ThreadState. + MainGreenlet* alloc_main() + { + PyGreenlet* gmain; + + /* create the main greenlet for this thread */ + gmain = reinterpret_cast(PyType_GenericAlloc(&PyGreenlet_Type, 0)); + if (gmain == NULL) { + throw PyFatalError("alloc_main failed to alloc"); //exits the process + } + + MainGreenlet* const main = new MainGreenlet(gmain, this); + + assert(Py_REFCNT(gmain) == 1); + assert(gmain->pimpl == main); + return main; + } + + +public: + static void* operator new(size_t UNUSED(count)) + { + return ThreadState::allocator.allocate(1); + } + + static void operator delete(void* ptr) + { + return ThreadState::allocator.deallocate(static_cast(ptr), + 1); + } + + static void init() + { + ThreadState::get_referrers_name = "get_referrers"; + ThreadState::_clocks_used_doing_gc = 0; + } + + ThreadState() + { + +#ifdef GREENLET_NEEDS_EXCEPTION_STATE_SAVED + this->exception_state = slp_get_exception_state(); +#endif + + // XXX: Potentially dangerous, exposing a not fully + // constructed object. + MainGreenlet* const main = this->alloc_main(); + this->main_greenlet = OwnedMainGreenlet::consuming( + main->self() + ); + assert(this->main_greenlet); + this->current_greenlet = main->self(); + // The main greenlet starts with 1 refs: The returned one. We + // then copied it to the current greenlet. + assert(this->main_greenlet.REFCNT() == 2); + } + + inline void restore_exception_state() + { +#ifdef GREENLET_NEEDS_EXCEPTION_STATE_SAVED + // It's probably important this be inlined and only call C + // functions to avoid adding an SEH frame. + slp_set_exception_state(this->exception_state); +#endif + } + + inline bool has_main_greenlet() const noexcept + { + return bool(this->main_greenlet); + } + + // Called from the ThreadStateCreator when we're in non-standard + // threading mode. In that case, there is an object in the Python + // thread state dictionary that points to us. The main greenlet + // also traverses into us, in which case it's crucial not to + // traverse back into the main greenlet. + int tp_traverse(visitproc visit, void* arg, bool traverse_main=true) + { + if (traverse_main) { + Py_VISIT(main_greenlet.borrow_o()); + } + if (traverse_main || current_greenlet != main_greenlet) { + Py_VISIT(current_greenlet.borrow_o()); + } + Py_VISIT(tracefunc.borrow()); + return 0; + } + + inline BorrowedMainGreenlet borrow_main_greenlet() const noexcept + { + assert(this->main_greenlet); + assert(this->main_greenlet.REFCNT() >= 2); + return this->main_greenlet; + }; + + inline OwnedMainGreenlet get_main_greenlet() const noexcept + { + return this->main_greenlet; + } + + /** + * In addition to returning a new reference to the currunt + * greenlet, this performs any maintenance needed. + */ + inline OwnedGreenlet get_current() + { + /* green_dealloc() cannot delete greenlets from other threads, so + it stores them in the thread dict; delete them now. */ + this->clear_deleteme_list(); + //assert(this->current_greenlet->main_greenlet == this->main_greenlet); + //assert(this->main_greenlet->main_greenlet == this->main_greenlet); + return this->current_greenlet; + } + + /** + * As for non-const get_current(); + */ + inline BorrowedGreenlet borrow_current() + { + this->clear_deleteme_list(); + return this->current_greenlet; + } + + /** + * Does no maintenance. + */ + inline OwnedGreenlet get_current() const + { + return this->current_greenlet; + } + + template + inline bool is_current(const refs::PyObjectPointer& obj) const + { + return this->current_greenlet.borrow_o() == obj.borrow_o(); + } + + inline void set_current(const OwnedGreenlet& target) + { + this->current_greenlet = target; + } + +private: + /** + * Deref and remove the greenlets from the deleteme list. Must be + * holding the GIL. + * + * If *murder* is true, then we must be called from a different + * thread than the one that these greenlets were running in. + * In that case, if the greenlet was actually running, we destroy + * the frame reference and otherwise make it appear dead before + * proceeding; otherwise, we would try (and fail) to raise an + * exception in it and wind up right back in this list. + */ + inline void clear_deleteme_list(const bool murder=false) + { + if (!this->deleteme.empty()) { + // It's possible we could add items to this list while + // running Python code if there's a thread switch, so we + // need to defensively copy it before that can happen. + deleteme_t copy = this->deleteme; + this->deleteme.clear(); // in case things come back on the list + for(deleteme_t::iterator it = copy.begin(), end = copy.end(); + it != end; + ++it ) { + PyGreenlet* to_del = *it; + if (murder) { + // Force each greenlet to appear dead; we can't raise an + // exception into it anymore anyway. + to_del->pimpl->murder_in_place(); + } + + // The only reference to these greenlets should be in + // this list, decreffing them should let them be + // deleted again, triggering calls to green_dealloc() + // in the correct thread (if we're not murdering). + // This may run arbitrary Python code and switch + // threads or greenlets! + Py_DECREF(to_del); + if (PyErr_Occurred()) { + PyErr_WriteUnraisable(nullptr); + PyErr_Clear(); + } + } + } + } + +public: + + /** + * Returns a new reference, or a false object. + */ + inline OwnedObject get_tracefunc() const + { + return tracefunc; + }; + + + inline void set_tracefunc(BorrowedObject tracefunc) + { + assert(tracefunc); + if (tracefunc == BorrowedObject(Py_None)) { + this->tracefunc.CLEAR(); + } + else { + this->tracefunc = tracefunc; + } + } + + /** + * Given a reference to a greenlet that some other thread + * attempted to delete (has a refcount of 0) store it for later + * deletion when the thread this state belongs to is current. + */ + inline void delete_when_thread_running(PyGreenlet* to_del) + { + Py_INCREF(to_del); + this->deleteme.push_back(to_del); + } + + /** + * Set to std::clock_t(-1) to disable. + */ + inline static std::clock_t& clocks_used_doing_gc() + { + return ThreadState::_clocks_used_doing_gc; + } + + ~ThreadState() + { + if (!PyInterpreterState_Head()) { + // We shouldn't get here (our callers protect us) + // but if we do, all we can do is bail early. + return; + } + + // We should not have an "origin" greenlet; that only exists + // for the temporary time during a switch, which should not + // be in progress as the thread dies. + //assert(!this->switching_state.origin); + + this->tracefunc.CLEAR(); + + // Forcibly GC as much as we can. + this->clear_deleteme_list(true); + + // The pending call did this. + assert(this->main_greenlet->thread_state() == nullptr); + + // If the main greenlet is the current greenlet, + // then we "fell off the end" and the thread died. + // It's possible that there is some other greenlet that + // switched to us, leaving a reference to the main greenlet + // on the stack, somewhere uncollectible. Try to detect that. + if (this->current_greenlet == this->main_greenlet && this->current_greenlet) { + assert(this->current_greenlet->is_currently_running_in_some_thread()); + // Drop one reference we hold. + this->current_greenlet.CLEAR(); + assert(!this->current_greenlet); + // Only our reference to the main greenlet should be left, + // But hold onto the pointer in case we need to do extra cleanup. + PyGreenlet* old_main_greenlet = this->main_greenlet.borrow(); + Py_ssize_t cnt = this->main_greenlet.REFCNT(); + this->main_greenlet.CLEAR(); + if (ThreadState::_clocks_used_doing_gc != std::clock_t(-1) + && cnt == 2 && Py_REFCNT(old_main_greenlet) == 1) { + // Highly likely that the reference is somewhere on + // the stack, not reachable by GC. Verify. + // XXX: This is O(n) in the total number of objects. + // TODO: Add a way to disable this at runtime, and + // another way to report on it. + std::clock_t begin = std::clock(); + NewReference gc(PyImport_ImportModule("gc")); + if (gc) { + OwnedObject get_referrers = gc.PyRequireAttr(ThreadState::get_referrers_name); + OwnedList refs(get_referrers.PyCall(old_main_greenlet)); + if (refs && refs.empty()) { + assert(refs.REFCNT() == 1); + // We found nothing! So we left a dangling + // reference: Probably the last thing some + // other greenlet did was call + // 'getcurrent().parent.switch()' to switch + // back to us. Clean it up. This will be the + // case on CPython 3.7 and newer, as they use + // an internal calling conversion that avoids + // creating method objects and storing them on + // the stack. + Py_DECREF(old_main_greenlet); + } + else if (refs + && refs.size() == 1 + && PyCFunction_Check(refs.at(0)) + && Py_REFCNT(refs.at(0)) == 2) { + assert(refs.REFCNT() == 1); + // Ok, we found a C method that refers to the + // main greenlet, and its only referenced + // twice, once in the list we just created, + // once from...somewhere else. If we can't + // find where else, then this is a leak. + // This happens in older versions of CPython + // that create a bound method object somewhere + // on the stack that we'll never get back to. + if (PyCFunction_GetFunction(refs.at(0).borrow()) == (PyCFunction)green_switch) { + BorrowedObject function_w = refs.at(0); + refs.clear(); // destroy the reference + // from the list. + // back to one reference. Can *it* be + // found? + assert(function_w.REFCNT() == 1); + refs = get_referrers.PyCall(function_w); + if (refs && refs.empty()) { + // Nope, it can't be found so it won't + // ever be GC'd. Drop it. + Py_CLEAR(function_w); + } + } + } + std::clock_t end = std::clock(); + ThreadState::_clocks_used_doing_gc += (end - begin); + } + } + } + + // We need to make sure this greenlet appears to be dead, + // because otherwise deallocing it would fail to raise an + // exception in it (the thread is dead) and put it back in our + // deleteme list. + if (this->current_greenlet) { + this->current_greenlet->murder_in_place(); + this->current_greenlet.CLEAR(); + } + + if (this->main_greenlet) { + // Couldn't have been the main greenlet that was running + // when the thread exited (because we already cleared this + // pointer if it was). This shouldn't be possible? + + // If the main greenlet was current when the thread died (it + // should be, right?) then we cleared its self pointer above + // when we cleared the current greenlet's main greenlet pointer. + // assert(this->main_greenlet->main_greenlet == this->main_greenlet + // || !this->main_greenlet->main_greenlet); + // // self reference, probably gone + // this->main_greenlet->main_greenlet.CLEAR(); + + // This will actually go away when the ivar is destructed. + this->main_greenlet.CLEAR(); + } + + if (PyErr_Occurred()) { + PyErr_WriteUnraisable(NULL); + PyErr_Clear(); + } + + } + +}; + +ImmortalString ThreadState::get_referrers_name(nullptr); +PythonAllocator ThreadState::allocator; +std::clock_t ThreadState::_clocks_used_doing_gc(0); + + + + + +}; // namespace greenlet + +#endif diff --git a/psets/9/finance/env/lib/python3.12/site-packages/greenlet/TThreadStateCreator.hpp b/psets/9/finance/env/lib/python3.12/site-packages/greenlet/TThreadStateCreator.hpp new file mode 100644 index 0000000..2ec7ab5 --- /dev/null +++ b/psets/9/finance/env/lib/python3.12/site-packages/greenlet/TThreadStateCreator.hpp @@ -0,0 +1,102 @@ +#ifndef GREENLET_THREAD_STATE_CREATOR_HPP +#define GREENLET_THREAD_STATE_CREATOR_HPP + +#include +#include + +#include "greenlet_internal.hpp" +#include "greenlet_refs.hpp" +#include "greenlet_thread_support.hpp" + +#include "TThreadState.hpp" + +namespace greenlet { + + +typedef void (*ThreadStateDestructor)(ThreadState* const); + +template +class ThreadStateCreator +{ +private: + // Initialized to 1, and, if still 1, created on access. + // Set to 0 on destruction. + ThreadState* _state; + G_NO_COPIES_OF_CLS(ThreadStateCreator); + + inline bool has_initialized_state() const noexcept + { + return this->_state != (ThreadState*)1; + } + + inline bool has_state() const noexcept + { + return this->has_initialized_state() && this->_state != nullptr; + } + +public: + + // Only one of these, auto created per thread. + // Constructing the state constructs the MainGreenlet. + ThreadStateCreator() : + _state((ThreadState*)1) + { + } + + ~ThreadStateCreator() + { + if (this->has_state()) { + Destructor(this->_state); + } + + this->_state = nullptr; + } + + inline ThreadState& state() + { + // The main greenlet will own this pointer when it is created, + // which will be right after this. The plan is to give every + // greenlet a pointer to the main greenlet for the thread it + // runs in; if we are doing something cross-thread, we need to + // access the pointer from the main greenlet. Deleting the + // thread, and hence the thread-local storage, will delete the + // state pointer in the main greenlet. + if (!this->has_initialized_state()) { + // XXX: Assuming allocation never fails + this->_state = new ThreadState; + // For non-standard threading, we need to store an object + // in the Python thread state dictionary so that it can be + // DECREF'd when the thread ends (ideally; the dict could + // last longer) and clean this object up. + } + if (!this->_state) { + throw std::runtime_error("Accessing state after destruction."); + } + return *this->_state; + } + + operator ThreadState&() + { + return this->state(); + } + + operator ThreadState*() + { + return &this->state(); + } + + inline int tp_traverse(visitproc visit, void* arg) + { + if (this->has_state()) { + return this->_state->tp_traverse(visit, arg); + } + return 0; + } + +}; + + + +}; // namespace greenlet + +#endif diff --git a/psets/9/finance/env/lib/python3.12/site-packages/greenlet/TThreadStateDestroy.cpp b/psets/9/finance/env/lib/python3.12/site-packages/greenlet/TThreadStateDestroy.cpp new file mode 100644 index 0000000..37fcc8c --- /dev/null +++ b/psets/9/finance/env/lib/python3.12/site-packages/greenlet/TThreadStateDestroy.cpp @@ -0,0 +1,258 @@ +/* -*- indent-tabs-mode: nil; tab-width: 4; -*- */ +/** + * Implementation of the ThreadState destructors. + * + * Format with: + * clang-format -i --style=file src/greenlet/greenlet.c + * + * + * Fix missing braces with: + * clang-tidy src/greenlet/greenlet.c -fix -checks="readability-braces-around-statements" +*/ +#ifndef T_THREADSTATE_DESTROY +#define T_THREADSTATE_DESTROY + +#include "TGreenlet.hpp" + +#include "greenlet_thread_support.hpp" +#include "greenlet_cpython_add_pending.hpp" +#include "greenlet_compiler_compat.hpp" +#include "TGreenletGlobals.cpp" +#include "TThreadState.hpp" +#include "TThreadStateCreator.hpp" + +namespace greenlet { + +extern "C" { + +struct ThreadState_DestroyNoGIL +{ + /** + This function uses the same lock that the PendingCallback does + */ + static void + MarkGreenletDeadAndQueueCleanup(ThreadState* const state) + { +#if GREENLET_BROKEN_THREAD_LOCAL_CLEANUP_JUST_LEAK + return; +#endif + // We are *NOT* holding the GIL. Our thread is in the middle + // of its death throes and the Python thread state is already + // gone so we can't use most Python APIs. One that is safe is + // ``Py_AddPendingCall``, unless the interpreter itself has + // been torn down. There is a limited number of calls that can + // be queued: 32 (NPENDINGCALLS) in CPython 3.10, so we + // coalesce these calls using our own queue. + + if (!MarkGreenletDeadIfNeeded(state)) { + // No state, or no greenlet + return; + } + + // XXX: Because we don't have the GIL, this is a race condition. + if (!PyInterpreterState_Head()) { + // We have to leak the thread state, if the + // interpreter has shut down when we're getting + // deallocated, we can't run the cleanup code that + // deleting it would imply. + return; + } + + AddToCleanupQueue(state); + + } + +private: + + // If the state has an allocated main greenlet: + // - mark the greenlet as dead by disassociating it from the state; + // - return 1 + // Otherwise, return 0. + static bool + MarkGreenletDeadIfNeeded(ThreadState* const state) + { + if (state && state->has_main_greenlet()) { + // mark the thread as dead ASAP. + // this is racy! If we try to throw or switch to a + // greenlet from this thread from some other thread before + // we clear the state pointer, it won't realize the state + // is dead which can crash the process. + PyGreenlet* p(state->borrow_main_greenlet().borrow()); + assert(p->pimpl->thread_state() == state || p->pimpl->thread_state() == nullptr); + dynamic_cast(p->pimpl)->thread_state(nullptr); + return true; + } + return false; + } + + static void + AddToCleanupQueue(ThreadState* const state) + { + assert(state && state->has_main_greenlet()); + + // NOTE: Because we're not holding the GIL here, some other + // Python thread could run and call ``os.fork()``, which would + // be bad if that happened while we are holding the cleanup + // lock (it wouldn't function in the child process). + // Make a best effort to try to keep the duration we hold the + // lock short. + // TODO: On platforms that support it, use ``pthread_atfork`` to + // drop this lock. + LockGuard cleanup_lock(*mod_globs->thread_states_to_destroy_lock); + + mod_globs->queue_to_destroy(state); + if (mod_globs->thread_states_to_destroy.size() == 1) { + // We added the first item to the queue. We need to schedule + // the cleanup. + + // A size greater than 1 means that we have already added the pending call, + // and in fact, it may be executing now. + // If it is executing, our lock makes sure that it will see the item we just added + // to the queue on its next iteration (after we release the lock) + // + // A size of 1 means there is no pending call, OR the pending call is + // currently executing, has dropped the lock, and is deleting the last item + // from the queue; its next iteration will go ahead and delete the item we just added. + // And the pending call we schedule here will have no work to do. + int result = AddPendingCall( + PendingCallback_DestroyQueueWithGIL, + nullptr); + if (result < 0) { + // Hmm, what can we do here? + fprintf(stderr, + "greenlet: WARNING: failed in call to Py_AddPendingCall; " + "expect a memory leak.\n"); + } + } + } + + static int + PendingCallback_DestroyQueueWithGIL(void* UNUSED(arg)) + { + // We're holding the GIL here, so no Python code should be able to + // run to call ``os.fork()``. + while (1) { + ThreadState* to_destroy; + { + LockGuard cleanup_lock(*mod_globs->thread_states_to_destroy_lock); + if (mod_globs->thread_states_to_destroy.empty()) { + break; + } + to_destroy = mod_globs->take_next_to_destroy(); + } + assert(to_destroy); + assert(to_destroy->has_main_greenlet()); + // Drop the lock while we do the actual deletion. + // This allows other calls to MarkGreenletDeadAndQueueCleanup + // to enter and add to our queue. + DestroyOneWithGIL(to_destroy); + } + return 0; + } + + static void + DestroyOneWithGIL(const ThreadState* const state) + { + // Holding the GIL. + // Passed a non-shared pointer to the actual thread state. + // state -> main greenlet + assert(state->has_main_greenlet()); + PyGreenlet* main(state->borrow_main_greenlet()); + // When we need to do cross-thread operations, we check this. + // A NULL value means the thread died some time ago. + // We do this here, rather than in a Python dealloc function + // for the greenlet, in case there's still a reference out + // there. + dynamic_cast(main->pimpl)->thread_state(nullptr); + + delete state; // Deleting this runs the destructor, DECREFs the main greenlet. + } + + // ensure this is actually defined. + static_assert(GREENLET_BROKEN_PY_ADD_PENDING == 1 || GREENLET_BROKEN_PY_ADD_PENDING == 0, + "GREENLET_BROKEN_PY_ADD_PENDING not defined correctly."); + +#if GREENLET_BROKEN_PY_ADD_PENDING + static int _push_pending_call(struct _pending_calls *pending, + int (*func)(void *), void *arg) + { + int i = pending->last; + int j = (i + 1) % NPENDINGCALLS; + if (j == pending->first) { + return -1; /* Queue full */ + } + pending->calls[i].func = func; + pending->calls[i].arg = arg; + pending->last = j; + return 0; + } + + static int AddPendingCall(int (*func)(void *), void *arg) + { + _PyRuntimeState *runtime = &_PyRuntime; + if (!runtime) { + // obviously impossible + return 0; + } + struct _pending_calls *pending = &runtime->ceval.pending; + if (!pending->lock) { + return 0; + } + int result = 0; + PyThread_acquire_lock(pending->lock, WAIT_LOCK); + if (!pending->finishing) { + result = _push_pending_call(pending, func, arg); + } + PyThread_release_lock(pending->lock); + SIGNAL_PENDING_CALLS(&runtime->ceval); + return result; + } +#else + // Python < 3.8 or >= 3.9 + static int AddPendingCall(int (*func)(void*), void* arg) + { + // If the interpreter is in the middle of finalizing, we can't add a + // pending call. Trying to do so will end up in a SIGSEGV, as + // Py_AddPendingCall will not be able to get the interpreter and will + // try to dereference a NULL pointer. It's possible this can still + // segfault if we happen to get context switched, and maybe we should + // just always implement our own AddPendingCall, but I'd like to see if + // this works first +#if GREENLET_PY313 + if (Py_IsFinalizing()) { +#else + if (_Py_IsFinalizing()) { +#endif +#ifdef GREENLET_DEBUG + // No need to log in the general case. Yes, we'll leak, + // but we're shutting down so it should be ok. + fprintf(stderr, + "greenlet: WARNING: Interpreter is finalizing. Ignoring " + "call to Py_AddPendingCall; \n"); +#endif + return 0; + } + return Py_AddPendingCall(func, arg); + } +#endif + + + + +}; +}; + +}; // namespace greenlet + +// The intent when GET_THREAD_STATE() is needed multiple times in a +// function is to take a reference to its return value in a local +// variable, to avoid the thread-local indirection. On some platforms +// (macOS), accessing a thread-local involves a function call (plus an +// initial function call in each function that uses a thread local); +// in contrast, static volatile variables are at some pre-computed +// offset. +typedef greenlet::ThreadStateCreator ThreadStateCreator; +static thread_local ThreadStateCreator g_thread_state_global; +#define GET_THREAD_STATE() g_thread_state_global + +#endif //T_THREADSTATE_DESTROY diff --git a/psets/9/finance/env/lib/python3.12/site-packages/greenlet/TUserGreenlet.cpp b/psets/9/finance/env/lib/python3.12/site-packages/greenlet/TUserGreenlet.cpp new file mode 100644 index 0000000..73a8133 --- /dev/null +++ b/psets/9/finance/env/lib/python3.12/site-packages/greenlet/TUserGreenlet.cpp @@ -0,0 +1,662 @@ +/* -*- indent-tabs-mode: nil; tab-width: 4; -*- */ +/** + * Implementation of greenlet::UserGreenlet. + * + * Format with: + * clang-format -i --style=file src/greenlet/greenlet.c + * + * + * Fix missing braces with: + * clang-tidy src/greenlet/greenlet.c -fix -checks="readability-braces-around-statements" +*/ +#ifndef T_USER_GREENLET_CPP +#define T_USER_GREENLET_CPP + +#include "greenlet_internal.hpp" +#include "TGreenlet.hpp" + +#include "TThreadStateDestroy.cpp" + + +namespace greenlet { +using greenlet::refs::BorrowedMainGreenlet; +greenlet::PythonAllocator UserGreenlet::allocator; + +void* UserGreenlet::operator new(size_t UNUSED(count)) +{ + return allocator.allocate(1); +} + + +void UserGreenlet::operator delete(void* ptr) +{ + return allocator.deallocate(static_cast(ptr), + 1); +} + + +UserGreenlet::UserGreenlet(PyGreenlet* p, BorrowedGreenlet the_parent) + : Greenlet(p), _parent(the_parent) +{ +} + +UserGreenlet::~UserGreenlet() +{ + // Python 3.11: If we don't clear out the raw frame datastack + // when deleting an unfinished greenlet, + // TestLeaks.test_untracked_memory_doesnt_increase_unfinished_thread_dealloc_in_main fails. + this->python_state.did_finish(nullptr); + this->tp_clear(); +} + + +const BorrowedMainGreenlet +UserGreenlet::main_greenlet() const +{ + return this->_main_greenlet; +} + + +BorrowedMainGreenlet +UserGreenlet::find_main_greenlet_in_lineage() const +{ + if (this->started()) { + assert(this->_main_greenlet); + return BorrowedMainGreenlet(this->_main_greenlet); + } + + if (!this->_parent) { + /* garbage collected greenlet in chain */ + // XXX: WHAT? + return BorrowedMainGreenlet(nullptr); + } + + return this->_parent->find_main_greenlet_in_lineage(); +} + + +/** + * CAUTION: This will allocate memory and may trigger garbage + * collection and arbitrary Python code. + */ +OwnedObject +UserGreenlet::throw_GreenletExit_during_dealloc(const ThreadState& current_thread_state) +{ + /* The dying greenlet cannot be a parent of ts_current + because the 'parent' field chain would hold a + reference */ + UserGreenlet::ParentIsCurrentGuard with_current_parent(this, current_thread_state); + + // We don't care about the return value, only whether an + // exception happened. Whether or not an exception happens, + // we need to restore the parent in case the greenlet gets + // resurrected. + return Greenlet::throw_GreenletExit_during_dealloc(current_thread_state); +} + +ThreadState* +UserGreenlet::thread_state() const noexcept +{ + // TODO: maybe make this throw, if the thread state isn't there? + // if (!this->main_greenlet) { + // throw std::runtime_error("No thread state"); // TODO: Better exception + // } + if (!this->_main_greenlet) { + return nullptr; + } + return this->_main_greenlet->thread_state(); +} + + +bool +UserGreenlet::was_running_in_dead_thread() const noexcept +{ + return this->_main_greenlet && !this->thread_state(); +} + +OwnedObject +UserGreenlet::g_switch() +{ + assert(this->args() || PyErr_Occurred()); + + try { + this->check_switch_allowed(); + } + catch (const PyErrOccurred&) { + this->release_args(); + throw; + } + + // Switching greenlets used to attempt to clean out ones that need + // deleted *if* we detected a thread switch. Should it still do + // that? + // An issue is that if we delete a greenlet from another thread, + // it gets queued to this thread, and ``kill_greenlet()`` switches + // back into the greenlet + + /* find the real target by ignoring dead greenlets, + and if necessary starting a greenlet. */ + switchstack_result_t err; + Greenlet* target = this; + // TODO: probably cleaner to handle the case where we do + // switch to ourself separately from the other cases. + // This can probably even further be simplified if we keep + // track of the switching_state we're going for and just call + // into g_switch() if it's not ourself. The main problem with that + // is that we would be using more stack space. + bool target_was_me = true; + bool was_initial_stub = false; + while (target) { + if (target->active()) { + if (!target_was_me) { + target->args() <<= this->args(); + assert(!this->args()); + } + err = target->g_switchstack(); + break; + } + if (!target->started()) { + // We never encounter a main greenlet that's not started. + assert(!target->main()); + UserGreenlet* real_target = static_cast(target); + assert(real_target); + void* dummymarker; + was_initial_stub = true; + if (!target_was_me) { + target->args() <<= this->args(); + assert(!this->args()); + } + try { + // This can only throw back to us while we're + // still in this greenlet. Once the new greenlet + // is bootstrapped, it has its own exception state. + err = real_target->g_initialstub(&dummymarker); + } + catch (const PyErrOccurred&) { + this->release_args(); + throw; + } + catch (const GreenletStartedWhileInPython&) { + // The greenlet was started sometime before this + // greenlet actually switched to it, i.e., + // "concurrent" calls to switch() or throw(). + // We need to retry the switch. + // Note that the current greenlet has been reset + // to this one (or we wouldn't be running!) + continue; + } + break; + } + + target = target->parent(); + target_was_me = false; + } + // The ``this`` pointer and all other stack or register based + // variables are invalid now, at least where things succeed + // above. + // But this one, probably not so much? It's not clear if it's + // safe to throw an exception at this point. + + if (err.status < 0) { + // If we get here, either g_initialstub() + // failed, or g_switchstack() failed. Either one of those + // cases SHOULD leave us in the original greenlet with a valid + // stack. + return this->on_switchstack_or_initialstub_failure(target, err, target_was_me, was_initial_stub); + } + + // err.the_new_current_greenlet would be the same as ``target``, + // if target wasn't probably corrupt. + return err.the_new_current_greenlet->g_switch_finish(err); +} + + + +Greenlet::switchstack_result_t +UserGreenlet::g_initialstub(void* mark) +{ + OwnedObject run; + + // We need to grab a reference to the current switch arguments + // in case we're entered concurrently during the call to + // GetAttr() and have to try again. + // We'll restore them when we return in that case. + // Scope them tightly to avoid ref leaks. + { + SwitchingArgs args(this->args()); + + /* save exception in case getattr clears it */ + PyErrPieces saved; + + /* + self.run is the object to call in the new greenlet. + This could run arbitrary python code and switch greenlets! + */ + run = this->self().PyRequireAttr(mod_globs->str_run); + /* restore saved exception */ + saved.PyErrRestore(); + + + /* recheck that it's safe to switch in case greenlet reparented anywhere above */ + this->check_switch_allowed(); + + /* by the time we got here another start could happen elsewhere, + * that means it should now be a regular switch. + * This can happen if the Python code is a subclass that implements + * __getattribute__ or __getattr__, or makes ``run`` a descriptor; + * all of those can run arbitrary code that switches back into + * this greenlet. + */ + if (this->stack_state.started()) { + // the successful switch cleared these out, we need to + // restore our version. They will be copied on up to the + // next target. + assert(!this->args()); + this->args() <<= args; + throw GreenletStartedWhileInPython(); + } + } + + // Sweet, if we got here, we have the go-ahead and will switch + // greenlets. + // Nothing we do from here on out should allow for a thread or + // greenlet switch: No arbitrary calls to Python, including + // decref'ing + +#if GREENLET_USE_CFRAME + /* OK, we need it, we're about to switch greenlets, save the state. */ + /* + See green_new(). This is a stack-allocated variable used + while *self* is in PyObject_Call(). + We want to defer copying the state info until we're sure + we need it and are in a stable place to do so. + */ + _PyCFrame trace_info; + + this->python_state.set_new_cframe(trace_info); +#endif + /* start the greenlet */ + ThreadState& thread_state = GET_THREAD_STATE().state(); + this->stack_state = StackState(mark, + thread_state.borrow_current()->stack_state); + this->python_state.set_initial_state(PyThreadState_GET()); + this->exception_state.clear(); + this->_main_greenlet = thread_state.get_main_greenlet(); + + /* perform the initial switch */ + switchstack_result_t err = this->g_switchstack(); + /* returns twice! + The 1st time with ``err == 1``: we are in the new greenlet. + This one owns a greenlet that used to be current. + The 2nd time with ``err <= 0``: back in the caller's + greenlet; this happens if the child finishes or switches + explicitly to us. Either way, the ``err`` variable is + created twice at the same memory location, but possibly + having different ``origin`` values. Note that it's not + constructed for the second time until the switch actually happens. + */ + if (err.status == 1) { + // In the new greenlet. + + // This never returns! Calling inner_bootstrap steals + // the contents of our run object within this stack frame, so + // it is not valid to do anything with it. + try { + this->inner_bootstrap(err.origin_greenlet.relinquish_ownership(), + run.relinquish_ownership()); + } + // Getting a C++ exception here isn't good. It's probably a + // bug in the underlying greenlet, meaning it's probably a + // C++ extension. We're going to abort anyway, but try to + // display some nice information *if* possible. Some obscure + // platforms don't properly support this (old 32-bit Arm, see see + // https://github.com/python-greenlet/greenlet/issues/385); that's not + // great, but should usually be OK because, as mentioned above, we're + // terminating anyway. + // + // The catching is tested by + // ``test_cpp.CPPTests.test_unhandled_exception_in_greenlet_aborts``. + // + // PyErrOccurred can theoretically be thrown by + // inner_bootstrap() -> g_switch_finish(), but that should + // never make it back to here. It is a std::exception and + // would be caught if it is. + catch (const std::exception& e) { + std::string base = "greenlet: Unhandled C++ exception: "; + base += e.what(); + Py_FatalError(base.c_str()); + } + catch (...) { + // Some compilers/runtimes use exceptions internally. + // It appears that GCC on Linux with libstdc++ throws an + // exception internally at process shutdown time to unwind + // stacks and clean up resources. Depending on exactly + // where we are when the process exits, that could result + // in an unknown exception getting here. If we + // Py_FatalError() or abort() here, we interfere with + // orderly process shutdown. Throwing the exception on up + // is the right thing to do. + // + // gevent's ``examples/dns_mass_resolve.py`` demonstrates this. +#ifndef NDEBUG + fprintf(stderr, + "greenlet: inner_bootstrap threw unknown exception; " + "is the process terminating?\n"); +#endif + throw; + } + Py_FatalError("greenlet: inner_bootstrap returned with no exception.\n"); + } + + + // In contrast, notice that we're keeping the origin greenlet + // around as an owned reference; we need it to call the trace + // function for the switch back into the parent. It was only + // captured at the time the switch actually happened, though, + // so we haven't been keeping an extra reference around this + // whole time. + + /* back in the parent */ + if (err.status < 0) { + /* start failed badly, restore greenlet state */ + this->stack_state = StackState(); + this->_main_greenlet.CLEAR(); + // CAUTION: This may run arbitrary Python code. + run.CLEAR(); // inner_bootstrap didn't run, we own the reference. + } + + // In the success case, the spawned code (inner_bootstrap) will + // take care of decrefing this, so we relinquish ownership so as + // to not double-decref. + + run.relinquish_ownership(); + + return err; +} + + +void +UserGreenlet::inner_bootstrap(PyGreenlet* origin_greenlet, PyObject* run) +{ + // The arguments here would be another great place for move. + // As it is, we take them as a reference so that when we clear + // them we clear what's on the stack above us. Do that NOW, and + // without using a C++ RAII object, + // so there's no way that exiting the parent frame can clear it, + // or we clear it unexpectedly. This arises in the context of the + // interpreter shutting down. See https://github.com/python-greenlet/greenlet/issues/325 + //PyObject* run = _run.relinquish_ownership(); + + /* in the new greenlet */ + assert(this->thread_state()->borrow_current() == BorrowedGreenlet(this->_self)); + // C++ exceptions cannot propagate to the parent greenlet from + // here. (TODO: Do we need a catch(...) clause, perhaps on the + // function itself? ALl we could do is terminate the program.) + // NOTE: On 32-bit Windows, the call chain is extremely + // important here in ways that are subtle, having to do with + // the depth of the SEH list. The call to restore it MUST NOT + // add a new SEH handler to the list, or we'll restore it to + // the wrong thing. + this->thread_state()->restore_exception_state(); + /* stack variables from above are no good and also will not unwind! */ + // EXCEPT: That can't be true, we access run, among others, here. + + this->stack_state.set_active(); /* running */ + + // We're about to possibly run Python code again, which + // could switch back/away to/from us, so we need to grab the + // arguments locally. + SwitchingArgs args; + args <<= this->args(); + assert(!this->args()); + + // XXX: We could clear this much earlier, right? + // Or would that introduce the possibility of running Python + // code when we don't want to? + // CAUTION: This may run arbitrary Python code. + this->_run_callable.CLEAR(); + + + // The first switch we need to manually call the trace + // function here instead of in g_switch_finish, because we + // never return there. + if (OwnedObject tracefunc = this->thread_state()->get_tracefunc()) { + OwnedGreenlet trace_origin; + trace_origin = origin_greenlet; + try { + g_calltrace(tracefunc, + args ? mod_globs->event_switch : mod_globs->event_throw, + trace_origin, + this->_self); + } + catch (const PyErrOccurred&) { + /* Turn trace errors into switch throws */ + args.CLEAR(); + } + } + + // We no longer need the origin, it was only here for + // tracing. + // We may never actually exit this stack frame so we need + // to explicitly clear it. + // This could run Python code and switch. + Py_CLEAR(origin_greenlet); + + OwnedObject result; + if (!args) { + /* pending exception */ + result = NULL; + } + else { + /* call g.run(*args, **kwargs) */ + // This could result in further switches + try { + //result = run.PyCall(args.args(), args.kwargs()); + // CAUTION: Just invoking this, before the function even + // runs, may cause memory allocations, which may trigger + // GC, which may run arbitrary Python code. + result = OwnedObject::consuming(PyObject_Call(run, args.args().borrow(), args.kwargs().borrow())); + } + catch (...) { + // Unhandled C++ exception! + + // If we declare ourselves as noexcept, if we don't catch + // this here, most platforms will just abort() the + // process. But on 64-bit Windows with older versions of + // the C runtime, this can actually corrupt memory and + // just return. We see this when compiling with the + // Windows 7.0 SDK targeting Windows Server 2008, but not + // when using the Appveyor Visual Studio 2019 image. So + // this currently only affects Python 2.7 on Windows 64. + // That is, the tests pass and the runtime aborts + // everywhere else. + // + // However, if we catch it and try to continue with a + // Python error, then all Windows 64 bit platforms corrupt + // memory. So all we can do is manually abort, hopefully + // with a good error message. (Note that the above was + // tested WITHOUT the `/EHr` switch being used at compile + // time, so MSVC may have "optimized" out important + // checking. Using that switch, we may be in a better + // place in terms of memory corruption.) But sometimes it + // can't be caught here at all, which is confusing but not + // terribly surprising; so again, the G_NOEXCEPT_WIN32 + // plus "/EHr". + // + // Hopefully the basic C stdlib is still functional enough + // for us to at least print an error. + // + // It gets more complicated than that, though, on some + // platforms, specifically at least Linux/gcc/libstdc++. They use + // an exception to unwind the stack when a background + // thread exits. (See comments about noexcept.) So this + // may not actually represent anything untoward. On those + // platforms we allow throws of this to propagate, or + // attempt to anyway. +# if defined(WIN32) || defined(_WIN32) + Py_FatalError( + "greenlet: Unhandled C++ exception from a greenlet run function. " + "Because memory is likely corrupted, terminating process."); + std::abort(); +#else + throw; +#endif + } + } + // These lines may run arbitrary code + args.CLEAR(); + Py_CLEAR(run); + + if (!result + && mod_globs->PyExc_GreenletExit.PyExceptionMatches() + && (this->args())) { + // This can happen, for example, if our only reference + // goes away after we switch back to the parent. + // See test_dealloc_switch_args_not_lost + PyErrPieces clear_error; + result <<= this->args(); + result = single_result(result); + } + this->release_args(); + this->python_state.did_finish(PyThreadState_GET()); + + result = g_handle_exit(result); + assert(this->thread_state()->borrow_current() == this->_self); + + /* jump back to parent */ + this->stack_state.set_inactive(); /* dead */ + + + // TODO: Can we decref some things here? Release our main greenlet + // and maybe parent? + for (Greenlet* parent = this->_parent; + parent; + parent = parent->parent()) { + // We need to somewhere consume a reference to + // the result; in most cases we'll never have control + // back in this stack frame again. Calling + // green_switch actually adds another reference! + // This would probably be clearer with a specific API + // to hand results to the parent. + parent->args() <<= result; + assert(!result); + // The parent greenlet now owns the result; in the + // typical case we'll never get back here to assign to + // result and thus release the reference. + try { + result = parent->g_switch(); + } + catch (const PyErrOccurred&) { + // Ignore, keep passing the error on up. + } + + /* Return here means switch to parent failed, + * in which case we throw *current* exception + * to the next parent in chain. + */ + assert(!result); + } + /* We ran out of parents, cannot continue */ + PyErr_WriteUnraisable(this->self().borrow_o()); + Py_FatalError("greenlet: ran out of parent greenlets while propagating exception; " + "cannot continue"); + std::abort(); +} + +void +UserGreenlet::run(const BorrowedObject nrun) +{ + if (this->started()) { + throw AttributeError( + "run cannot be set " + "after the start of the greenlet"); + } + this->_run_callable = nrun; +} + +const OwnedGreenlet +UserGreenlet::parent() const +{ + return this->_parent; +} + +void +UserGreenlet::parent(const BorrowedObject raw_new_parent) +{ + if (!raw_new_parent) { + throw AttributeError("can't delete attribute"); + } + + BorrowedMainGreenlet main_greenlet_of_new_parent; + BorrowedGreenlet new_parent(raw_new_parent.borrow()); // could + // throw + // TypeError! + for (BorrowedGreenlet p = new_parent; p; p = p->parent()) { + if (p == this->self()) { + throw ValueError("cyclic parent chain"); + } + main_greenlet_of_new_parent = p->main_greenlet(); + } + + if (!main_greenlet_of_new_parent) { + throw ValueError("parent must not be garbage collected"); + } + + if (this->started() + && this->_main_greenlet != main_greenlet_of_new_parent) { + throw ValueError("parent cannot be on a different thread"); + } + + this->_parent = new_parent; +} + +void +UserGreenlet::murder_in_place() +{ + this->_main_greenlet.CLEAR(); + Greenlet::murder_in_place(); +} + +bool +UserGreenlet::belongs_to_thread(const ThreadState* thread_state) const +{ + return Greenlet::belongs_to_thread(thread_state) && this->_main_greenlet == thread_state->borrow_main_greenlet(); +} + + +int +UserGreenlet::tp_traverse(visitproc visit, void* arg) +{ + Py_VISIT(this->_parent.borrow_o()); + Py_VISIT(this->_main_greenlet.borrow_o()); + Py_VISIT(this->_run_callable.borrow_o()); + + return Greenlet::tp_traverse(visit, arg); +} + +int +UserGreenlet::tp_clear() +{ + Greenlet::tp_clear(); + this->_parent.CLEAR(); + this->_main_greenlet.CLEAR(); + this->_run_callable.CLEAR(); + return 0; +} + +UserGreenlet::ParentIsCurrentGuard::ParentIsCurrentGuard(UserGreenlet* p, + const ThreadState& thread_state) + : oldparent(p->_parent), + greenlet(p) +{ + p->_parent = thread_state.get_current(); +} + +UserGreenlet::ParentIsCurrentGuard::~ParentIsCurrentGuard() +{ + this->greenlet->_parent = oldparent; + oldparent.CLEAR(); +} + +}; //namespace greenlet +#endif diff --git a/psets/9/finance/env/lib/python3.12/site-packages/greenlet/__init__.py b/psets/9/finance/env/lib/python3.12/site-packages/greenlet/__init__.py new file mode 100644 index 0000000..b2dcc9b --- /dev/null +++ b/psets/9/finance/env/lib/python3.12/site-packages/greenlet/__init__.py @@ -0,0 +1,71 @@ +# -*- coding: utf-8 -*- +""" +The root of the greenlet package. +""" +from __future__ import absolute_import +from __future__ import division +from __future__ import print_function + +__all__ = [ + '__version__', + '_C_API', + + 'GreenletExit', + 'error', + + 'getcurrent', + 'greenlet', + + 'gettrace', + 'settrace', +] + +# pylint:disable=no-name-in-module + +### +# Metadata +### +__version__ = '3.1.1' +from ._greenlet import _C_API # pylint:disable=no-name-in-module + +### +# Exceptions +### +from ._greenlet import GreenletExit +from ._greenlet import error + +### +# greenlets +### +from ._greenlet import getcurrent +from ._greenlet import greenlet + +### +# tracing +### +try: + from ._greenlet import gettrace + from ._greenlet import settrace +except ImportError: + # Tracing wasn't supported. + # XXX: The option to disable it was removed in 1.0, + # so this branch should be dead code. + pass + +### +# Constants +# These constants aren't documented and aren't recommended. +# In 1.0, USE_GC and USE_TRACING are always true, and USE_CONTEXT_VARS +# is the same as ``sys.version_info[:2] >= 3.7`` +### +from ._greenlet import GREENLET_USE_CONTEXT_VARS # pylint:disable=unused-import +from ._greenlet import GREENLET_USE_GC # pylint:disable=unused-import +from ._greenlet import GREENLET_USE_TRACING # pylint:disable=unused-import + +# Controlling the use of the gc module. Provisional API for this greenlet +# implementation in 2.0. +from ._greenlet import CLOCKS_PER_SEC # pylint:disable=unused-import +from ._greenlet import enable_optional_cleanup # pylint:disable=unused-import +from ._greenlet import get_clocks_used_doing_optional_cleanup # pylint:disable=unused-import + +# Other APIS in the _greenlet module are for test support. diff --git a/psets/9/finance/env/lib/python3.12/site-packages/greenlet/__pycache__/__init__.cpython-312.pyc b/psets/9/finance/env/lib/python3.12/site-packages/greenlet/__pycache__/__init__.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..d8ebae09aeb2fd5a963ddc7dbe0e2efe693f673b GIT binary patch literal 1075 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

JA}s;t=4KA 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 WkM?i=c4;R4qCZ>xlazwG^!`5}&RqWh literal 0 HcmV?d00001 diff --git a/psets/9/finance/env/lib/python3.12/site-packages/greenlet/greenlet.cpp b/psets/9/finance/env/lib/python3.12/site-packages/greenlet/greenlet.cpp new file mode 100644 index 0000000..e8d92a0 --- /dev/null +++ b/psets/9/finance/env/lib/python3.12/site-packages/greenlet/greenlet.cpp @@ -0,0 +1,320 @@ +/* -*- indent-tabs-mode: nil; tab-width: 4; -*- */ +/* Format with: + * clang-format -i --style=file src/greenlet/greenlet.c + * + * + * Fix missing braces with: + * clang-tidy src/greenlet/greenlet.c -fix -checks="readability-braces-around-statements" +*/ +#include +#include +#include +#include + + +#define PY_SSIZE_T_CLEAN +#include +#include "structmember.h" // PyMemberDef + +#include "greenlet_internal.hpp" +// Code after this point can assume access to things declared in stdint.h, +// including the fixed-width types. This goes for the platform-specific switch functions +// as well. +#include "greenlet_refs.hpp" +#include "greenlet_slp_switch.hpp" + +#include "greenlet_thread_support.hpp" +#include "TGreenlet.hpp" + +#include "TGreenletGlobals.cpp" + +#include "TGreenlet.cpp" +#include "TMainGreenlet.cpp" +#include "TUserGreenlet.cpp" +#include "TBrokenGreenlet.cpp" +#include "TExceptionState.cpp" +#include "TPythonState.cpp" +#include "TStackState.cpp" + +#include "TThreadState.hpp" +#include "TThreadStateCreator.hpp" +#include "TThreadStateDestroy.cpp" + +#include "PyGreenlet.cpp" +#include "PyGreenletUnswitchable.cpp" +#include "CObjects.cpp" + +using greenlet::LockGuard; +using greenlet::LockInitError; +using greenlet::PyErrOccurred; +using greenlet::Require; + +using greenlet::g_handle_exit; +using greenlet::single_result; + +using greenlet::Greenlet; +using greenlet::UserGreenlet; +using greenlet::MainGreenlet; +using greenlet::BrokenGreenlet; +using greenlet::ThreadState; +using greenlet::PythonState; + + + +// ******* Implementation of things from included files +template +greenlet::refs::_BorrowedGreenlet& greenlet::refs::_BorrowedGreenlet::operator=(const greenlet::refs::BorrowedObject& other) +{ + this->_set_raw_pointer(static_cast(other)); + return *this; +} + +template +inline greenlet::refs::_BorrowedGreenlet::operator Greenlet*() const noexcept +{ + if (!this->p) { + return nullptr; + } + return reinterpret_cast(this->p)->pimpl; +} + +template +greenlet::refs::_BorrowedGreenlet::_BorrowedGreenlet(const BorrowedObject& p) + : BorrowedReference(nullptr) +{ + + this->_set_raw_pointer(p.borrow()); +} + +template +inline greenlet::refs::_OwnedGreenlet::operator Greenlet*() const noexcept +{ + if (!this->p) { + return nullptr; + } + return reinterpret_cast(this->p)->pimpl; +} + + + +#ifdef __clang__ +# pragma clang diagnostic push +# pragma clang diagnostic ignored "-Wmissing-field-initializers" +# pragma clang diagnostic ignored "-Wwritable-strings" +#elif defined(__GNUC__) +# pragma GCC diagnostic push +// warning: ISO C++ forbids converting a string constant to ‘char*’ +// (The python APIs aren't const correct and accept writable char*) +# pragma GCC diagnostic ignored "-Wwrite-strings" +#endif + + +/*********************************************************** + +A PyGreenlet is a range of C stack addresses that must be +saved and restored in such a way that the full range of the +stack contains valid data when we switch to it. + +Stack layout for a greenlet: + + | ^^^ | + | older data | + | | + stack_stop . |_______________| + . | | + . | greenlet data | + . | in stack | + . * |_______________| . . _____________ stack_copy + stack_saved + . | | | | + . | data | |greenlet data| + . | unrelated | | saved | + . | to | | in heap | + stack_start . | this | . . |_____________| stack_copy + | greenlet | + | | + | newer data | + | vvv | + + +Note that a greenlet's stack data is typically partly at its correct +place in the stack, and partly saved away in the heap, but always in +the above configuration: two blocks, the more recent one in the heap +and the older one still in the stack (either block may be empty). + +Greenlets are chained: each points to the previous greenlet, which is +the one that owns the data currently in the C stack above my +stack_stop. The currently running greenlet is the first element of +this chain. The main (initial) greenlet is the last one. Greenlets +whose stack is entirely in the heap can be skipped from the chain. + +The chain is not related to execution order, but only to the order +in which bits of C stack happen to belong to greenlets at a particular +point in time. + +The main greenlet doesn't have a stack_stop: it is responsible for the +complete rest of the C stack, and we don't know where it begins. We +use (char*) -1, the largest possible address. + +States: + stack_stop == NULL && stack_start == NULL: did not start yet + stack_stop != NULL && stack_start == NULL: already finished + stack_stop != NULL && stack_start != NULL: active + +The running greenlet's stack_start is undefined but not NULL. + + ***********************************************************/ + + + + +/***********************************************************/ + +/* Some functions must not be inlined: + * slp_restore_state, when inlined into slp_switch might cause + it to restore stack over its own local variables + * slp_save_state, when inlined would add its own local + variables to the saved stack, wasting space + * slp_switch, cannot be inlined for obvious reasons + * g_initialstub, when inlined would receive a pointer into its + own stack frame, leading to incomplete stack save/restore + +g_initialstub is a member function and declared virtual so that the +compiler always calls it through a vtable. + +slp_save_state and slp_restore_state are also member functions. They +are called from trampoline functions that themselves are declared as +not eligible for inlining. +*/ + +extern "C" { +static int GREENLET_NOINLINE(slp_save_state_trampoline)(char* stackref) +{ + return switching_thread_state->slp_save_state(stackref); +} +static void GREENLET_NOINLINE(slp_restore_state_trampoline)() +{ + switching_thread_state->slp_restore_state(); +} +} + + +/***********************************************************/ + + +#include "PyModule.cpp" + + + +static PyObject* +greenlet_internal_mod_init() noexcept +{ + static void* _PyGreenlet_API[PyGreenlet_API_pointers]; + + try { + CreatedModule m(greenlet_module_def); + + Require(PyType_Ready(&PyGreenlet_Type)); + Require(PyType_Ready(&PyGreenletUnswitchable_Type)); + + mod_globs = new greenlet::GreenletGlobals; + ThreadState::init(); + + m.PyAddObject("greenlet", PyGreenlet_Type); + m.PyAddObject("UnswitchableGreenlet", PyGreenletUnswitchable_Type); + m.PyAddObject("error", mod_globs->PyExc_GreenletError); + m.PyAddObject("GreenletExit", mod_globs->PyExc_GreenletExit); + + m.PyAddObject("GREENLET_USE_GC", 1); + m.PyAddObject("GREENLET_USE_TRACING", 1); + m.PyAddObject("GREENLET_USE_CONTEXT_VARS", 1L); + m.PyAddObject("GREENLET_USE_STANDARD_THREADING", 1L); + + OwnedObject clocks_per_sec = OwnedObject::consuming(PyLong_FromSsize_t(CLOCKS_PER_SEC)); + m.PyAddObject("CLOCKS_PER_SEC", clocks_per_sec); + + /* also publish module-level data as attributes of the greentype. */ + // XXX: This is weird, and enables a strange pattern of + // confusing the class greenlet with the module greenlet; with + // the exception of (possibly) ``getcurrent()``, this + // shouldn't be encouraged so don't add new items here. + for (const char* const* p = copy_on_greentype; *p; p++) { + OwnedObject o = m.PyRequireAttr(*p); + PyDict_SetItemString(PyGreenlet_Type.tp_dict, *p, o.borrow()); + } + + /* + * Expose C API + */ + + /* types */ + _PyGreenlet_API[PyGreenlet_Type_NUM] = (void*)&PyGreenlet_Type; + + /* exceptions */ + _PyGreenlet_API[PyExc_GreenletError_NUM] = (void*)mod_globs->PyExc_GreenletError; + _PyGreenlet_API[PyExc_GreenletExit_NUM] = (void*)mod_globs->PyExc_GreenletExit; + + /* methods */ + _PyGreenlet_API[PyGreenlet_New_NUM] = (void*)PyGreenlet_New; + _PyGreenlet_API[PyGreenlet_GetCurrent_NUM] = (void*)PyGreenlet_GetCurrent; + _PyGreenlet_API[PyGreenlet_Throw_NUM] = (void*)PyGreenlet_Throw; + _PyGreenlet_API[PyGreenlet_Switch_NUM] = (void*)PyGreenlet_Switch; + _PyGreenlet_API[PyGreenlet_SetParent_NUM] = (void*)PyGreenlet_SetParent; + + /* Previously macros, but now need to be functions externally. */ + _PyGreenlet_API[PyGreenlet_MAIN_NUM] = (void*)Extern_PyGreenlet_MAIN; + _PyGreenlet_API[PyGreenlet_STARTED_NUM] = (void*)Extern_PyGreenlet_STARTED; + _PyGreenlet_API[PyGreenlet_ACTIVE_NUM] = (void*)Extern_PyGreenlet_ACTIVE; + _PyGreenlet_API[PyGreenlet_GET_PARENT_NUM] = (void*)Extern_PyGreenlet_GET_PARENT; + + /* XXX: Note that our module name is ``greenlet._greenlet``, but for + backwards compatibility with existing C code, we need the _C_API to + be directly in greenlet. + */ + const NewReference c_api_object(Require( + PyCapsule_New( + (void*)_PyGreenlet_API, + "greenlet._C_API", + NULL))); + m.PyAddObject("_C_API", c_api_object); + assert(c_api_object.REFCNT() == 2); + + // cerr << "Sizes:" + // << "\n\tGreenlet : " << sizeof(Greenlet) + // << "\n\tUserGreenlet : " << sizeof(UserGreenlet) + // << "\n\tMainGreenlet : " << sizeof(MainGreenlet) + // << "\n\tExceptionState : " << sizeof(greenlet::ExceptionState) + // << "\n\tPythonState : " << sizeof(greenlet::PythonState) + // << "\n\tStackState : " << sizeof(greenlet::StackState) + // << "\n\tSwitchingArgs : " << sizeof(greenlet::SwitchingArgs) + // << "\n\tOwnedObject : " << sizeof(greenlet::refs::OwnedObject) + // << "\n\tBorrowedObject : " << sizeof(greenlet::refs::BorrowedObject) + // << "\n\tPyGreenlet : " << sizeof(PyGreenlet) + // << endl; + + return m.borrow(); // But really it's the main reference. + } + catch (const LockInitError& e) { + PyErr_SetString(PyExc_MemoryError, e.what()); + return NULL; + } + catch (const PyErrOccurred&) { + return NULL; + } + +} + +extern "C" { + +PyMODINIT_FUNC +PyInit__greenlet(void) +{ + return greenlet_internal_mod_init(); +} + +}; // extern C + +#ifdef __clang__ +# pragma clang diagnostic pop +#elif defined(__GNUC__) +# pragma GCC diagnostic pop +#endif diff --git a/psets/9/finance/env/lib/python3.12/site-packages/greenlet/greenlet.h b/psets/9/finance/env/lib/python3.12/site-packages/greenlet/greenlet.h new file mode 100644 index 0000000..d02a16e --- /dev/null +++ b/psets/9/finance/env/lib/python3.12/site-packages/greenlet/greenlet.h @@ -0,0 +1,164 @@ +/* -*- indent-tabs-mode: nil; tab-width: 4; -*- */ + +/* Greenlet object interface */ + +#ifndef Py_GREENLETOBJECT_H +#define Py_GREENLETOBJECT_H + + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/* This is deprecated and undocumented. It does not change. */ +#define GREENLET_VERSION "1.0.0" + +#ifndef GREENLET_MODULE +#define implementation_ptr_t void* +#endif + +typedef struct _greenlet { + PyObject_HEAD + PyObject* weakreflist; + PyObject* dict; + implementation_ptr_t pimpl; +} PyGreenlet; + +#define PyGreenlet_Check(op) (op && PyObject_TypeCheck(op, &PyGreenlet_Type)) + + +/* C API functions */ + +/* Total number of symbols that are exported */ +#define PyGreenlet_API_pointers 12 + +#define PyGreenlet_Type_NUM 0 +#define PyExc_GreenletError_NUM 1 +#define PyExc_GreenletExit_NUM 2 + +#define PyGreenlet_New_NUM 3 +#define PyGreenlet_GetCurrent_NUM 4 +#define PyGreenlet_Throw_NUM 5 +#define PyGreenlet_Switch_NUM 6 +#define PyGreenlet_SetParent_NUM 7 + +#define PyGreenlet_MAIN_NUM 8 +#define PyGreenlet_STARTED_NUM 9 +#define PyGreenlet_ACTIVE_NUM 10 +#define PyGreenlet_GET_PARENT_NUM 11 + +#ifndef GREENLET_MODULE +/* This section is used by modules that uses the greenlet C API */ +static void** _PyGreenlet_API = NULL; + +# define PyGreenlet_Type \ + (*(PyTypeObject*)_PyGreenlet_API[PyGreenlet_Type_NUM]) + +# define PyExc_GreenletError \ + ((PyObject*)_PyGreenlet_API[PyExc_GreenletError_NUM]) + +# define PyExc_GreenletExit \ + ((PyObject*)_PyGreenlet_API[PyExc_GreenletExit_NUM]) + +/* + * PyGreenlet_New(PyObject *args) + * + * greenlet.greenlet(run, parent=None) + */ +# define PyGreenlet_New \ + (*(PyGreenlet * (*)(PyObject * run, PyGreenlet * parent)) \ + _PyGreenlet_API[PyGreenlet_New_NUM]) + +/* + * PyGreenlet_GetCurrent(void) + * + * greenlet.getcurrent() + */ +# define PyGreenlet_GetCurrent \ + (*(PyGreenlet * (*)(void)) _PyGreenlet_API[PyGreenlet_GetCurrent_NUM]) + +/* + * PyGreenlet_Throw( + * PyGreenlet *greenlet, + * PyObject *typ, + * PyObject *val, + * PyObject *tb) + * + * g.throw(...) + */ +# define PyGreenlet_Throw \ + (*(PyObject * (*)(PyGreenlet * self, \ + PyObject * typ, \ + PyObject * val, \ + PyObject * tb)) \ + _PyGreenlet_API[PyGreenlet_Throw_NUM]) + +/* + * PyGreenlet_Switch(PyGreenlet *greenlet, PyObject *args) + * + * g.switch(*args, **kwargs) + */ +# define PyGreenlet_Switch \ + (*(PyObject * \ + (*)(PyGreenlet * greenlet, PyObject * args, PyObject * kwargs)) \ + _PyGreenlet_API[PyGreenlet_Switch_NUM]) + +/* + * PyGreenlet_SetParent(PyObject *greenlet, PyObject *new_parent) + * + * g.parent = new_parent + */ +# define PyGreenlet_SetParent \ + (*(int (*)(PyGreenlet * greenlet, PyGreenlet * nparent)) \ + _PyGreenlet_API[PyGreenlet_SetParent_NUM]) + +/* + * PyGreenlet_GetParent(PyObject* greenlet) + * + * return greenlet.parent; + * + * This could return NULL even if there is no exception active. + * If it does not return NULL, you are responsible for decrementing the + * reference count. + */ +# define PyGreenlet_GetParent \ + (*(PyGreenlet* (*)(PyGreenlet*)) \ + _PyGreenlet_API[PyGreenlet_GET_PARENT_NUM]) + +/* + * deprecated, undocumented alias. + */ +# define PyGreenlet_GET_PARENT PyGreenlet_GetParent + +# define PyGreenlet_MAIN \ + (*(int (*)(PyGreenlet*)) \ + _PyGreenlet_API[PyGreenlet_MAIN_NUM]) + +# define PyGreenlet_STARTED \ + (*(int (*)(PyGreenlet*)) \ + _PyGreenlet_API[PyGreenlet_STARTED_NUM]) + +# define PyGreenlet_ACTIVE \ + (*(int (*)(PyGreenlet*)) \ + _PyGreenlet_API[PyGreenlet_ACTIVE_NUM]) + + + + +/* Macro that imports greenlet and initializes C API */ +/* NOTE: This has actually moved to ``greenlet._greenlet._C_API``, but we + keep the older definition to be sure older code that might have a copy of + the header still works. */ +# define PyGreenlet_Import() \ + { \ + _PyGreenlet_API = (void**)PyCapsule_Import("greenlet._C_API", 0); \ + } + +#endif /* GREENLET_MODULE */ + +#ifdef __cplusplus +} +#endif +#endif /* !Py_GREENLETOBJECT_H */ diff --git a/psets/9/finance/env/lib/python3.12/site-packages/greenlet/greenlet_allocator.hpp b/psets/9/finance/env/lib/python3.12/site-packages/greenlet/greenlet_allocator.hpp new file mode 100644 index 0000000..b452f54 --- /dev/null +++ b/psets/9/finance/env/lib/python3.12/site-packages/greenlet/greenlet_allocator.hpp @@ -0,0 +1,63 @@ +#ifndef GREENLET_ALLOCATOR_HPP +#define GREENLET_ALLOCATOR_HPP + +#define PY_SSIZE_T_CLEAN +#include +#include +#include "greenlet_compiler_compat.hpp" + + +namespace greenlet +{ + // This allocator is stateless; all instances are identical. + // It can *ONLY* be used when we're sure we're holding the GIL + // (Python's allocators require the GIL). + template + struct PythonAllocator : public std::allocator { + + PythonAllocator(const PythonAllocator& UNUSED(other)) + : std::allocator() + { + } + + PythonAllocator(const std::allocator other) + : std::allocator(other) + {} + + template + PythonAllocator(const std::allocator& other) + : std::allocator(other) + { + } + + PythonAllocator() : std::allocator() {} + + T* allocate(size_t number_objects, const void* UNUSED(hint)=0) + { + void* p; + if (number_objects == 1) + p = PyObject_Malloc(sizeof(T)); + else + p = PyMem_Malloc(sizeof(T) * number_objects); + return static_cast(p); + } + + void deallocate(T* t, size_t n) + { + void* p = t; + if (n == 1) { + PyObject_Free(p); + } + else + PyMem_Free(p); + } + // This member is deprecated in C++17 and removed in C++20 + template< class U > + struct rebind { + typedef PythonAllocator other; + }; + + }; +} + +#endif diff --git a/psets/9/finance/env/lib/python3.12/site-packages/greenlet/greenlet_compiler_compat.hpp b/psets/9/finance/env/lib/python3.12/site-packages/greenlet/greenlet_compiler_compat.hpp new file mode 100644 index 0000000..af24bd8 --- /dev/null +++ b/psets/9/finance/env/lib/python3.12/site-packages/greenlet/greenlet_compiler_compat.hpp @@ -0,0 +1,98 @@ +/* -*- indent-tabs-mode: nil; tab-width: 4; -*- */ +#ifndef GREENLET_COMPILER_COMPAT_HPP +#define GREENLET_COMPILER_COMPAT_HPP + +/** + * Definitions to aid with compatibility with different compilers. + * + * .. caution:: Use extreme care with noexcept. + * Some compilers and runtimes, specifically gcc/libgcc/libstdc++ on + * Linux, implement stack unwinding by throwing an uncatchable + * exception, one that specifically does not appear to be an active + * exception to the rest of the runtime. If this happens while we're in a noexcept function, + * we have violated our dynamic exception contract, and so the runtime + * will call std::terminate(), which kills the process with the + * unhelpful message "terminate called without an active exception". + * + * This has happened in this scenario: A background thread is running + * a greenlet that has made a native call and released the GIL. + * Meanwhile, the main thread finishes and starts shutting down the + * interpreter. When the background thread is scheduled again and + * attempts to obtain the GIL, it notices that the interpreter is + * exiting and calls ``pthread_exit()``. This in turn starts to unwind + * the stack by throwing that exception. But we had the ``PyCall`` + * functions annotated as noexcept, so the runtime terminated us. + * + * #2 0x00007fab26fec2b7 in std::terminate() () from /lib/x86_64-linux-gnu/libstdc++.so.6 + * #3 0x00007fab26febb3c in __gxx_personality_v0 () from /lib/x86_64-linux-gnu/libstdc++.so.6 + * #4 0x00007fab26f34de6 in ?? () from /lib/x86_64-linux-gnu/libgcc_s.so.1 + * #6 0x00007fab276a34c6 in __GI___pthread_unwind at ./nptl/unwind.c:130 + * #7 0x00007fab2769bd3a in __do_cancel () at ../sysdeps/nptl/pthreadP.h:280 + * #8 __GI___pthread_exit (value=value@entry=0x0) at ./nptl/pthread_exit.c:36 + * #9 0x000000000052e567 in PyThread_exit_thread () at ../Python/thread_pthread.h:370 + * #10 0x00000000004d60b5 in take_gil at ../Python/ceval_gil.h:224 + * #11 0x00000000004d65f9 in PyEval_RestoreThread at ../Python/ceval.c:467 + * #12 0x000000000060cce3 in setipaddr at ../Modules/socketmodule.c:1203 + * #13 0x00000000006101cd in socket_gethostbyname + */ + +#include + +# define G_NO_COPIES_OF_CLS(Cls) private: \ + Cls(const Cls& other) = delete; \ + Cls& operator=(const Cls& other) = delete + +# define G_NO_ASSIGNMENT_OF_CLS(Cls) private: \ + Cls& operator=(const Cls& other) = delete + +# define G_NO_COPY_CONSTRUCTOR_OF_CLS(Cls) private: \ + Cls(const Cls& other) = delete; + + +// CAUTION: MSVC is stupidly picky: +// +// "The compiler ignores, without warning, any __declspec keywords +// placed after * or & and in front of the variable identifier in a +// declaration." +// (https://docs.microsoft.com/en-us/cpp/cpp/declspec?view=msvc-160) +// +// So pointer return types must be handled differently (because of the +// trailing *), or you get inscrutable compiler warnings like "error +// C2059: syntax error: ''" +// +// In C++ 11, there is a standard syntax for attributes, and +// GCC defines an attribute to use with this: [[gnu:noinline]]. +// In the future, this is expected to become standard. + +#if defined(__GNUC__) || defined(__clang__) +/* We used to check for GCC 4+ or 3.4+, but those compilers are + laughably out of date. Just assume they support it. */ +# define GREENLET_NOINLINE(name) __attribute__((noinline)) name +# define GREENLET_NOINLINE_P(rtype, name) rtype __attribute__((noinline)) name +# define UNUSED(x) UNUSED_ ## x __attribute__((__unused__)) +#elif defined(_MSC_VER) +/* We used to check for && (_MSC_VER >= 1300) but that's also out of date. */ +# define GREENLET_NOINLINE(name) __declspec(noinline) name +# define GREENLET_NOINLINE_P(rtype, name) __declspec(noinline) rtype name +# define UNUSED(x) UNUSED_ ## x +#endif + +#if defined(_MSC_VER) +# define G_NOEXCEPT_WIN32 noexcept +#else +# define G_NOEXCEPT_WIN32 +#endif + +#if defined(__GNUC__) && defined(__POWERPC__) && defined(__APPLE__) +// 32-bit PPC/MacOSX. Only known to be tested on unreleased versions +// of macOS 10.6 using a macports build gcc 14. It appears that +// running C++ destructors of thread-local variables is broken. + +// See https://github.com/python-greenlet/greenlet/pull/419 +# define GREENLET_BROKEN_THREAD_LOCAL_CLEANUP_JUST_LEAK 1 +#else +# define GREENLET_BROKEN_THREAD_LOCAL_CLEANUP_JUST_LEAK 0 +#endif + + +#endif diff --git a/psets/9/finance/env/lib/python3.12/site-packages/greenlet/greenlet_cpython_add_pending.hpp b/psets/9/finance/env/lib/python3.12/site-packages/greenlet/greenlet_cpython_add_pending.hpp new file mode 100644 index 0000000..0d28efd --- /dev/null +++ b/psets/9/finance/env/lib/python3.12/site-packages/greenlet/greenlet_cpython_add_pending.hpp @@ -0,0 +1,172 @@ +#ifndef GREENLET_CPYTHON_ADD_PENDING_HPP +#define GREENLET_CPYTHON_ADD_PENDING_HPP + +#if (PY_VERSION_HEX >= 0x30800A0 && PY_VERSION_HEX < 0x3090000) && !(defined(_WIN32) || defined(WIN32)) +// XXX: From Python 3.8a3 [1] up until Python 3.9a6 [2][3], +// ``Py_AddPendingCall`` would try to produce a Python exception if +// the interpreter was in the beginning of shutting down when this +// function is called. However, ``Py_AddPendingCall`` doesn't require +// the GIL, and we are absolutely not holding it when we make that +// call. That means that trying to create the Python exception is +// using the C API in an undefined state; here the C API detects this +// and aborts the process with an error ("Fatal Python error: Python +// memory allocator called without holding the GIL": Add -> +// PyErr_SetString -> PyUnicode_New -> PyObject_Malloc). This arises +// (obviously) in multi-threaded programs and happens if one thread is +// exiting and cleaning up its thread-local data while the other +// thread is trying to shut down the interpreter. A crash on shutdown +// is still a crash and could result in data loss (e.g., daemon +// threads are still running, pending signal handlers may be present, +// buffers may not be flushed, there may be __del__ that need run, +// etc), so we have to work around it. +// +// Of course, we can (and do) check for whether the interpreter is +// shutting down before calling ``Py_AddPendingCall``, but that's a +// race condition since we don't hold the GIL, and so we may not +// actually get the right answer. Plus, ``Py_FinalizeEx`` actually +// calls ``_Py_FinishPendingCalls`` (which sets the pending->finishing +// flag, which is used to gate creating the exceptioen) *before* +// publishing any other data that would let us detect the shutdown +// (such as runtime->finalizing). So that point is moot. +// +// Our solution for those versions is to inline the same code, without +// the problematic bit that sets the exception. Unfortunately, all of +// the structure definitions are private/opaque, *and* we can't +// actually count on being able to include their definitions from +// ``internal/pycore_*``, because on some platforms those header files +// are incomplete (i.e., on macOS with macports 3.8, the includes are +// fine, but on Ubuntu jammy with 3.8 from ppa:deadsnakes or GitHub +// Actions 3.8 (I think it's Ubuntu 18.04), they con't be used; at +// least, I couldn't get them to work). So we need to define the +// structures and _PyRuntime data member ourself. Yet more +// unfortunately, _PyRuntime won't link on Windows, so we can only do +// this on other platforms. +// +// [1] https://github.com/python/cpython/commit/842a2f07f2f08a935ef470bfdaeef40f87490cfc +// [2] https://github.com/python/cpython/commit/cfc3c2f8b34d3864717ab584c5b6c260014ba55a +// [3] https://github.com/python/cpython/issues/81308 +# define GREENLET_BROKEN_PY_ADD_PENDING 1 + +// When defining these structures, the important thing is to get +// binary compatibility, i.e., structure layout. For that, we only +// need to define fields up to the ones we use; after that they're +// irrelevant UNLESS the structure is included in another structure +// *before* the structure we're interested in --- in that case, it +// must be complete. Ellipsis indicate elided trailing members. +// Pointer types are changed to void* to keep from having to define +// more structures. + +// From "internal/pycore_atomic.h" + +// There are several different definitions of this, including the +// plain ``int`` version, a ``volatile int`` and an ``_Atomic int`` +// I don't think any of those change the size/layout. +typedef struct _Py_atomic_int { + volatile int _value; +} _Py_atomic_int; + +// This needs too much infrastructure, so we just do a regular store. +#define _Py_atomic_store_relaxed(ATOMIC_VAL, NEW_VAL) \ + (ATOMIC_VAL)->_value = NEW_VAL + + + +// From "internal/pycore_pymem.h" +#define NUM_GENERATIONS 3 + + +struct gc_generation { + PyGC_Head head; // We already have this defined. + int threshold; + int count; +}; +struct gc_generation_stats { + Py_ssize_t collections; + Py_ssize_t collected; + Py_ssize_t uncollectable; +}; + +struct _gc_runtime_state { + void *trash_delete_later; + int trash_delete_nesting; + int enabled; + int debug; + struct gc_generation generations[NUM_GENERATIONS]; + void *generation0; + struct gc_generation permanent_generation; + struct gc_generation_stats generation_stats[NUM_GENERATIONS]; + int collecting; + void *garbage; + void *callbacks; + Py_ssize_t long_lived_total; + Py_ssize_t long_lived_pending; +}; + +// From "internal/pycore_pystate.h" +struct _pending_calls { + int finishing; + PyThread_type_lock lock; + _Py_atomic_int calls_to_do; + int async_exc; +#define NPENDINGCALLS 32 + struct { + int (*func)(void *); + void *arg; + } calls[NPENDINGCALLS]; + int first; + int last; +}; + +struct _ceval_runtime_state { + int recursion_limit; + int tracing_possible; + _Py_atomic_int eval_breaker; + _Py_atomic_int gil_drop_request; + struct _pending_calls pending; + // ... +}; + +typedef struct pyruntimestate { + int preinitializing; + int preinitialized; + int core_initialized; + int initialized; + void *finalizing; + + struct pyinterpreters { + PyThread_type_lock mutex; + void *head; + void *main; + int64_t next_id; + } interpreters; + // XXX Remove this field once we have a tp_* slot. + struct _xidregistry { + PyThread_type_lock mutex; + void *head; + } xidregistry; + + unsigned long main_thread; + +#define NEXITFUNCS 32 + void (*exitfuncs[NEXITFUNCS])(void); + int nexitfuncs; + + struct _gc_runtime_state gc; + struct _ceval_runtime_state ceval; + // ... +} _PyRuntimeState; + +#define SIGNAL_PENDING_CALLS(ceval) \ + do { \ + _Py_atomic_store_relaxed(&(ceval)->pending.calls_to_do, 1); \ + _Py_atomic_store_relaxed(&(ceval)->eval_breaker, 1); \ + } while (0) + +extern _PyRuntimeState _PyRuntime; + +#else +# define GREENLET_BROKEN_PY_ADD_PENDING 0 +#endif + + +#endif diff --git a/psets/9/finance/env/lib/python3.12/site-packages/greenlet/greenlet_cpython_compat.hpp b/psets/9/finance/env/lib/python3.12/site-packages/greenlet/greenlet_cpython_compat.hpp new file mode 100644 index 0000000..ce5fd88 --- /dev/null +++ b/psets/9/finance/env/lib/python3.12/site-packages/greenlet/greenlet_cpython_compat.hpp @@ -0,0 +1,142 @@ +/* -*- indent-tabs-mode: nil; tab-width: 4; -*- */ +#ifndef GREENLET_CPYTHON_COMPAT_H +#define GREENLET_CPYTHON_COMPAT_H + +/** + * Helpers for compatibility with multiple versions of CPython. + */ + +#define PY_SSIZE_T_CLEAN +#include "Python.h" + + +#if PY_VERSION_HEX >= 0x30A00B1 +# define GREENLET_PY310 1 +#else +# define GREENLET_PY310 0 +#endif + +/* +Python 3.10 beta 1 changed tstate->use_tracing to a nested cframe member. +See https://github.com/python/cpython/pull/25276 +We have to save and restore this as well. + +Python 3.13 removed PyThreadState.cframe (GH-108035). +*/ +#if GREENLET_PY310 && PY_VERSION_HEX < 0x30D0000 +# define GREENLET_USE_CFRAME 1 +#else +# define GREENLET_USE_CFRAME 0 +#endif + + +#if PY_VERSION_HEX >= 0x30B00A4 +/* +Greenlet won't compile on anything older than Python 3.11 alpha 4 (see +https://bugs.python.org/issue46090). Summary of breaking internal changes: +- Python 3.11 alpha 1 changed how frame objects are represented internally. + - https://github.com/python/cpython/pull/30122 +- Python 3.11 alpha 3 changed how recursion limits are stored. + - https://github.com/python/cpython/pull/29524 +- Python 3.11 alpha 4 changed how exception state is stored. It also includes a + change to help greenlet save and restore the interpreter frame "data stack". + - https://github.com/python/cpython/pull/30122 + - https://github.com/python/cpython/pull/30234 +*/ +# define GREENLET_PY311 1 +#else +# define GREENLET_PY311 0 +#endif + + +#if PY_VERSION_HEX >= 0x30C0000 +# define GREENLET_PY312 1 +#else +# define GREENLET_PY312 0 +#endif + +#if PY_VERSION_HEX >= 0x30D0000 +# define GREENLET_PY313 1 +#else +# define GREENLET_PY313 0 +#endif + +#ifndef Py_SET_REFCNT +/* Py_REFCNT and Py_SIZE macros are converted to functions +https://bugs.python.org/issue39573 */ +# define Py_SET_REFCNT(obj, refcnt) Py_REFCNT(obj) = (refcnt) +#endif + +#ifndef _Py_DEC_REFTOTAL +/* _Py_DEC_REFTOTAL macro has been removed from Python 3.9 by: + https://github.com/python/cpython/commit/49932fec62c616ec88da52642339d83ae719e924 + + The symbol we use to replace it was removed by at least 3.12. +*/ +# ifdef Py_REF_DEBUG +# if GREENLET_PY312 +# define _Py_DEC_REFTOTAL +# else +# define _Py_DEC_REFTOTAL _Py_RefTotal-- +# endif +# else +# define _Py_DEC_REFTOTAL +# endif +#endif +// Define these flags like Cython does if we're on an old version. +#ifndef Py_TPFLAGS_CHECKTYPES + #define Py_TPFLAGS_CHECKTYPES 0 +#endif +#ifndef Py_TPFLAGS_HAVE_INDEX + #define Py_TPFLAGS_HAVE_INDEX 0 +#endif +#ifndef Py_TPFLAGS_HAVE_NEWBUFFER + #define Py_TPFLAGS_HAVE_NEWBUFFER 0 +#endif + +#ifndef Py_TPFLAGS_HAVE_VERSION_TAG + #define Py_TPFLAGS_HAVE_VERSION_TAG 0 +#endif + +#define G_TPFLAGS_DEFAULT Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_VERSION_TAG | Py_TPFLAGS_CHECKTYPES | Py_TPFLAGS_HAVE_NEWBUFFER | Py_TPFLAGS_HAVE_GC + + +#if PY_VERSION_HEX < 0x03090000 +// The official version only became available in 3.9 +# define PyObject_GC_IsTracked(o) _PyObject_GC_IS_TRACKED(o) +#endif + + +// bpo-43760 added PyThreadState_EnterTracing() to Python 3.11.0a2 +#if PY_VERSION_HEX < 0x030B00A2 && !defined(PYPY_VERSION) +static inline void PyThreadState_EnterTracing(PyThreadState *tstate) +{ + tstate->tracing++; +#if PY_VERSION_HEX >= 0x030A00A1 + tstate->cframe->use_tracing = 0; +#else + tstate->use_tracing = 0; +#endif +} +#endif + +// bpo-43760 added PyThreadState_LeaveTracing() to Python 3.11.0a2 +#if PY_VERSION_HEX < 0x030B00A2 && !defined(PYPY_VERSION) +static inline void PyThreadState_LeaveTracing(PyThreadState *tstate) +{ + tstate->tracing--; + int use_tracing = (tstate->c_tracefunc != NULL + || tstate->c_profilefunc != NULL); +#if PY_VERSION_HEX >= 0x030A00A1 + tstate->cframe->use_tracing = use_tracing; +#else + tstate->use_tracing = use_tracing; +#endif +} +#endif + +#if !defined(Py_C_RECURSION_LIMIT) && defined(C_RECURSION_LIMIT) +# define Py_C_RECURSION_LIMIT C_RECURSION_LIMIT +#endif + +#endif /* GREENLET_CPYTHON_COMPAT_H */ diff --git a/psets/9/finance/env/lib/python3.12/site-packages/greenlet/greenlet_exceptions.hpp b/psets/9/finance/env/lib/python3.12/site-packages/greenlet/greenlet_exceptions.hpp new file mode 100644 index 0000000..617f07c --- /dev/null +++ b/psets/9/finance/env/lib/python3.12/site-packages/greenlet/greenlet_exceptions.hpp @@ -0,0 +1,171 @@ +#ifndef GREENLET_EXCEPTIONS_HPP +#define GREENLET_EXCEPTIONS_HPP + +#define PY_SSIZE_T_CLEAN +#include +#include +#include + +#ifdef __clang__ +# pragma clang diagnostic push +# pragma clang diagnostic ignored "-Wunused-function" +#endif + +namespace greenlet { + + class PyErrOccurred : public std::runtime_error + { + public: + + // CAUTION: In debug builds, may run arbitrary Python code. + static const PyErrOccurred + from_current() + { + assert(PyErr_Occurred()); +#ifndef NDEBUG + // This is not exception safe, and + // not necessarily safe in general (what if it switches?) + // But we only do this in debug mode, where we are in + // tight control of what exceptions are getting raised and + // can prevent those issues. + + // You can't call PyObject_Str with a pending exception. + PyObject* typ; + PyObject* val; + PyObject* tb; + + PyErr_Fetch(&typ, &val, &tb); + PyObject* typs = PyObject_Str(typ); + PyObject* vals = PyObject_Str(val ? val : typ); + const char* typ_msg = PyUnicode_AsUTF8(typs); + const char* val_msg = PyUnicode_AsUTF8(vals); + PyErr_Restore(typ, val, tb); + + std::string msg(typ_msg); + msg += ": "; + msg += val_msg; + PyErrOccurred ex(msg); + Py_XDECREF(typs); + Py_XDECREF(vals); + + return ex; +#else + return PyErrOccurred(); +#endif + } + + PyErrOccurred() : std::runtime_error("") + { + assert(PyErr_Occurred()); + } + + PyErrOccurred(const std::string& msg) : std::runtime_error(msg) + { + assert(PyErr_Occurred()); + } + + PyErrOccurred(PyObject* exc_kind, const char* const msg) + : std::runtime_error(msg) + { + PyErr_SetString(exc_kind, msg); + } + + PyErrOccurred(PyObject* exc_kind, const std::string msg) + : std::runtime_error(msg) + { + // This copies the c_str, so we don't have any lifetime + // issues to worry about. + PyErr_SetString(exc_kind, msg.c_str()); + } + + PyErrOccurred(PyObject* exc_kind, + const std::string msg, //This is the format + //string; that's not + //usually safe! + + PyObject* borrowed_obj_one, PyObject* borrowed_obj_two) + : std::runtime_error(msg) + { + + //This is designed specifically for the + //``check_switch_allowed`` function. + + // PyObject_Str and PyObject_Repr are safe to call with + // NULL pointers; they return the string "" in that + // case. + // This function always returns null. + PyErr_Format(exc_kind, + msg.c_str(), + borrowed_obj_one, borrowed_obj_two); + } + }; + + class TypeError : public PyErrOccurred + { + public: + TypeError(const char* const what) + : PyErrOccurred(PyExc_TypeError, what) + { + } + TypeError(const std::string what) + : PyErrOccurred(PyExc_TypeError, what) + { + } + }; + + class ValueError : public PyErrOccurred + { + public: + ValueError(const char* const what) + : PyErrOccurred(PyExc_ValueError, what) + { + } + }; + + class AttributeError : public PyErrOccurred + { + public: + AttributeError(const char* const what) + : PyErrOccurred(PyExc_AttributeError, what) + { + } + }; + + /** + * Calls `Py_FatalError` when constructed, so you can't actually + * throw this. It just makes static analysis easier. + */ + class PyFatalError : public std::runtime_error + { + public: + PyFatalError(const char* const msg) + : std::runtime_error(msg) + { + Py_FatalError(msg); + } + }; + + static inline PyObject* + Require(PyObject* p, const std::string& msg="") + { + if (!p) { + throw PyErrOccurred(msg); + } + return p; + }; + + static inline void + Require(const int retval) + { + if (retval < 0) { + throw PyErrOccurred(); + } + }; + + +}; +#ifdef __clang__ +# pragma clang diagnostic pop +#endif + +#endif diff --git a/psets/9/finance/env/lib/python3.12/site-packages/greenlet/greenlet_internal.hpp b/psets/9/finance/env/lib/python3.12/site-packages/greenlet/greenlet_internal.hpp new file mode 100644 index 0000000..f2b15d5 --- /dev/null +++ b/psets/9/finance/env/lib/python3.12/site-packages/greenlet/greenlet_internal.hpp @@ -0,0 +1,107 @@ +/* -*- indent-tabs-mode: nil; tab-width: 4; -*- */ +#ifndef GREENLET_INTERNAL_H +#define GREENLET_INTERNAL_H +#ifdef __clang__ +# pragma clang diagnostic push +# pragma clang diagnostic ignored "-Wunused-function" +#endif + +/** + * Implementation helpers. + * + * C++ templates and inline functions should go here. + */ +#define PY_SSIZE_T_CLEAN +#include "greenlet_compiler_compat.hpp" +#include "greenlet_cpython_compat.hpp" +#include "greenlet_exceptions.hpp" +#include "TGreenlet.hpp" +#include "greenlet_allocator.hpp" + +#include +#include + +#define GREENLET_MODULE +struct _greenlet; +typedef struct _greenlet PyGreenlet; +namespace greenlet { + + class ThreadState; + // We can't use the PythonAllocator for this, because we push to it + // from the thread state destructor, which doesn't have the GIL, + // and Python's allocators can only be called with the GIL. + typedef std::vector cleanup_queue_t; + +}; + + +#define implementation_ptr_t greenlet::Greenlet* + + +#include "greenlet.h" + +void +greenlet::refs::MainGreenletExactChecker(void *p) +{ + if (!p) { + return; + } + // We control the class of the main greenlet exactly. + if (Py_TYPE(p) != &PyGreenlet_Type) { + std::string err("MainGreenlet: Expected exactly a greenlet, not a "); + err += Py_TYPE(p)->tp_name; + throw greenlet::TypeError(err); + } + + // Greenlets from dead threads no longer respond to main() with a + // true value; so in that case we need to perform an additional + // check. + Greenlet* g = static_cast(p)->pimpl; + if (g->main()) { + return; + } + if (!dynamic_cast(g)) { + std::string err("MainGreenlet: Expected exactly a main greenlet, not a "); + err += Py_TYPE(p)->tp_name; + throw greenlet::TypeError(err); + } +} + + + +template +inline greenlet::Greenlet* greenlet::refs::_OwnedGreenlet::operator->() const noexcept +{ + return reinterpret_cast(this->p)->pimpl; +} + +template +inline greenlet::Greenlet* greenlet::refs::_BorrowedGreenlet::operator->() const noexcept +{ + return reinterpret_cast(this->p)->pimpl; +} + +#include +#include + + +extern PyTypeObject PyGreenlet_Type; + + + +/** + * Forward declarations needed in multiple files. + */ +static PyObject* green_switch(PyGreenlet* self, PyObject* args, PyObject* kwargs); + + +#ifdef __clang__ +# pragma clang diagnostic pop +#endif + + +#endif + +// Local Variables: +// flycheck-clang-include-path: ("../../include" "/opt/local/Library/Frameworks/Python.framework/Versions/3.10/include/python3.10") +// End: diff --git a/psets/9/finance/env/lib/python3.12/site-packages/greenlet/greenlet_refs.hpp b/psets/9/finance/env/lib/python3.12/site-packages/greenlet/greenlet_refs.hpp new file mode 100644 index 0000000..b7e5e3f --- /dev/null +++ b/psets/9/finance/env/lib/python3.12/site-packages/greenlet/greenlet_refs.hpp @@ -0,0 +1,1118 @@ +#ifndef GREENLET_REFS_HPP +#define GREENLET_REFS_HPP + +#define PY_SSIZE_T_CLEAN +#include + +#include + +//#include "greenlet_internal.hpp" +#include "greenlet_compiler_compat.hpp" +#include "greenlet_cpython_compat.hpp" +#include "greenlet_exceptions.hpp" + +struct _greenlet; +struct _PyMainGreenlet; + +typedef struct _greenlet PyGreenlet; +extern PyTypeObject PyGreenlet_Type; + + +#ifdef GREENLET_USE_STDIO +#include +using std::cerr; +using std::endl; +#endif + +namespace greenlet +{ + class Greenlet; + + namespace refs + { + // Type checkers throw a TypeError if the argument is not + // null, and isn't of the required Python type. + // (We can't use most of the defined type checkers + // like PyList_Check, etc, directly, because they are + // implemented as macros.) + typedef void (*TypeChecker)(void*); + + void + NoOpChecker(void*) + { + return; + } + + void + GreenletChecker(void *p) + { + if (!p) { + return; + } + + PyTypeObject* typ = Py_TYPE(p); + // fast, common path. (PyObject_TypeCheck is a macro or + // static inline function, and it also does a + // direct comparison of the type pointers, but its fast + // path only handles one type) + if (typ == &PyGreenlet_Type) { + return; + } + + if (!PyObject_TypeCheck(p, &PyGreenlet_Type)) { + std::string err("GreenletChecker: Expected any type of greenlet, not "); + err += Py_TYPE(p)->tp_name; + throw TypeError(err); + } + } + + void + MainGreenletExactChecker(void *p); + + template + class PyObjectPointer; + + template + class OwnedReference; + + + template + class BorrowedReference; + + typedef BorrowedReference BorrowedObject; + typedef OwnedReference OwnedObject; + + class ImmortalObject; + class ImmortalString; + + template + class _OwnedGreenlet; + + typedef _OwnedGreenlet OwnedGreenlet; + typedef _OwnedGreenlet OwnedMainGreenlet; + + template + class _BorrowedGreenlet; + + typedef _BorrowedGreenlet BorrowedGreenlet; + + void + ContextExactChecker(void *p) + { + if (!p) { + return; + } + if (!PyContext_CheckExact(p)) { + throw TypeError( + "greenlet context must be a contextvars.Context or None" + ); + } + } + + typedef OwnedReference OwnedContext; + } +} + +namespace greenlet { + + + namespace refs { + // A set of classes to make reference counting rules in python + // code explicit. + // + // Rules of use: + // (1) Functions returning a new reference that the caller of the + // function is expected to dispose of should return a + // ``OwnedObject`` object. This object automatically releases its + // reference when it goes out of scope. It works like a ``std::shared_ptr`` + // and can be copied or used as a function parameter (but don't do + // that). Note that constructing a ``OwnedObject`` from a + // PyObject* steals the reference. + // (2) Parameters to functions should be either a + // ``OwnedObject&``, or, more generally, a ``PyObjectPointer&``. + // If the function needs to create its own new reference, it can + // do so by copying to a local ``OwnedObject``. + // (3) Functions returning an existing pointer that is NOT + // incref'd, and which the caller MUST NOT decref, + // should return a ``BorrowedObject``. + + // XXX: The following two paragraphs do not hold for all platforms. + // Notably, 32-bit PPC Linux passes structs by reference, not by + // value, so this actually doesn't work. (Although that's the only + // platform that doesn't work on.) DO NOT ATTEMPT IT. The + // unfortunate consequence of that is that the slots which we + // *know* are already type safe will wind up calling the type + // checker function (when we had the slots accepting + // BorrowedGreenlet, this was bypassed), so this slows us down. + // TODO: Optimize this again. + + // For a class with a single pointer member, whose constructor + // does nothing but copy a pointer parameter into the member, and + // which can then be converted back to the pointer type, compilers + // generate code that's the same as just passing the pointer. + // That is, func(BorrowedObject x) called like ``PyObject* p = + // ...; f(p)`` has 0 overhead. Similarly, they "unpack" to the + // pointer type with 0 overhead. + // + // If there are no virtual functions, no complex inheritance (maybe?) and + // no destructor, these can be directly used as parameters in + // Python callbacks like tp_init: the layout is the same as a + // single pointer. Only subclasses with trivial constructors that + // do nothing but set the single pointer member are safe to use + // that way. + + + // This is the base class for things that can be done with a + // PyObject pointer. It assumes nothing about memory management. + // NOTE: Nothing is virtual, so subclasses shouldn't add new + // storage fields or try to override these methods. + template + class PyObjectPointer + { + public: + typedef T PyType; + protected: + T* p; + public: + PyObjectPointer(T* it=nullptr) : p(it) + { + TC(p); + } + + // We don't allow automatic casting to PyObject* at this + // level, because then we could be passed to Py_DECREF/INCREF, + // but we want nothing to do with memory management. If you + // know better, then you can use the get() method, like on a + // std::shared_ptr. Except we name it borrow() to clarify that + // if this is a reference-tracked object, the pointer you get + // back will go away when the object does. + // TODO: This should probably not exist here, but be moved + // down to relevant sub-types. + + T* borrow() const noexcept + { + return this->p; + } + + PyObject* borrow_o() const noexcept + { + return reinterpret_cast(this->p); + } + + T* operator->() const noexcept + { + return this->p; + } + + bool is_None() const noexcept + { + return this->p == Py_None; + } + + PyObject* acquire_or_None() const noexcept + { + PyObject* result = this->p ? reinterpret_cast(this->p) : Py_None; + Py_INCREF(result); + return result; + } + + explicit operator bool() const noexcept + { + return this->p != nullptr; + } + + bool operator!() const noexcept + { + return this->p == nullptr; + } + + Py_ssize_t REFCNT() const noexcept + { + return p ? Py_REFCNT(p) : -42; + } + + PyTypeObject* TYPE() const noexcept + { + return p ? Py_TYPE(p) : nullptr; + } + + inline OwnedObject PyStr() const noexcept; + inline const std::string as_str() const noexcept; + inline OwnedObject PyGetAttr(const ImmortalObject& name) const noexcept; + inline OwnedObject PyRequireAttr(const char* const name) const; + inline OwnedObject PyRequireAttr(const ImmortalString& name) const; + inline OwnedObject PyCall(const BorrowedObject& arg) const; + inline OwnedObject PyCall(PyGreenlet* arg) const ; + inline OwnedObject PyCall(PyObject* arg) const ; + // PyObject_Call(this, args, kwargs); + inline OwnedObject PyCall(const BorrowedObject args, + const BorrowedObject kwargs) const; + inline OwnedObject PyCall(const OwnedObject& args, + const OwnedObject& kwargs) const; + + protected: + void _set_raw_pointer(void* t) + { + TC(t); + p = reinterpret_cast(t); + } + void* _get_raw_pointer() const + { + return p; + } + }; + +#ifdef GREENLET_USE_STDIO + template + std::ostream& operator<<(std::ostream& os, const PyObjectPointer& s) + { + const std::type_info& t = typeid(s); + os << t.name() + << "(addr=" << s.borrow() + << ", refcnt=" << s.REFCNT() + << ", value=" << s.as_str() + << ")"; + + return os; + } +#endif + + template + inline bool operator==(const PyObjectPointer& lhs, const PyObject* const rhs) noexcept + { + return static_cast(lhs.borrow_o()) == static_cast(rhs); + } + + template + inline bool operator==(const PyObjectPointer& lhs, const PyObjectPointer& rhs) noexcept + { + return lhs.borrow_o() == rhs.borrow_o(); + } + + template + inline bool operator!=(const PyObjectPointer& lhs, + const PyObjectPointer& rhs) noexcept + { + return lhs.borrow_o() != rhs.borrow_o(); + } + + template + class OwnedReference : public PyObjectPointer + { + private: + friend class OwnedList; + + protected: + explicit OwnedReference(T* it) : PyObjectPointer(it) + { + } + + public: + + // Constructors + + static OwnedReference consuming(PyObject* p) + { + return OwnedReference(reinterpret_cast(p)); + } + + static OwnedReference owning(T* p) + { + OwnedReference result(p); + Py_XINCREF(result.p); + return result; + } + + OwnedReference() : PyObjectPointer(nullptr) + {} + + explicit OwnedReference(const PyObjectPointer<>& other) + : PyObjectPointer(nullptr) + { + T* op = other.borrow(); + TC(op); + this->p = other.borrow(); + Py_XINCREF(this->p); + } + + // It would be good to make use of the C++11 distinction + // between move and copy operations, e.g., constructing from a + // pointer should be a move operation. + // In the common case of ``OwnedObject x = Py_SomeFunction()``, + // the call to the copy constructor will be elided completely. + OwnedReference(const OwnedReference& other) + : PyObjectPointer(other.p) + { + Py_XINCREF(this->p); + } + + static OwnedReference None() + { + Py_INCREF(Py_None); + return OwnedReference(Py_None); + } + + // We can assign from exactly our type without any extra checking + OwnedReference& operator=(const OwnedReference& other) + { + Py_XINCREF(other.p); + const T* tmp = this->p; + this->p = other.p; + Py_XDECREF(tmp); + return *this; + } + + OwnedReference& operator=(const BorrowedReference other) + { + return this->operator=(other.borrow()); + } + + OwnedReference& operator=(T* const other) + { + TC(other); + Py_XINCREF(other); + T* tmp = this->p; + this->p = other; + Py_XDECREF(tmp); + return *this; + } + + // We can assign from an arbitrary reference type + // if it passes our check. + template + OwnedReference& operator=(const OwnedReference& other) + { + X* op = other.borrow(); + TC(op); + return this->operator=(reinterpret_cast(op)); + } + + inline void steal(T* other) + { + assert(this->p == nullptr); + TC(other); + this->p = other; + } + + T* relinquish_ownership() + { + T* result = this->p; + this->p = nullptr; + return result; + } + + T* acquire() const + { + // Return a new reference. + // TODO: This may go away when we have reference objects + // throughout the code. + Py_XINCREF(this->p); + return this->p; + } + + // Nothing else declares a destructor, we're the leaf, so we + // should be able to get away without virtual. + ~OwnedReference() + { + Py_CLEAR(this->p); + } + + void CLEAR() + { + Py_CLEAR(this->p); + assert(this->p == nullptr); + } + }; + + static inline + void operator<<=(PyObject*& target, OwnedObject& o) + { + target = o.relinquish_ownership(); + } + + + class NewReference : public OwnedObject + { + private: + G_NO_COPIES_OF_CLS(NewReference); + public: + // Consumes the reference. Only use this + // for API return values. + NewReference(PyObject* it) : OwnedObject(it) + { + } + }; + + class NewDictReference : public NewReference + { + private: + G_NO_COPIES_OF_CLS(NewDictReference); + public: + NewDictReference() : NewReference(PyDict_New()) + { + if (!this->p) { + throw PyErrOccurred(); + } + } + + void SetItem(const char* const key, PyObject* value) + { + Require(PyDict_SetItemString(this->p, key, value)); + } + + void SetItem(const PyObjectPointer<>& key, PyObject* value) + { + Require(PyDict_SetItem(this->p, key.borrow_o(), value)); + } + }; + + template + class _OwnedGreenlet: public OwnedReference + { + private: + protected: + _OwnedGreenlet(T* it) : OwnedReference(it) + {} + + public: + _OwnedGreenlet() : OwnedReference() + {} + + _OwnedGreenlet(const _OwnedGreenlet& other) : OwnedReference(other) + { + } + _OwnedGreenlet(OwnedMainGreenlet& other) : + OwnedReference(reinterpret_cast(other.acquire())) + { + } + _OwnedGreenlet(const BorrowedGreenlet& other); + // Steals a reference. + static _OwnedGreenlet consuming(PyGreenlet* it) + { + return _OwnedGreenlet(reinterpret_cast(it)); + } + + inline _OwnedGreenlet& operator=(const OwnedGreenlet& other) + { + return this->operator=(other.borrow()); + } + + inline _OwnedGreenlet& operator=(const BorrowedGreenlet& other); + + _OwnedGreenlet& operator=(const OwnedMainGreenlet& other) + { + PyGreenlet* owned = other.acquire(); + Py_XDECREF(this->p); + this->p = reinterpret_cast(owned); + return *this; + } + + _OwnedGreenlet& operator=(T* const other) + { + OwnedReference::operator=(other); + return *this; + } + + T* relinquish_ownership() + { + T* result = this->p; + this->p = nullptr; + return result; + } + + PyObject* relinquish_ownership_o() + { + return reinterpret_cast(relinquish_ownership()); + } + + inline Greenlet* operator->() const noexcept; + inline operator Greenlet*() const noexcept; + }; + + template + class BorrowedReference : public PyObjectPointer + { + public: + // Allow implicit creation from PyObject* pointers as we + // transition to using these classes. Also allow automatic + // conversion to PyObject* for passing to C API calls and even + // for Py_INCREF/DECREF, because we ourselves do no memory management. + BorrowedReference(T* it) : PyObjectPointer(it) + {} + + BorrowedReference(const PyObjectPointer& ref) : PyObjectPointer(ref.borrow()) + {} + + BorrowedReference() : PyObjectPointer(nullptr) + {} + + operator T*() const + { + return this->p; + } + }; + + typedef BorrowedReference BorrowedObject; + //typedef BorrowedReference BorrowedGreenlet; + + template + class _BorrowedGreenlet : public BorrowedReference + { + public: + _BorrowedGreenlet() : + BorrowedReference(nullptr) + {} + + _BorrowedGreenlet(T* it) : + BorrowedReference(it) + {} + + _BorrowedGreenlet(const BorrowedObject& it); + + _BorrowedGreenlet(const OwnedGreenlet& it) : + BorrowedReference(it.borrow()) + {} + + _BorrowedGreenlet& operator=(const BorrowedObject& other); + + // We get one of these for PyGreenlet, but one for PyObject + // is handy as well + operator PyObject*() const + { + return reinterpret_cast(this->p); + } + Greenlet* operator->() const noexcept; + operator Greenlet*() const noexcept; + }; + + typedef _BorrowedGreenlet BorrowedGreenlet; + + template + _OwnedGreenlet::_OwnedGreenlet(const BorrowedGreenlet& other) + : OwnedReference(reinterpret_cast(other.borrow())) + { + Py_XINCREF(this->p); + } + + + class BorrowedMainGreenlet + : public _BorrowedGreenlet + { + public: + BorrowedMainGreenlet(const OwnedMainGreenlet& it) : + _BorrowedGreenlet(it.borrow()) + {} + BorrowedMainGreenlet(PyGreenlet* it=nullptr) + : _BorrowedGreenlet(it) + {} + }; + + template + _OwnedGreenlet& _OwnedGreenlet::operator=(const BorrowedGreenlet& other) + { + return this->operator=(other.borrow()); + } + + + class ImmortalObject : public PyObjectPointer<> + { + private: + G_NO_ASSIGNMENT_OF_CLS(ImmortalObject); + public: + explicit ImmortalObject(PyObject* it) : PyObjectPointer<>(it) + { + } + + ImmortalObject(const ImmortalObject& other) + : PyObjectPointer<>(other.p) + { + + } + + /** + * Become the new owner of the object. Does not change the + * reference count. + */ + ImmortalObject& operator=(PyObject* it) + { + assert(this->p == nullptr); + this->p = it; + return *this; + } + + static ImmortalObject consuming(PyObject* it) + { + return ImmortalObject(it); + } + + inline operator PyObject*() const + { + return this->p; + } + }; + + class ImmortalString : public ImmortalObject + { + private: + G_NO_COPIES_OF_CLS(ImmortalString); + const char* str; + public: + ImmortalString(const char* const str) : + ImmortalObject(str ? Require(PyUnicode_InternFromString(str)) : nullptr) + { + this->str = str; + } + + inline ImmortalString& operator=(const char* const str) + { + if (!this->p) { + this->p = Require(PyUnicode_InternFromString(str)); + this->str = str; + } + else { + assert(this->str == str); + } + return *this; + } + + inline operator std::string() const + { + return this->str; + } + + }; + + class ImmortalEventName : public ImmortalString + { + private: + G_NO_COPIES_OF_CLS(ImmortalEventName); + public: + ImmortalEventName(const char* const str) : ImmortalString(str) + {} + }; + + class ImmortalException : public ImmortalObject + { + private: + G_NO_COPIES_OF_CLS(ImmortalException); + public: + ImmortalException(const char* const name, PyObject* base=nullptr) : + ImmortalObject(name + // Python 2.7 isn't const correct + ? Require(PyErr_NewException((char*)name, base, nullptr)) + : nullptr) + {} + + inline bool PyExceptionMatches() const + { + return PyErr_ExceptionMatches(this->p) > 0; + } + + }; + + template + inline OwnedObject PyObjectPointer::PyStr() const noexcept + { + if (!this->p) { + return OwnedObject(); + } + return OwnedObject::consuming(PyObject_Str(reinterpret_cast(this->p))); + } + + template + inline const std::string PyObjectPointer::as_str() const noexcept + { + // NOTE: This is not Python exception safe. + if (this->p) { + // The Python APIs return a cached char* value that's only valid + // as long as the original object stays around, and we're + // about to (probably) toss it. Hence the copy to std::string. + OwnedObject py_str = this->PyStr(); + if (!py_str) { + return "(nil)"; + } + return PyUnicode_AsUTF8(py_str.borrow()); + } + return "(nil)"; + } + + template + inline OwnedObject PyObjectPointer::PyGetAttr(const ImmortalObject& name) const noexcept + { + assert(this->p); + return OwnedObject::consuming(PyObject_GetAttr(reinterpret_cast(this->p), name)); + } + + template + inline OwnedObject PyObjectPointer::PyRequireAttr(const char* const name) const + { + assert(this->p); + return OwnedObject::consuming(Require(PyObject_GetAttrString(this->p, name), name)); + } + + template + inline OwnedObject PyObjectPointer::PyRequireAttr(const ImmortalString& name) const + { + assert(this->p); + return OwnedObject::consuming(Require( + PyObject_GetAttr( + reinterpret_cast(this->p), + name + ), + name + )); + } + + template + inline OwnedObject PyObjectPointer::PyCall(const BorrowedObject& arg) const + { + return this->PyCall(arg.borrow()); + } + + template + inline OwnedObject PyObjectPointer::PyCall(PyGreenlet* arg) const + { + return this->PyCall(reinterpret_cast(arg)); + } + + template + inline OwnedObject PyObjectPointer::PyCall(PyObject* arg) const + { + assert(this->p); + return OwnedObject::consuming(PyObject_CallFunctionObjArgs(this->p, arg, NULL)); + } + + template + inline OwnedObject PyObjectPointer::PyCall(const BorrowedObject args, + const BorrowedObject kwargs) const + { + assert(this->p); + return OwnedObject::consuming(PyObject_Call(this->p, args, kwargs)); + } + + template + inline OwnedObject PyObjectPointer::PyCall(const OwnedObject& args, + const OwnedObject& kwargs) const + { + assert(this->p); + return OwnedObject::consuming(PyObject_Call(this->p, args.borrow(), kwargs.borrow())); + } + + inline void + ListChecker(void * p) + { + if (!p) { + return; + } + if (!PyList_Check(p)) { + throw TypeError("Expected a list"); + } + } + + class OwnedList : public OwnedReference + { + private: + G_NO_ASSIGNMENT_OF_CLS(OwnedList); + public: + // TODO: Would like to use move. + explicit OwnedList(const OwnedObject& other) + : OwnedReference(other) + { + } + + OwnedList& operator=(const OwnedObject& other) + { + if (other && PyList_Check(other.p)) { + // Valid list. Own a new reference to it, discard the + // reference to what we did own. + PyObject* new_ptr = other.p; + Py_INCREF(new_ptr); + Py_XDECREF(this->p); + this->p = new_ptr; + } + else { + // Either the other object was NULL (an error) or it + // wasn't a list. Either way, we're now invalidated. + Py_XDECREF(this->p); + this->p = nullptr; + } + return *this; + } + + inline bool empty() const + { + return PyList_GET_SIZE(p) == 0; + } + + inline Py_ssize_t size() const + { + return PyList_GET_SIZE(p); + } + + inline BorrowedObject at(const Py_ssize_t index) const + { + return PyList_GET_ITEM(p, index); + } + + inline void clear() + { + PyList_SetSlice(p, 0, PyList_GET_SIZE(p), NULL); + } + }; + + // Use this to represent the module object used at module init + // time. + // This could either be a borrowed (Py2) or new (Py3) reference; + // either way, we don't want to do any memory management + // on it here, Python itself will handle that. + // XXX: Actually, that's not quite right. On Python 3, if an + // exception occurs before we return to the interpreter, this will + // leak; but all previous versions also had that problem. + class CreatedModule : public PyObjectPointer<> + { + private: + G_NO_COPIES_OF_CLS(CreatedModule); + public: + CreatedModule(PyModuleDef& mod_def) : PyObjectPointer<>( + Require(PyModule_Create(&mod_def))) + { + } + + // PyAddObject(): Add a reference to the object to the module. + // On return, the reference count of the object is unchanged. + // + // The docs warn that PyModule_AddObject only steals the + // reference on success, so if it fails after we've incref'd + // or allocated, we're responsible for the decref. + void PyAddObject(const char* name, const long new_bool) + { + OwnedObject p = OwnedObject::consuming(Require(PyBool_FromLong(new_bool))); + this->PyAddObject(name, p); + } + + void PyAddObject(const char* name, const OwnedObject& new_object) + { + // The caller already owns a reference they will decref + // when their variable goes out of scope, we still need to + // incref/decref. + this->PyAddObject(name, new_object.borrow()); + } + + void PyAddObject(const char* name, const ImmortalObject& new_object) + { + this->PyAddObject(name, new_object.borrow()); + } + + void PyAddObject(const char* name, PyTypeObject& type) + { + this->PyAddObject(name, reinterpret_cast(&type)); + } + + void PyAddObject(const char* name, PyObject* new_object) + { + Py_INCREF(new_object); + try { + Require(PyModule_AddObject(this->p, name, new_object)); + } + catch (const PyErrOccurred&) { + Py_DECREF(p); + throw; + } + } + }; + + class PyErrFetchParam : public PyObjectPointer<> + { + // Not an owned object, because we can't be initialized with + // one, and we only sometimes acquire ownership. + private: + G_NO_COPIES_OF_CLS(PyErrFetchParam); + public: + // To allow declaring these and passing them to + // PyErr_Fetch we implement the empty constructor, + // and the address operator. + PyErrFetchParam() : PyObjectPointer<>(nullptr) + { + } + + PyObject** operator&() + { + return &this->p; + } + + // This allows us to pass one directly without the &, + // BUT it has higher precedence than the bool operator + // if it's not explicit. + operator PyObject**() + { + return &this->p; + } + + // We don't want to be able to pass these to Py_DECREF and + // such so we don't have the implicit PyObject* conversion. + + inline PyObject* relinquish_ownership() + { + PyObject* result = this->p; + this->p = nullptr; + return result; + } + + ~PyErrFetchParam() + { + Py_XDECREF(p); + } + }; + + class OwnedErrPiece : public OwnedObject + { + private: + + public: + // Unlike OwnedObject, this increments the refcount. + OwnedErrPiece(PyObject* p=nullptr) : OwnedObject(p) + { + this->acquire(); + } + + PyObject** operator&() + { + return &this->p; + } + + inline operator PyObject*() const + { + return this->p; + } + + operator PyTypeObject*() const + { + return reinterpret_cast(this->p); + } + }; + + class PyErrPieces + { + private: + OwnedErrPiece type; + OwnedErrPiece instance; + OwnedErrPiece traceback; + bool restored; + public: + // Takes new references; if we're destroyed before + // restoring the error, we drop the references. + PyErrPieces(PyObject* t, PyObject* v, PyObject* tb) : + type(t), + instance(v), + traceback(tb), + restored(0) + { + this->normalize(); + } + + PyErrPieces() : + restored(0) + { + // PyErr_Fetch transfers ownership to us, so + // we don't actually need to INCREF; but we *do* + // need to DECREF if we're not restored. + PyErrFetchParam t, v, tb; + PyErr_Fetch(&t, &v, &tb); + type.steal(t.relinquish_ownership()); + instance.steal(v.relinquish_ownership()); + traceback.steal(tb.relinquish_ownership()); + } + + void PyErrRestore() + { + // can only do this once + assert(!this->restored); + this->restored = true; + PyErr_Restore( + this->type.relinquish_ownership(), + this->instance.relinquish_ownership(), + this->traceback.relinquish_ownership()); + assert(!this->type && !this->instance && !this->traceback); + } + + private: + void normalize() + { + // First, check the traceback argument, replacing None, + // with NULL + if (traceback.is_None()) { + traceback = nullptr; + } + + if (traceback && !PyTraceBack_Check(traceback.borrow())) { + throw PyErrOccurred(PyExc_TypeError, + "throw() third argument must be a traceback object"); + } + + if (PyExceptionClass_Check(type)) { + // If we just had a type, we'll now have a type and + // instance. + // The type's refcount will have gone up by one + // because of the instance and the instance will have + // a refcount of one. Either way, we owned, and still + // do own, exactly one reference. + PyErr_NormalizeException(&type, &instance, &traceback); + + } + else if (PyExceptionInstance_Check(type)) { + /* Raising an instance --- usually that means an + object that is a subclass of BaseException, but on + Python 2, that can also mean an arbitrary old-style + object. The value should be a dummy. */ + if (instance && !instance.is_None()) { + throw PyErrOccurred( + PyExc_TypeError, + "instance exception may not have a separate value"); + } + /* Normalize to raise , */ + this->instance = this->type; + this->type = PyExceptionInstance_Class(instance.borrow()); + + /* + It would be tempting to do this: + + Py_ssize_t type_count = Py_REFCNT(Py_TYPE(instance.borrow())); + this->type = PyExceptionInstance_Class(instance.borrow()); + assert(this->type.REFCNT() == type_count + 1); + + But that doesn't work on Python 2 in the case of + old-style instances: The result of Py_TYPE is going to + be the global shared that all + old-style classes have, while the return of Instance_Class() + will be the Python-level class object. The two are unrelated. + */ + } + else { + /* Not something you can raise. throw() fails. */ + PyErr_Format(PyExc_TypeError, + "exceptions must be classes, or instances, not %s", + Py_TYPE(type.borrow())->tp_name); + throw PyErrOccurred(); + } + } + }; + + // PyArg_Parse's O argument returns a borrowed reference. + class PyArgParseParam : public BorrowedObject + { + private: + G_NO_COPIES_OF_CLS(PyArgParseParam); + public: + explicit PyArgParseParam(PyObject* p=nullptr) : BorrowedObject(p) + { + } + + inline PyObject** operator&() + { + return &this->p; + } + }; + +};}; + +#endif diff --git a/psets/9/finance/env/lib/python3.12/site-packages/greenlet/greenlet_slp_switch.hpp b/psets/9/finance/env/lib/python3.12/site-packages/greenlet/greenlet_slp_switch.hpp new file mode 100644 index 0000000..bd4b7ae --- /dev/null +++ b/psets/9/finance/env/lib/python3.12/site-packages/greenlet/greenlet_slp_switch.hpp @@ -0,0 +1,99 @@ +#ifndef GREENLET_SLP_SWITCH_HPP +#define GREENLET_SLP_SWITCH_HPP + +#include "greenlet_compiler_compat.hpp" +#include "greenlet_refs.hpp" + +/* + * the following macros are spliced into the OS/compiler + * specific code, in order to simplify maintenance. + */ +// We can save about 10% of the time it takes to switch greenlets if +// we thread the thread state through the slp_save_state() and the +// following slp_restore_state() calls from +// slp_switch()->g_switchstack() (which already needs to access it). +// +// However: +// +// that requires changing the prototypes and implementations of the +// switching functions. If we just change the prototype of +// slp_switch() to accept the argument and update the macros, without +// changing the implementation of slp_switch(), we get crashes on +// 64-bit Linux and 32-bit x86 (for reasons that aren't 100% clear); +// on the other hand, 64-bit macOS seems to be fine. Also, 64-bit +// windows is an issue because slp_switch is written fully in assembly +// and currently ignores its argument so some code would have to be +// adjusted there to pass the argument on to the +// ``slp_save_state_asm()`` function (but interestingly, because of +// the calling convention, the extra argument is just ignored and +// things function fine, albeit slower, if we just modify +// ``slp_save_state_asm`()` to fetch the pointer to pass to the +// macro.) +// +// Our compromise is to use a *glabal*, untracked, weak, pointer +// to the necessary thread state during the process of switching only. +// This is safe because we're protected by the GIL, and if we're +// running this code, the thread isn't exiting. This also nets us a +// 10-12% speed improvement. + +static greenlet::Greenlet* volatile switching_thread_state = nullptr; + + +extern "C" { +static int GREENLET_NOINLINE(slp_save_state_trampoline)(char* stackref); +static void GREENLET_NOINLINE(slp_restore_state_trampoline)(); +} + + +#define SLP_SAVE_STATE(stackref, stsizediff) \ +do { \ + assert(switching_thread_state); \ + stackref += STACK_MAGIC; \ + if (slp_save_state_trampoline((char*)stackref)) \ + return -1; \ + if (!switching_thread_state->active()) \ + return 1; \ + stsizediff = switching_thread_state->stack_start() - (char*)stackref; \ +} while (0) + +#define SLP_RESTORE_STATE() slp_restore_state_trampoline() + +#define SLP_EVAL +extern "C" { +#define slp_switch GREENLET_NOINLINE(slp_switch) +#include "slp_platformselect.h" +} +#undef slp_switch + +#ifndef STACK_MAGIC +# error \ + "greenlet needs to be ported to this platform, or taught how to detect your compiler properly." +#endif /* !STACK_MAGIC */ + + + +#ifdef EXTERNAL_ASM +/* CCP addition: Make these functions, to be called from assembler. + * The token include file for the given platform should enable the + * EXTERNAL_ASM define so that this is included. + */ +extern "C" { +intptr_t +slp_save_state_asm(intptr_t* ref) +{ + intptr_t diff; + SLP_SAVE_STATE(ref, diff); + return diff; +} + +void +slp_restore_state_asm(void) +{ + SLP_RESTORE_STATE(); +} + +extern int slp_switch(void); +}; +#endif + +#endif diff --git a/psets/9/finance/env/lib/python3.12/site-packages/greenlet/greenlet_thread_support.hpp b/psets/9/finance/env/lib/python3.12/site-packages/greenlet/greenlet_thread_support.hpp new file mode 100644 index 0000000..3ded7d2 --- /dev/null +++ b/psets/9/finance/env/lib/python3.12/site-packages/greenlet/greenlet_thread_support.hpp @@ -0,0 +1,31 @@ +#ifndef GREENLET_THREAD_SUPPORT_HPP +#define GREENLET_THREAD_SUPPORT_HPP + +/** + * Defines various utility functions to help greenlet integrate well + * with threads. This used to be needed when we supported Python + * 2.7 on Windows, which used a very old compiler. We wrote an + * alternative implementation using Python APIs and POSIX or Windows + * APIs, but that's no longer needed. So this file is a shadow of its + * former self --- but may be needed in the future. + */ + +#include +#include +#include + +#include "greenlet_compiler_compat.hpp" + +namespace greenlet { + typedef std::mutex Mutex; + typedef std::lock_guard LockGuard; + class LockInitError : public std::runtime_error + { + public: + LockInitError(const char* what) : std::runtime_error(what) + {}; + }; +}; + + +#endif /* GREENLET_THREAD_SUPPORT_HPP */ diff --git a/psets/9/finance/env/lib/python3.12/site-packages/greenlet/platform/__init__.py b/psets/9/finance/env/lib/python3.12/site-packages/greenlet/platform/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/psets/9/finance/env/lib/python3.12/site-packages/greenlet/platform/__pycache__/__init__.cpython-312.pyc b/psets/9/finance/env/lib/python3.12/site-packages/greenlet/platform/__pycache__/__init__.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..3b441467b96a1da59a858173337b70013a5a4c74 GIT binary patch literal 198 zcmX@j%ge<81ShH@(?RrO5P=Rpvj9b=GgLBYGWxA#C}INgK7-W!O4ZNJE75mJEJ@AN zPtH%t%uCl#E;cpLFDOneDb}~tPs_|p%u7zyPt7aS&&f>EFQ_cZ$j>v@Gc?jK&MZmQ zEl5nxPE1cN)=w`=P0hgjEsy$%s>_Z;f6HA literal 0 HcmV?d00001 diff --git a/psets/9/finance/env/lib/python3.12/site-packages/greenlet/platform/setup_switch_x64_masm.cmd b/psets/9/finance/env/lib/python3.12/site-packages/greenlet/platform/setup_switch_x64_masm.cmd new file mode 100644 index 0000000..038ced2 --- /dev/null +++ b/psets/9/finance/env/lib/python3.12/site-packages/greenlet/platform/setup_switch_x64_masm.cmd @@ -0,0 +1,2 @@ +call "C:\Program Files (x86)\Microsoft Visual Studio 9.0\VC\vcvarsall.bat" amd64 +ml64 /nologo /c /Fo switch_x64_masm.obj switch_x64_masm.asm diff --git a/psets/9/finance/env/lib/python3.12/site-packages/greenlet/platform/switch_aarch64_gcc.h b/psets/9/finance/env/lib/python3.12/site-packages/greenlet/platform/switch_aarch64_gcc.h new file mode 100644 index 0000000..058617c --- /dev/null +++ b/psets/9/finance/env/lib/python3.12/site-packages/greenlet/platform/switch_aarch64_gcc.h @@ -0,0 +1,124 @@ +/* + * this is the internal transfer function. + * + * HISTORY + * 07-Sep-16 Add clang support using x register naming. Fredrik Fornwall + * 13-Apr-13 Add support for strange GCC caller-save decisions + * 08-Apr-13 File creation. Michael Matz + * + * NOTES + * + * Simply save all callee saved registers + * + */ + +#define STACK_REFPLUS 1 + +#ifdef SLP_EVAL +#define STACK_MAGIC 0 +#define REGS_TO_SAVE "x19", "x20", "x21", "x22", "x23", "x24", "x25", "x26", \ + "x27", "x28", "x30" /* aka lr */, \ + "v8", "v9", "v10", "v11", \ + "v12", "v13", "v14", "v15" + +/* + * Recall: + asm asm-qualifiers ( AssemblerTemplate + : OutputOperands + [ : InputOperands + [ : Clobbers ] ]) + + or (if asm-qualifiers contains 'goto') + + asm asm-qualifiers ( AssemblerTemplate + : OutputOperands + : InputOperands + : Clobbers + : GotoLabels) + + and OutputOperands are + + [ [asmSymbolicName] ] constraint (cvariablename) + + When a name is given, refer to it as ``%[the name]``. + When not given, ``%i`` where ``i`` is the zero-based index. + + constraints starting with ``=`` means only writing; ``+`` means + reading and writing. + + This is followed by ``r`` (must be register) or ``m`` (must be memory) + and these can be combined. + + The ``cvariablename`` is actually an lvalue expression. + + In AArch65, 31 general purpose registers. If named X0... they are + 64-bit. If named W0... they are the bottom 32 bits of the + corresponding 64 bit register. + + XZR and WZR are hardcoded to 0, and ignore writes. + + Arguments are in X0..X7. C++ uses X0 for ``this``. X0 holds simple return + values (?) + + Whenever a W register is written, the top half of the X register is zeroed. + */ + +static int +slp_switch(void) +{ + int err; + void *fp; + /* Windowz uses a 32-bit long on a 64-bit platform, unlike the rest of + the world, and in theory we can be compiled with GCC/llvm on 64-bit + windows. So we need a fixed-width type. + */ + int64_t *stackref, stsizediff; + __asm__ volatile ("" : : : REGS_TO_SAVE); + __asm__ volatile ("str x29, %0" : "=m"(fp) : : ); + __asm__ ("mov %0, sp" : "=r" (stackref)); + { + SLP_SAVE_STATE(stackref, stsizediff); + __asm__ volatile ( + "add sp,sp,%0\n" + "add x29,x29,%0\n" + : + : "r" (stsizediff) + ); + SLP_RESTORE_STATE(); + /* SLP_SAVE_STATE macro contains some return statements + (of -1 and 1). It falls through only when + the return value of slp_save_state() is zero, which + is placed in x0. + In that case we (slp_switch) also want to return zero + (also in x0 of course). + Now, some GCC versions (seen with 4.8) think it's a + good idea to save/restore x0 around the call to + slp_restore_state(), instead of simply zeroing it + at the return below. But slp_restore_state + writes random values to the stack slot used for this + save/restore (from when it once was saved above in + SLP_SAVE_STATE, when it was still uninitialized), so + "restoring" that precious zero actually makes us + return random values. There are some ways to make + GCC not use that zero value in the normal return path + (e.g. making err volatile, but that costs a little + stack space), and the simplest is to call a function + that returns an unknown value (which happens to be zero), + so the saved/restored value is unused. + + Thus, this line stores a 0 into the ``err`` variable + (which must be held in a register for this instruction, + of course). The ``w`` qualifier causes the instruction + to use W0 instead of X0, otherwise we get a warning + about a value size mismatch (because err is an int, + and aarch64 platforms are LP64: 32-bit int, 64 bit long + and pointer). + */ + __asm__ volatile ("mov %w0, #0" : "=r" (err)); + } + __asm__ volatile ("ldr x29, %0" : : "m" (fp) :); + __asm__ volatile ("" : : : REGS_TO_SAVE); + return err; +} + +#endif diff --git a/psets/9/finance/env/lib/python3.12/site-packages/greenlet/platform/switch_alpha_unix.h b/psets/9/finance/env/lib/python3.12/site-packages/greenlet/platform/switch_alpha_unix.h new file mode 100644 index 0000000..7e07abf --- /dev/null +++ b/psets/9/finance/env/lib/python3.12/site-packages/greenlet/platform/switch_alpha_unix.h @@ -0,0 +1,30 @@ +#define STACK_REFPLUS 1 + +#ifdef SLP_EVAL +#define STACK_MAGIC 0 + +#define REGS_TO_SAVE "$9", "$10", "$11", "$12", "$13", "$14", "$15", \ + "$f2", "$f3", "$f4", "$f5", "$f6", "$f7", "$f8", "$f9" + +static int +slp_switch(void) +{ + int ret; + long *stackref, stsizediff; + __asm__ volatile ("" : : : REGS_TO_SAVE); + __asm__ volatile ("mov $30, %0" : "=r" (stackref) : ); + { + SLP_SAVE_STATE(stackref, stsizediff); + __asm__ volatile ( + "addq $30, %0, $30\n\t" + : /* no outputs */ + : "r" (stsizediff) + ); + SLP_RESTORE_STATE(); + } + __asm__ volatile ("" : : : REGS_TO_SAVE); + __asm__ volatile ("mov $31, %0" : "=r" (ret) : ); + return ret; +} + +#endif diff --git a/psets/9/finance/env/lib/python3.12/site-packages/greenlet/platform/switch_amd64_unix.h b/psets/9/finance/env/lib/python3.12/site-packages/greenlet/platform/switch_amd64_unix.h new file mode 100644 index 0000000..d470110 --- /dev/null +++ b/psets/9/finance/env/lib/python3.12/site-packages/greenlet/platform/switch_amd64_unix.h @@ -0,0 +1,87 @@ +/* + * this is the internal transfer function. + * + * HISTORY + * 3-May-13 Ralf Schmitt + * Add support for strange GCC caller-save decisions + * (ported from switch_aarch64_gcc.h) + * 18-Aug-11 Alexey Borzenkov + * Correctly save rbp, csr and cw + * 01-Apr-04 Hye-Shik Chang + * Ported from i386 to amd64. + * 24-Nov-02 Christian Tismer + * needed to add another magic constant to insure + * that f in slp_eval_frame(PyFrameObject *f) + * STACK_REFPLUS will probably be 1 in most cases. + * gets included into the saved stack area. + * 17-Sep-02 Christian Tismer + * after virtualizing stack save/restore, the + * stack size shrunk a bit. Needed to introduce + * an adjustment STACK_MAGIC per platform. + * 15-Sep-02 Gerd Woetzel + * slightly changed framework for spark + * 31-Avr-02 Armin Rigo + * Added ebx, esi and edi register-saves. + * 01-Mar-02 Samual M. Rushing + * Ported from i386. + */ + +#define STACK_REFPLUS 1 + +#ifdef SLP_EVAL + +/* #define STACK_MAGIC 3 */ +/* the above works fine with gcc 2.96, but 2.95.3 wants this */ +#define STACK_MAGIC 0 + +#define REGS_TO_SAVE "r12", "r13", "r14", "r15" + +static int +slp_switch(void) +{ + int err; + void* rbp; + void* rbx; + unsigned int csr; + unsigned short cw; + /* This used to be declared 'register', but that does nothing in + modern compilers and is explicitly forbidden in some new + standards. */ + long *stackref, stsizediff; + __asm__ volatile ("" : : : REGS_TO_SAVE); + __asm__ volatile ("fstcw %0" : "=m" (cw)); + __asm__ volatile ("stmxcsr %0" : "=m" (csr)); + __asm__ volatile ("movq %%rbp, %0" : "=m" (rbp)); + __asm__ volatile ("movq %%rbx, %0" : "=m" (rbx)); + __asm__ ("movq %%rsp, %0" : "=g" (stackref)); + { + SLP_SAVE_STATE(stackref, stsizediff); + __asm__ volatile ( + "addq %0, %%rsp\n" + "addq %0, %%rbp\n" + : + : "r" (stsizediff) + ); + SLP_RESTORE_STATE(); + __asm__ volatile ("xorq %%rax, %%rax" : "=a" (err)); + } + __asm__ volatile ("movq %0, %%rbx" : : "m" (rbx)); + __asm__ volatile ("movq %0, %%rbp" : : "m" (rbp)); + __asm__ volatile ("ldmxcsr %0" : : "m" (csr)); + __asm__ volatile ("fldcw %0" : : "m" (cw)); + __asm__ volatile ("" : : : REGS_TO_SAVE); + return err; +} + +#endif + +/* + * further self-processing support + */ + +/* + * if you want to add self-inspection tools, place them + * here. See the x86_msvc for the necessary defines. + * These features are highly experimental und not + * essential yet. + */ diff --git a/psets/9/finance/env/lib/python3.12/site-packages/greenlet/platform/switch_arm32_gcc.h b/psets/9/finance/env/lib/python3.12/site-packages/greenlet/platform/switch_arm32_gcc.h new file mode 100644 index 0000000..655003a --- /dev/null +++ b/psets/9/finance/env/lib/python3.12/site-packages/greenlet/platform/switch_arm32_gcc.h @@ -0,0 +1,79 @@ +/* + * this is the internal transfer function. + * + * HISTORY + * 14-Aug-06 File creation. Ported from Arm Thumb. Sylvain Baro + * 3-Sep-06 Commented out saving of r1-r3 (r4 already commented out) as I + * read that these do not need to be saved. Also added notes and + * errors related to the frame pointer. Richard Tew. + * + * NOTES + * + * It is not possible to detect if fp is used or not, so the supplied + * switch function needs to support it, so that you can remove it if + * it does not apply to you. + * + * POSSIBLE ERRORS + * + * "fp cannot be used in asm here" + * + * - Try commenting out "fp" in REGS_TO_SAVE. + * + */ + +#define STACK_REFPLUS 1 + +#ifdef SLP_EVAL +#define STACK_MAGIC 0 +#define REG_SP "sp" +#define REG_SPSP "sp,sp" +#ifdef __thumb__ +#define REG_FP "r7" +#define REG_FPFP "r7,r7" +#define REGS_TO_SAVE_GENERAL "r4", "r5", "r6", "r8", "r9", "r10", "r11", "lr" +#else +#define REG_FP "fp" +#define REG_FPFP "fp,fp" +#define REGS_TO_SAVE_GENERAL "r4", "r5", "r6", "r7", "r8", "r9", "r10", "lr" +#endif +#if defined(__SOFTFP__) +#define REGS_TO_SAVE REGS_TO_SAVE_GENERAL +#elif defined(__VFP_FP__) +#define REGS_TO_SAVE REGS_TO_SAVE_GENERAL, "d8", "d9", "d10", "d11", \ + "d12", "d13", "d14", "d15" +#elif defined(__MAVERICK__) +#define REGS_TO_SAVE REGS_TO_SAVE_GENERAL, "mvf4", "mvf5", "mvf6", "mvf7", \ + "mvf8", "mvf9", "mvf10", "mvf11", \ + "mvf12", "mvf13", "mvf14", "mvf15" +#else +#define REGS_TO_SAVE REGS_TO_SAVE_GENERAL, "f4", "f5", "f6", "f7" +#endif + +static int +#ifdef __GNUC__ +__attribute__((optimize("no-omit-frame-pointer"))) +#endif +slp_switch(void) +{ + void *fp; + int *stackref, stsizediff; + int result; + __asm__ volatile ("" : : : REGS_TO_SAVE); + __asm__ volatile ("mov r0," REG_FP "\n\tstr r0,%0" : "=m" (fp) : : "r0"); + __asm__ ("mov %0," REG_SP : "=r" (stackref)); + { + SLP_SAVE_STATE(stackref, stsizediff); + __asm__ volatile ( + "add " REG_SPSP ",%0\n" + "add " REG_FPFP ",%0\n" + : + : "r" (stsizediff) + ); + SLP_RESTORE_STATE(); + } + __asm__ volatile ("ldr r0,%1\n\tmov " REG_FP ",r0\n\tmov %0, #0" : "=r" (result) : "m" (fp) : "r0"); + __asm__ volatile ("" : : : REGS_TO_SAVE); + return result; +} + +#endif diff --git a/psets/9/finance/env/lib/python3.12/site-packages/greenlet/platform/switch_arm32_ios.h b/psets/9/finance/env/lib/python3.12/site-packages/greenlet/platform/switch_arm32_ios.h new file mode 100644 index 0000000..9e640e1 --- /dev/null +++ b/psets/9/finance/env/lib/python3.12/site-packages/greenlet/platform/switch_arm32_ios.h @@ -0,0 +1,67 @@ +/* + * this is the internal transfer function. + * + * HISTORY + * 31-May-15 iOS support. Ported from arm32. Proton + * + * NOTES + * + * It is not possible to detect if fp is used or not, so the supplied + * switch function needs to support it, so that you can remove it if + * it does not apply to you. + * + * POSSIBLE ERRORS + * + * "fp cannot be used in asm here" + * + * - Try commenting out "fp" in REGS_TO_SAVE. + * + */ + +#define STACK_REFPLUS 1 + +#ifdef SLP_EVAL + +#define STACK_MAGIC 0 +#define REG_SP "sp" +#define REG_SPSP "sp,sp" +#define REG_FP "r7" +#define REG_FPFP "r7,r7" +#define REGS_TO_SAVE_GENERAL "r4", "r5", "r6", "r8", "r10", "r11", "lr" +#define REGS_TO_SAVE REGS_TO_SAVE_GENERAL, "d8", "d9", "d10", "d11", \ + "d12", "d13", "d14", "d15" + +static int +#ifdef __GNUC__ +__attribute__((optimize("no-omit-frame-pointer"))) +#endif +slp_switch(void) +{ + void *fp; + int *stackref, stsizediff, result; + __asm__ volatile ("" : : : REGS_TO_SAVE); + __asm__ volatile ("str " REG_FP ",%0" : "=m" (fp)); + __asm__ ("mov %0," REG_SP : "=r" (stackref)); + { + SLP_SAVE_STATE(stackref, stsizediff); + __asm__ volatile ( + "add " REG_SPSP ",%0\n" + "add " REG_FPFP ",%0\n" + : + : "r" (stsizediff) + : REGS_TO_SAVE /* Clobber registers, force compiler to + * recalculate address of void *fp from REG_SP or REG_FP */ + ); + SLP_RESTORE_STATE(); + } + __asm__ volatile ( + "ldr " REG_FP ", %1\n\t" + "mov %0, #0" + : "=r" (result) + : "m" (fp) + : REGS_TO_SAVE /* Force compiler to restore saved registers after this */ + ); + return result; +} + +#endif diff --git a/psets/9/finance/env/lib/python3.12/site-packages/greenlet/platform/switch_arm64_masm.asm b/psets/9/finance/env/lib/python3.12/site-packages/greenlet/platform/switch_arm64_masm.asm new file mode 100644 index 0000000..29f9c22 --- /dev/null +++ b/psets/9/finance/env/lib/python3.12/site-packages/greenlet/platform/switch_arm64_masm.asm @@ -0,0 +1,53 @@ + AREA switch_arm64_masm, CODE, READONLY; + GLOBAL slp_switch [FUNC] + EXTERN slp_save_state_asm + EXTERN slp_restore_state_asm + +slp_switch + ; push callee saved registers to stack + stp x19, x20, [sp, #-16]! + stp x21, x22, [sp, #-16]! + stp x23, x24, [sp, #-16]! + stp x25, x26, [sp, #-16]! + stp x27, x28, [sp, #-16]! + stp x29, x30, [sp, #-16]! + stp d8, d9, [sp, #-16]! + stp d10, d11, [sp, #-16]! + stp d12, d13, [sp, #-16]! + stp d14, d15, [sp, #-16]! + + ; call slp_save_state_asm with stack pointer + mov x0, sp + bl slp_save_state_asm + + ; early return for return value of 1 and -1 + cmp x0, #-1 + b.eq RETURN + cmp x0, #1 + b.eq RETURN + + ; increment stack and frame pointer + add sp, sp, x0 + add x29, x29, x0 + + bl slp_restore_state_asm + + ; store return value for successful completion of routine + mov x0, #0 + +RETURN + ; pop registers from stack + ldp d14, d15, [sp], #16 + ldp d12, d13, [sp], #16 + ldp d10, d11, [sp], #16 + ldp d8, d9, [sp], #16 + ldp x29, x30, [sp], #16 + ldp x27, x28, [sp], #16 + ldp x25, x26, [sp], #16 + ldp x23, x24, [sp], #16 + ldp x21, x22, [sp], #16 + ldp x19, x20, [sp], #16 + + ret + + END diff --git a/psets/9/finance/env/lib/python3.12/site-packages/greenlet/platform/switch_arm64_masm.obj b/psets/9/finance/env/lib/python3.12/site-packages/greenlet/platform/switch_arm64_masm.obj new file mode 100644 index 0000000000000000000000000000000000000000..f6f220e4310baaa9756110685ce7d6a2bdf90c37 GIT binary patch literal 746 zcma)4PiqrF6n~qoo~*PNZ{i+=wji4b#Xu2~wiJpGk)*AMF07NyB(9n1#+i+!)I;v| zBKQG3?t1eB$T(lYgGb4+lu{_QmQrebldQB_4?cMF-uu0IZ{DA2e8@rZ+e^~30488W z`B{KPh%yV{HEIpyeum^wI#7P*HfX)ux?9U&c!SFK-$o|OFtKn{Q|a-#N>2inp0-tb zCRKXAtg2SolaoLv$Ll&ds_Epj?SH+8K{t?XSjKaFsEy%yh}=V70BaHj zEY5kWk_zcJo{$SSUL~=K(zW|tnhm$rA z<%dZ$q?>RX*18r{!azhaYR1lVb;g;mR-6h!#F>|p@;aje%0a|CZrE7s+SXuT>MS=Y ziQPiMY-5DD&5+S7^H03fy7qt7ir}L34kK|h68s-MU>{lXOqlr?!Y=`~WwviNenFS_ zZalVSHh-0FU4lj#X8u5`ODn6@#{f?dHE&%XdP~_I3;$RS9-(z*>>ydkm*f@oWlUn~ Qn+^;lsEi}=H#!Q3U&UU-WdHyG literal 0 HcmV?d00001 diff --git a/psets/9/finance/env/lib/python3.12/site-packages/greenlet/platform/switch_arm64_msvc.h b/psets/9/finance/env/lib/python3.12/site-packages/greenlet/platform/switch_arm64_msvc.h new file mode 100644 index 0000000..7ab7f45 --- /dev/null +++ b/psets/9/finance/env/lib/python3.12/site-packages/greenlet/platform/switch_arm64_msvc.h @@ -0,0 +1,17 @@ +/* + * this is the internal transfer function. + * + * HISTORY + * 21-Oct-21 Niyas Sait + * First version to enable win/arm64 support. + */ + +#define STACK_REFPLUS 1 +#define STACK_MAGIC 0 + +/* Use the generic support for an external assembly language slp_switch function. */ +#define EXTERNAL_ASM + +#ifdef SLP_EVAL +/* This always uses the external masm assembly file. */ +#endif \ No newline at end of file diff --git a/psets/9/finance/env/lib/python3.12/site-packages/greenlet/platform/switch_csky_gcc.h b/psets/9/finance/env/lib/python3.12/site-packages/greenlet/platform/switch_csky_gcc.h new file mode 100644 index 0000000..ac469d3 --- /dev/null +++ b/psets/9/finance/env/lib/python3.12/site-packages/greenlet/platform/switch_csky_gcc.h @@ -0,0 +1,48 @@ +#ifdef SLP_EVAL +#define STACK_MAGIC 0 +#define REG_FP "r8" +#ifdef __CSKYABIV2__ +#define REGS_TO_SAVE_GENERAL "r4", "r5", "r6", "r7", "r9", "r10", "r11", "r15",\ + "r16", "r17", "r18", "r19", "r20", "r21", "r22",\ + "r23", "r24", "r25" + +#if defined (__CSKY_HARD_FLOAT__) || (__CSKY_VDSP__) +#define REGS_TO_SAVE REGS_TO_SAVE_GENERAL, "vr8", "vr9", "vr10", "vr11", "vr12",\ + "vr13", "vr14", "vr15" +#else +#define REGS_TO_SAVE REGS_TO_SAVE_GENERAL +#endif +#else +#define REGS_TO_SAVE "r9", "r10", "r11", "r12", "r13", "r15" +#endif + + +static int +#ifdef __GNUC__ +__attribute__((optimize("no-omit-frame-pointer"))) +#endif +slp_switch(void) +{ + int *stackref, stsizediff; + int result; + + __asm__ volatile ("" : : : REGS_TO_SAVE); + __asm__ ("mov %0, sp" : "=r" (stackref)); + { + SLP_SAVE_STATE(stackref, stsizediff); + __asm__ volatile ( + "addu sp,%0\n" + "addu "REG_FP",%0\n" + : + : "r" (stsizediff) + ); + + SLP_RESTORE_STATE(); + } + __asm__ volatile ("movi %0, 0" : "=r" (result)); + __asm__ volatile ("" : : : REGS_TO_SAVE); + + return result; +} + +#endif diff --git a/psets/9/finance/env/lib/python3.12/site-packages/greenlet/platform/switch_loongarch64_linux.h b/psets/9/finance/env/lib/python3.12/site-packages/greenlet/platform/switch_loongarch64_linux.h new file mode 100644 index 0000000..9eaf34e --- /dev/null +++ b/psets/9/finance/env/lib/python3.12/site-packages/greenlet/platform/switch_loongarch64_linux.h @@ -0,0 +1,31 @@ +#define STACK_REFPLUS 1 + +#ifdef SLP_EVAL +#define STACK_MAGIC 0 + +#define REGS_TO_SAVE "s0", "s1", "s2", "s3", "s4", "s5", \ + "s6", "s7", "s8", "fp", \ + "f24", "f25", "f26", "f27", "f28", "f29", "f30", "f31" + +static int +slp_switch(void) +{ + int ret; + long *stackref, stsizediff; + __asm__ volatile ("" : : : REGS_TO_SAVE); + __asm__ volatile ("move %0, $sp" : "=r" (stackref) : ); + { + SLP_SAVE_STATE(stackref, stsizediff); + __asm__ volatile ( + "add.d $sp, $sp, %0\n\t" + : /* no outputs */ + : "r" (stsizediff) + ); + SLP_RESTORE_STATE(); + } + __asm__ volatile ("" : : : REGS_TO_SAVE); + __asm__ volatile ("move %0, $zero" : "=r" (ret) : ); + return ret; +} + +#endif diff --git a/psets/9/finance/env/lib/python3.12/site-packages/greenlet/platform/switch_m68k_gcc.h b/psets/9/finance/env/lib/python3.12/site-packages/greenlet/platform/switch_m68k_gcc.h new file mode 100644 index 0000000..da761c2 --- /dev/null +++ b/psets/9/finance/env/lib/python3.12/site-packages/greenlet/platform/switch_m68k_gcc.h @@ -0,0 +1,38 @@ +/* + * this is the internal transfer function. + * + * HISTORY + * 2014-01-06 Andreas Schwab + * File created. + */ + +#ifdef SLP_EVAL + +#define STACK_MAGIC 0 + +#define REGS_TO_SAVE "%d2", "%d3", "%d4", "%d5", "%d6", "%d7", \ + "%a2", "%a3", "%a4" + +static int +slp_switch(void) +{ + int err; + int *stackref, stsizediff; + void *fp, *a5; + __asm__ volatile ("" : : : REGS_TO_SAVE); + __asm__ volatile ("move.l %%fp, %0" : "=m"(fp)); + __asm__ volatile ("move.l %%a5, %0" : "=m"(a5)); + __asm__ ("move.l %%sp, %0" : "=r"(stackref)); + { + SLP_SAVE_STATE(stackref, stsizediff); + __asm__ volatile ("add.l %0, %%sp; add.l %0, %%fp" : : "r"(stsizediff)); + SLP_RESTORE_STATE(); + __asm__ volatile ("clr.l %0" : "=g" (err)); + } + __asm__ volatile ("move.l %0, %%a5" : : "m"(a5)); + __asm__ volatile ("move.l %0, %%fp" : : "m"(fp)); + __asm__ volatile ("" : : : REGS_TO_SAVE); + return err; +} + +#endif diff --git a/psets/9/finance/env/lib/python3.12/site-packages/greenlet/platform/switch_mips_unix.h b/psets/9/finance/env/lib/python3.12/site-packages/greenlet/platform/switch_mips_unix.h new file mode 100644 index 0000000..b9003e9 --- /dev/null +++ b/psets/9/finance/env/lib/python3.12/site-packages/greenlet/platform/switch_mips_unix.h @@ -0,0 +1,64 @@ +/* + * this is the internal transfer function. + * + * HISTORY + * 20-Sep-14 Matt Madison + * Re-code the saving of the gp register for MIPS64. + * 05-Jan-08 Thiemo Seufer + * Ported from ppc. + */ + +#define STACK_REFPLUS 1 + +#ifdef SLP_EVAL + +#define STACK_MAGIC 0 + +#define REGS_TO_SAVE "$16", "$17", "$18", "$19", "$20", "$21", "$22", \ + "$23", "$30" +static int +slp_switch(void) +{ + int err; + int *stackref, stsizediff; +#ifdef __mips64 + uint64_t gpsave; +#endif + __asm__ __volatile__ ("" : : : REGS_TO_SAVE); +#ifdef __mips64 + __asm__ __volatile__ ("sd $28,%0" : "=m" (gpsave) : : ); +#endif + __asm__ ("move %0, $29" : "=r" (stackref) : ); + { + SLP_SAVE_STATE(stackref, stsizediff); + __asm__ __volatile__ ( +#ifdef __mips64 + "daddu $29, %0\n" +#else + "addu $29, %0\n" +#endif + : /* no outputs */ + : "r" (stsizediff) + ); + SLP_RESTORE_STATE(); + } +#ifdef __mips64 + __asm__ __volatile__ ("ld $28,%0" : : "m" (gpsave) : ); +#endif + __asm__ __volatile__ ("" : : : REGS_TO_SAVE); + __asm__ __volatile__ ("move %0, $0" : "=r" (err)); + return err; +} + +#endif + +/* + * further self-processing support + */ + +/* + * if you want to add self-inspection tools, place them + * here. See the x86_msvc for the necessary defines. + * These features are highly experimental und not + * essential yet. + */ diff --git a/psets/9/finance/env/lib/python3.12/site-packages/greenlet/platform/switch_ppc64_aix.h b/psets/9/finance/env/lib/python3.12/site-packages/greenlet/platform/switch_ppc64_aix.h new file mode 100644 index 0000000..e7e0b87 --- /dev/null +++ b/psets/9/finance/env/lib/python3.12/site-packages/greenlet/platform/switch_ppc64_aix.h @@ -0,0 +1,103 @@ +/* + * this is the internal transfer function. + * + * HISTORY + * 16-Oct-20 Jesse Gorzinski + * Copied from Linux PPC64 implementation + * 04-Sep-18 Alexey Borzenkov + * Workaround a gcc bug using manual save/restore of r30 + * 21-Mar-18 Tulio Magno Quites Machado Filho + * Added r30 to the list of saved registers in order to fully comply with + * both ppc64 ELFv1 ABI and the ppc64le ELFv2 ABI, that classify this + * register as a nonvolatile register used for local variables. + * 21-Mar-18 Laszlo Boszormenyi + * Save r2 (TOC pointer) manually. + * 10-Dec-13 Ulrich Weigand + * Support ELFv2 ABI. Save float/vector registers. + * 09-Mar-12 Michael Ellerman + * 64-bit implementation, copied from 32-bit. + * 07-Sep-05 (py-dev mailing list discussion) + * removed 'r31' from the register-saved. !!!! WARNING !!!! + * It means that this file can no longer be compiled statically! + * It is now only suitable as part of a dynamic library! + * 14-Jan-04 Bob Ippolito + * added cr2-cr4 to the registers to be saved. + * Open questions: Should we save FP registers? + * What about vector registers? + * Differences between darwin and unix? + * 24-Nov-02 Christian Tismer + * needed to add another magic constant to insure + * that f in slp_eval_frame(PyFrameObject *f) + * STACK_REFPLUS will probably be 1 in most cases. + * gets included into the saved stack area. + * 04-Oct-02 Gustavo Niemeyer + * Ported from MacOS version. + * 17-Sep-02 Christian Tismer + * after virtualizing stack save/restore, the + * stack size shrunk a bit. Needed to introduce + * an adjustment STACK_MAGIC per platform. + * 15-Sep-02 Gerd Woetzel + * slightly changed framework for sparc + * 29-Jun-02 Christian Tismer + * Added register 13-29, 31 saves. The same way as + * Armin Rigo did for the x86_unix version. + * This seems to be now fully functional! + * 04-Mar-02 Hye-Shik Chang + * Ported from i386. + * 31-Jul-12 Trevor Bowen + * Changed memory constraints to register only. + */ + +#define STACK_REFPLUS 1 + +#ifdef SLP_EVAL + +#define STACK_MAGIC 6 + +#if defined(__ALTIVEC__) +#define ALTIVEC_REGS \ + "v20", "v21", "v22", "v23", "v24", "v25", "v26", "v27", \ + "v28", "v29", "v30", "v31", +#else +#define ALTIVEC_REGS +#endif + +#define REGS_TO_SAVE "r14", "r15", "r16", "r17", "r18", "r19", "r20", \ + "r21", "r22", "r23", "r24", "r25", "r26", "r27", "r28", "r29", \ + "r31", \ + "fr14", "fr15", "fr16", "fr17", "fr18", "fr19", "fr20", "fr21", \ + "fr22", "fr23", "fr24", "fr25", "fr26", "fr27", "fr28", "fr29", \ + "fr30", "fr31", \ + ALTIVEC_REGS \ + "cr2", "cr3", "cr4" + +static int +slp_switch(void) +{ + int err; + long *stackref, stsizediff; + void * toc; + void * r30; + __asm__ volatile ("" : : : REGS_TO_SAVE); + __asm__ volatile ("std 2, %0" : "=m" (toc)); + __asm__ volatile ("std 30, %0" : "=m" (r30)); + __asm__ ("mr %0, 1" : "=r" (stackref) : ); + { + SLP_SAVE_STATE(stackref, stsizediff); + __asm__ volatile ( + "mr 11, %0\n" + "add 1, 1, 11\n" + : /* no outputs */ + : "r" (stsizediff) + : "11" + ); + SLP_RESTORE_STATE(); + } + __asm__ volatile ("ld 30, %0" : : "m" (r30)); + __asm__ volatile ("ld 2, %0" : : "m" (toc)); + __asm__ volatile ("" : : : REGS_TO_SAVE); + __asm__ volatile ("li %0, 0" : "=r" (err)); + return err; +} + +#endif diff --git a/psets/9/finance/env/lib/python3.12/site-packages/greenlet/platform/switch_ppc64_linux.h b/psets/9/finance/env/lib/python3.12/site-packages/greenlet/platform/switch_ppc64_linux.h new file mode 100644 index 0000000..3c324d0 --- /dev/null +++ b/psets/9/finance/env/lib/python3.12/site-packages/greenlet/platform/switch_ppc64_linux.h @@ -0,0 +1,105 @@ +/* + * this is the internal transfer function. + * + * HISTORY + * 04-Sep-18 Alexey Borzenkov + * Workaround a gcc bug using manual save/restore of r30 + * 21-Mar-18 Tulio Magno Quites Machado Filho + * Added r30 to the list of saved registers in order to fully comply with + * both ppc64 ELFv1 ABI and the ppc64le ELFv2 ABI, that classify this + * register as a nonvolatile register used for local variables. + * 21-Mar-18 Laszlo Boszormenyi + * Save r2 (TOC pointer) manually. + * 10-Dec-13 Ulrich Weigand + * Support ELFv2 ABI. Save float/vector registers. + * 09-Mar-12 Michael Ellerman + * 64-bit implementation, copied from 32-bit. + * 07-Sep-05 (py-dev mailing list discussion) + * removed 'r31' from the register-saved. !!!! WARNING !!!! + * It means that this file can no longer be compiled statically! + * It is now only suitable as part of a dynamic library! + * 14-Jan-04 Bob Ippolito + * added cr2-cr4 to the registers to be saved. + * Open questions: Should we save FP registers? + * What about vector registers? + * Differences between darwin and unix? + * 24-Nov-02 Christian Tismer + * needed to add another magic constant to insure + * that f in slp_eval_frame(PyFrameObject *f) + * STACK_REFPLUS will probably be 1 in most cases. + * gets included into the saved stack area. + * 04-Oct-02 Gustavo Niemeyer + * Ported from MacOS version. + * 17-Sep-02 Christian Tismer + * after virtualizing stack save/restore, the + * stack size shrunk a bit. Needed to introduce + * an adjustment STACK_MAGIC per platform. + * 15-Sep-02 Gerd Woetzel + * slightly changed framework for sparc + * 29-Jun-02 Christian Tismer + * Added register 13-29, 31 saves. The same way as + * Armin Rigo did for the x86_unix version. + * This seems to be now fully functional! + * 04-Mar-02 Hye-Shik Chang + * Ported from i386. + * 31-Jul-12 Trevor Bowen + * Changed memory constraints to register only. + */ + +#define STACK_REFPLUS 1 + +#ifdef SLP_EVAL + +#if _CALL_ELF == 2 +#define STACK_MAGIC 4 +#else +#define STACK_MAGIC 6 +#endif + +#if defined(__ALTIVEC__) +#define ALTIVEC_REGS \ + "v20", "v21", "v22", "v23", "v24", "v25", "v26", "v27", \ + "v28", "v29", "v30", "v31", +#else +#define ALTIVEC_REGS +#endif + +#define REGS_TO_SAVE "r14", "r15", "r16", "r17", "r18", "r19", "r20", \ + "r21", "r22", "r23", "r24", "r25", "r26", "r27", "r28", "r29", \ + "r31", \ + "fr14", "fr15", "fr16", "fr17", "fr18", "fr19", "fr20", "fr21", \ + "fr22", "fr23", "fr24", "fr25", "fr26", "fr27", "fr28", "fr29", \ + "fr30", "fr31", \ + ALTIVEC_REGS \ + "cr2", "cr3", "cr4" + +static int +slp_switch(void) +{ + int err; + long *stackref, stsizediff; + void * toc; + void * r30; + __asm__ volatile ("" : : : REGS_TO_SAVE); + __asm__ volatile ("std 2, %0" : "=m" (toc)); + __asm__ volatile ("std 30, %0" : "=m" (r30)); + __asm__ ("mr %0, 1" : "=r" (stackref) : ); + { + SLP_SAVE_STATE(stackref, stsizediff); + __asm__ volatile ( + "mr 11, %0\n" + "add 1, 1, 11\n" + : /* no outputs */ + : "r" (stsizediff) + : "11" + ); + SLP_RESTORE_STATE(); + } + __asm__ volatile ("ld 30, %0" : : "m" (r30)); + __asm__ volatile ("ld 2, %0" : : "m" (toc)); + __asm__ volatile ("" : : : REGS_TO_SAVE); + __asm__ volatile ("li %0, 0" : "=r" (err)); + return err; +} + +#endif diff --git a/psets/9/finance/env/lib/python3.12/site-packages/greenlet/platform/switch_ppc_aix.h b/psets/9/finance/env/lib/python3.12/site-packages/greenlet/platform/switch_ppc_aix.h new file mode 100644 index 0000000..6d93c13 --- /dev/null +++ b/psets/9/finance/env/lib/python3.12/site-packages/greenlet/platform/switch_ppc_aix.h @@ -0,0 +1,87 @@ +/* + * this is the internal transfer function. + * + * HISTORY + * 07-Mar-11 Floris Bruynooghe + * Do not add stsizediff to general purpose + * register (GPR) 30 as this is a non-volatile and + * unused by the PowerOpen Environment, therefore + * this was modifying a user register instead of the + * frame pointer (which does not seem to exist). + * 07-Sep-05 (py-dev mailing list discussion) + * removed 'r31' from the register-saved. !!!! WARNING !!!! + * It means that this file can no longer be compiled statically! + * It is now only suitable as part of a dynamic library! + * 14-Jan-04 Bob Ippolito + * added cr2-cr4 to the registers to be saved. + * Open questions: Should we save FP registers? + * What about vector registers? + * Differences between darwin and unix? + * 24-Nov-02 Christian Tismer + * needed to add another magic constant to insure + * that f in slp_eval_frame(PyFrameObject *f) + * STACK_REFPLUS will probably be 1 in most cases. + * gets included into the saved stack area. + * 04-Oct-02 Gustavo Niemeyer + * Ported from MacOS version. + * 17-Sep-02 Christian Tismer + * after virtualizing stack save/restore, the + * stack size shrunk a bit. Needed to introduce + * an adjustment STACK_MAGIC per platform. + * 15-Sep-02 Gerd Woetzel + * slightly changed framework for sparc + * 29-Jun-02 Christian Tismer + * Added register 13-29, 31 saves. The same way as + * Armin Rigo did for the x86_unix version. + * This seems to be now fully functional! + * 04-Mar-02 Hye-Shik Chang + * Ported from i386. + */ + +#define STACK_REFPLUS 1 + +#ifdef SLP_EVAL + +#define STACK_MAGIC 3 + +/* !!!!WARNING!!!! need to add "r31" in the next line if this header file + * is meant to be compiled non-dynamically! + */ +#define REGS_TO_SAVE "r13", "r14", "r15", "r16", "r17", "r18", "r19", "r20", \ + "r21", "r22", "r23", "r24", "r25", "r26", "r27", "r28", "r29", \ + "cr2", "cr3", "cr4" +static int +slp_switch(void) +{ + int err; + int *stackref, stsizediff; + __asm__ volatile ("" : : : REGS_TO_SAVE); + __asm__ ("mr %0, 1" : "=r" (stackref) : ); + { + SLP_SAVE_STATE(stackref, stsizediff); + __asm__ volatile ( + "mr 11, %0\n" + "add 1, 1, 11\n" + : /* no outputs */ + : "r" (stsizediff) + : "11" + ); + SLP_RESTORE_STATE(); + } + __asm__ volatile ("" : : : REGS_TO_SAVE); + __asm__ volatile ("li %0, 0" : "=r" (err)); + return err; +} + +#endif + +/* + * further self-processing support + */ + +/* + * if you want to add self-inspection tools, place them + * here. See the x86_msvc for the necessary defines. + * These features are highly experimental und not + * essential yet. + */ diff --git a/psets/9/finance/env/lib/python3.12/site-packages/greenlet/platform/switch_ppc_linux.h b/psets/9/finance/env/lib/python3.12/site-packages/greenlet/platform/switch_ppc_linux.h new file mode 100644 index 0000000..e83ad70 --- /dev/null +++ b/psets/9/finance/env/lib/python3.12/site-packages/greenlet/platform/switch_ppc_linux.h @@ -0,0 +1,84 @@ +/* + * this is the internal transfer function. + * + * HISTORY + * 07-Sep-05 (py-dev mailing list discussion) + * removed 'r31' from the register-saved. !!!! WARNING !!!! + * It means that this file can no longer be compiled statically! + * It is now only suitable as part of a dynamic library! + * 14-Jan-04 Bob Ippolito + * added cr2-cr4 to the registers to be saved. + * Open questions: Should we save FP registers? + * What about vector registers? + * Differences between darwin and unix? + * 24-Nov-02 Christian Tismer + * needed to add another magic constant to insure + * that f in slp_eval_frame(PyFrameObject *f) + * STACK_REFPLUS will probably be 1 in most cases. + * gets included into the saved stack area. + * 04-Oct-02 Gustavo Niemeyer + * Ported from MacOS version. + * 17-Sep-02 Christian Tismer + * after virtualizing stack save/restore, the + * stack size shrunk a bit. Needed to introduce + * an adjustment STACK_MAGIC per platform. + * 15-Sep-02 Gerd Woetzel + * slightly changed framework for sparc + * 29-Jun-02 Christian Tismer + * Added register 13-29, 31 saves. The same way as + * Armin Rigo did for the x86_unix version. + * This seems to be now fully functional! + * 04-Mar-02 Hye-Shik Chang + * Ported from i386. + * 31-Jul-12 Trevor Bowen + * Changed memory constraints to register only. + */ + +#define STACK_REFPLUS 1 + +#ifdef SLP_EVAL + +#define STACK_MAGIC 3 + +/* !!!!WARNING!!!! need to add "r31" in the next line if this header file + * is meant to be compiled non-dynamically! + */ +#define REGS_TO_SAVE "r13", "r14", "r15", "r16", "r17", "r18", "r19", "r20", \ + "r21", "r22", "r23", "r24", "r25", "r26", "r27", "r28", "r29", \ + "cr2", "cr3", "cr4" +static int +slp_switch(void) +{ + int err; + int *stackref, stsizediff; + __asm__ volatile ("" : : : REGS_TO_SAVE); + __asm__ ("mr %0, 1" : "=r" (stackref) : ); + { + SLP_SAVE_STATE(stackref, stsizediff); + __asm__ volatile ( + "mr 11, %0\n" + "add 1, 1, 11\n" + "add 30, 30, 11\n" + : /* no outputs */ + : "r" (stsizediff) + : "11" + ); + SLP_RESTORE_STATE(); + } + __asm__ volatile ("" : : : REGS_TO_SAVE); + __asm__ volatile ("li %0, 0" : "=r" (err)); + return err; +} + +#endif + +/* + * further self-processing support + */ + +/* + * if you want to add self-inspection tools, place them + * here. See the x86_msvc for the necessary defines. + * These features are highly experimental und not + * essential yet. + */ diff --git a/psets/9/finance/env/lib/python3.12/site-packages/greenlet/platform/switch_ppc_macosx.h b/psets/9/finance/env/lib/python3.12/site-packages/greenlet/platform/switch_ppc_macosx.h new file mode 100644 index 0000000..bd414c6 --- /dev/null +++ b/psets/9/finance/env/lib/python3.12/site-packages/greenlet/platform/switch_ppc_macosx.h @@ -0,0 +1,82 @@ +/* + * this is the internal transfer function. + * + * HISTORY + * 07-Sep-05 (py-dev mailing list discussion) + * removed 'r31' from the register-saved. !!!! WARNING !!!! + * It means that this file can no longer be compiled statically! + * It is now only suitable as part of a dynamic library! + * 14-Jan-04 Bob Ippolito + * added cr2-cr4 to the registers to be saved. + * Open questions: Should we save FP registers? + * What about vector registers? + * Differences between darwin and unix? + * 24-Nov-02 Christian Tismer + * needed to add another magic constant to insure + * that f in slp_eval_frame(PyFrameObject *f) + * STACK_REFPLUS will probably be 1 in most cases. + * gets included into the saved stack area. + * 17-Sep-02 Christian Tismer + * after virtualizing stack save/restore, the + * stack size shrunk a bit. Needed to introduce + * an adjustment STACK_MAGIC per platform. + * 15-Sep-02 Gerd Woetzel + * slightly changed framework for sparc + * 29-Jun-02 Christian Tismer + * Added register 13-29, 31 saves. The same way as + * Armin Rigo did for the x86_unix version. + * This seems to be now fully functional! + * 04-Mar-02 Hye-Shik Chang + * Ported from i386. + */ + +#define STACK_REFPLUS 1 + +#ifdef SLP_EVAL + +#define STACK_MAGIC 3 + +/* !!!!WARNING!!!! need to add "r31" in the next line if this header file + * is meant to be compiled non-dynamically! + */ +#define REGS_TO_SAVE "r13", "r14", "r15", "r16", "r17", "r18", "r19", "r20", \ + "r21", "r22", "r23", "r24", "r25", "r26", "r27", "r28", "r29", \ + "cr2", "cr3", "cr4" + +static int +slp_switch(void) +{ + int err; + int *stackref, stsizediff; + __asm__ volatile ("" : : : REGS_TO_SAVE); + __asm__ ("; asm block 2\n\tmr %0, r1" : "=r" (stackref) : ); + { + SLP_SAVE_STATE(stackref, stsizediff); + __asm__ volatile ( + "; asm block 3\n" + "\tmr r11, %0\n" + "\tadd r1, r1, r11\n" + "\tadd r30, r30, r11\n" + : /* no outputs */ + : "r" (stsizediff) + : "r11" + ); + SLP_RESTORE_STATE(); + } + __asm__ volatile ("" : : : REGS_TO_SAVE); + __asm__ volatile ("li %0, 0" : "=r" (err)); + return err; +} + +#endif + +/* + * further self-processing support + */ + +/* + * if you want to add self-inspection tools, place them + * here. See the x86_msvc for the necessary defines. + * These features are highly experimental und not + * essential yet. + */ diff --git a/psets/9/finance/env/lib/python3.12/site-packages/greenlet/platform/switch_ppc_unix.h b/psets/9/finance/env/lib/python3.12/site-packages/greenlet/platform/switch_ppc_unix.h new file mode 100644 index 0000000..bb18808 --- /dev/null +++ b/psets/9/finance/env/lib/python3.12/site-packages/greenlet/platform/switch_ppc_unix.h @@ -0,0 +1,82 @@ +/* + * this is the internal transfer function. + * + * HISTORY + * 07-Sep-05 (py-dev mailing list discussion) + * removed 'r31' from the register-saved. !!!! WARNING !!!! + * It means that this file can no longer be compiled statically! + * It is now only suitable as part of a dynamic library! + * 14-Jan-04 Bob Ippolito + * added cr2-cr4 to the registers to be saved. + * Open questions: Should we save FP registers? + * What about vector registers? + * Differences between darwin and unix? + * 24-Nov-02 Christian Tismer + * needed to add another magic constant to insure + * that f in slp_eval_frame(PyFrameObject *f) + * STACK_REFPLUS will probably be 1 in most cases. + * gets included into the saved stack area. + * 04-Oct-02 Gustavo Niemeyer + * Ported from MacOS version. + * 17-Sep-02 Christian Tismer + * after virtualizing stack save/restore, the + * stack size shrunk a bit. Needed to introduce + * an adjustment STACK_MAGIC per platform. + * 15-Sep-02 Gerd Woetzel + * slightly changed framework for sparc + * 29-Jun-02 Christian Tismer + * Added register 13-29, 31 saves. The same way as + * Armin Rigo did for the x86_unix version. + * This seems to be now fully functional! + * 04-Mar-02 Hye-Shik Chang + * Ported from i386. + */ + +#define STACK_REFPLUS 1 + +#ifdef SLP_EVAL + +#define STACK_MAGIC 3 + +/* !!!!WARNING!!!! need to add "r31" in the next line if this header file + * is meant to be compiled non-dynamically! + */ +#define REGS_TO_SAVE "r13", "r14", "r15", "r16", "r17", "r18", "r19", "r20", \ + "r21", "r22", "r23", "r24", "r25", "r26", "r27", "r28", "r29", \ + "cr2", "cr3", "cr4" +static int +slp_switch(void) +{ + int err; + int *stackref, stsizediff; + __asm__ volatile ("" : : : REGS_TO_SAVE); + __asm__ ("mr %0, 1" : "=r" (stackref) : ); + { + SLP_SAVE_STATE(stackref, stsizediff); + __asm__ volatile ( + "mr 11, %0\n" + "add 1, 1, 11\n" + "add 30, 30, 11\n" + : /* no outputs */ + : "r" (stsizediff) + : "11" + ); + SLP_RESTORE_STATE(); + } + __asm__ volatile ("" : : : REGS_TO_SAVE); + __asm__ volatile ("li %0, 0" : "=r" (err)); + return err; +} + +#endif + +/* + * further self-processing support + */ + +/* + * if you want to add self-inspection tools, place them + * here. See the x86_msvc for the necessary defines. + * These features are highly experimental und not + * essential yet. + */ diff --git a/psets/9/finance/env/lib/python3.12/site-packages/greenlet/platform/switch_riscv_unix.h b/psets/9/finance/env/lib/python3.12/site-packages/greenlet/platform/switch_riscv_unix.h new file mode 100644 index 0000000..e74f37a --- /dev/null +++ b/psets/9/finance/env/lib/python3.12/site-packages/greenlet/platform/switch_riscv_unix.h @@ -0,0 +1,36 @@ +#define STACK_REFPLUS 1 + +#ifdef SLP_EVAL +#define STACK_MAGIC 0 + +#define REGS_TO_SAVE "s1", "s2", "s3", "s4", "s5", \ + "s6", "s7", "s8", "s9", "s10", "s11", "fs0", "fs1", \ + "fs2", "fs3", "fs4", "fs5", "fs6", "fs7", "fs8", "fs9", \ + "fs10", "fs11" + +static int +slp_switch(void) +{ + long fp; + int ret; + long *stackref, stsizediff; + __asm__ volatile ("" : : : REGS_TO_SAVE); + __asm__ volatile ("mv %0, fp" : "=r" (fp) : ); + __asm__ volatile ("mv %0, sp" : "=r" (stackref) : ); + { + SLP_SAVE_STATE(stackref, stsizediff); + __asm__ volatile ( + "add sp, sp, %0\n\t" + "add fp, fp, %0\n\t" + : /* no outputs */ + : "r" (stsizediff) + ); + SLP_RESTORE_STATE(); + } + __asm__ volatile ("" : : : REGS_TO_SAVE); + __asm__ volatile ("ld fp, %0" : : "m" (fp)); + __asm__ volatile ("mv %0, zero" : "=r" (ret) : ); + return ret; +} + +#endif diff --git a/psets/9/finance/env/lib/python3.12/site-packages/greenlet/platform/switch_s390_unix.h b/psets/9/finance/env/lib/python3.12/site-packages/greenlet/platform/switch_s390_unix.h new file mode 100644 index 0000000..9199367 --- /dev/null +++ b/psets/9/finance/env/lib/python3.12/site-packages/greenlet/platform/switch_s390_unix.h @@ -0,0 +1,87 @@ +/* + * this is the internal transfer function. + * + * HISTORY + * 25-Jan-12 Alexey Borzenkov + * Fixed Linux/S390 port to work correctly with + * different optimization options both on 31-bit + * and 64-bit. Thanks to Stefan Raabe for lots + * of testing. + * 24-Nov-02 Christian Tismer + * needed to add another magic constant to insure + * that f in slp_eval_frame(PyFrameObject *f) + * STACK_REFPLUS will probably be 1 in most cases. + * gets included into the saved stack area. + * 06-Oct-02 Gustavo Niemeyer + * Ported to Linux/S390. + */ + +#define STACK_REFPLUS 1 + +#ifdef SLP_EVAL + +#ifdef __s390x__ +#define STACK_MAGIC 20 /* 20 * 8 = 160 bytes of function call area */ +#else +#define STACK_MAGIC 24 /* 24 * 4 = 96 bytes of function call area */ +#endif + +/* Technically, r11-r13 also need saving, but function prolog starts + with stm(g) and since there are so many saved registers already + it won't be optimized, resulting in all r6-r15 being saved */ +#define REGS_TO_SAVE "r6", "r7", "r8", "r9", "r10", "r14", \ + "f0", "f1", "f2", "f3", "f4", "f5", "f6", "f7", \ + "f8", "f9", "f10", "f11", "f12", "f13", "f14", "f15" + +static int +slp_switch(void) +{ + int ret; + long *stackref, stsizediff; + __asm__ volatile ("" : : : REGS_TO_SAVE); +#ifdef __s390x__ + __asm__ volatile ("lgr %0, 15" : "=r" (stackref) : ); +#else + __asm__ volatile ("lr %0, 15" : "=r" (stackref) : ); +#endif + { + SLP_SAVE_STATE(stackref, stsizediff); +/* N.B. + r11 may be used as the frame pointer, and in that case it cannot be + clobbered and needs offsetting just like the stack pointer (but in cases + where frame pointer isn't used we might clobber it accidentally). What's + scary is that r11 is 2nd (and even 1st when GOT is used) callee saved + register that gcc would chose for surviving function calls. However, + since r6-r10 are clobbered above, their cost for reuse is reduced, so + gcc IRA will chose them over r11 (not seeing r11 is implicitly saved), + making it relatively safe to offset in all cases. :) */ + __asm__ volatile ( +#ifdef __s390x__ + "agr 15, %0\n\t" + "agr 11, %0" +#else + "ar 15, %0\n\t" + "ar 11, %0" +#endif + : /* no outputs */ + : "r" (stsizediff) + ); + SLP_RESTORE_STATE(); + } + __asm__ volatile ("" : : : REGS_TO_SAVE); + __asm__ volatile ("lhi %0, 0" : "=r" (ret) : ); + return ret; +} + +#endif + +/* + * further self-processing support + */ + +/* + * if you want to add self-inspection tools, place them + * here. See the x86_msvc for the necessary defines. + * These features are highly experimental und not + * essential yet. + */ diff --git a/psets/9/finance/env/lib/python3.12/site-packages/greenlet/platform/switch_sh_gcc.h b/psets/9/finance/env/lib/python3.12/site-packages/greenlet/platform/switch_sh_gcc.h new file mode 100644 index 0000000..5ecc3b3 --- /dev/null +++ b/psets/9/finance/env/lib/python3.12/site-packages/greenlet/platform/switch_sh_gcc.h @@ -0,0 +1,36 @@ +#define STACK_REFPLUS 1 + +#ifdef SLP_EVAL +#define STACK_MAGIC 0 +#define REGS_TO_SAVE "r8", "r9", "r10", "r11", "r13", \ + "fr12", "fr13", "fr14", "fr15" + +// r12 Global context pointer, GP +// r14 Frame pointer, FP +// r15 Stack pointer, SP + +static int +slp_switch(void) +{ + int err; + void* fp; + int *stackref, stsizediff; + __asm__ volatile("" : : : REGS_TO_SAVE); + __asm__ volatile("mov.l r14, %0" : "=m"(fp) : :); + __asm__("mov r15, %0" : "=r"(stackref)); + { + SLP_SAVE_STATE(stackref, stsizediff); + __asm__ volatile( + "add %0, r15\n" + "add %0, r14\n" + : /* no outputs */ + : "r"(stsizediff)); + SLP_RESTORE_STATE(); + __asm__ volatile("mov r0, %0" : "=r"(err) : :); + } + __asm__ volatile("mov.l %0, r14" : : "m"(fp) :); + __asm__ volatile("" : : : REGS_TO_SAVE); + return err; +} + +#endif diff --git a/psets/9/finance/env/lib/python3.12/site-packages/greenlet/platform/switch_sparc_sun_gcc.h b/psets/9/finance/env/lib/python3.12/site-packages/greenlet/platform/switch_sparc_sun_gcc.h new file mode 100644 index 0000000..96990c3 --- /dev/null +++ b/psets/9/finance/env/lib/python3.12/site-packages/greenlet/platform/switch_sparc_sun_gcc.h @@ -0,0 +1,92 @@ +/* + * this is the internal transfer function. + * + * HISTORY + * 16-May-15 Alexey Borzenkov + * Move stack spilling code inside save/restore functions + * 30-Aug-13 Floris Bruynooghe + Clean the register windows again before returning. + This does not clobber the PIC register as it leaves + the current window intact and is required for multi- + threaded code to work correctly. + * 08-Mar-11 Floris Bruynooghe + * No need to set return value register explicitly + * before the stack and framepointer are adjusted + * as none of the other registers are influenced by + * this. Also don't needlessly clean the windows + * ('ta %0" :: "i" (ST_CLEAN_WINDOWS)') as that + * clobbers the gcc PIC register (%l7). + * 24-Nov-02 Christian Tismer + * needed to add another magic constant to insure + * that f in slp_eval_frame(PyFrameObject *f) + * STACK_REFPLUS will probably be 1 in most cases. + * gets included into the saved stack area. + * 17-Sep-02 Christian Tismer + * after virtualizing stack save/restore, the + * stack size shrunk a bit. Needed to introduce + * an adjustment STACK_MAGIC per platform. + * 15-Sep-02 Gerd Woetzel + * added support for SunOS sparc with gcc + */ + +#define STACK_REFPLUS 1 + +#ifdef SLP_EVAL + + +#define STACK_MAGIC 0 + + +#if defined(__sparcv9) +#define SLP_FLUSHW __asm__ volatile ("flushw") +#else +#define SLP_FLUSHW __asm__ volatile ("ta 3") /* ST_FLUSH_WINDOWS */ +#endif + +/* On sparc we need to spill register windows inside save/restore functions */ +#define SLP_BEFORE_SAVE_STATE() SLP_FLUSHW +#define SLP_BEFORE_RESTORE_STATE() SLP_FLUSHW + + +static int +slp_switch(void) +{ + int err; + int *stackref, stsizediff; + + /* Put current stack pointer into stackref. + * Register spilling is done in save/restore. + */ + __asm__ volatile ("mov %%sp, %0" : "=r" (stackref)); + + { + /* Thou shalt put SLP_SAVE_STATE into a local block */ + /* Copy the current stack onto the heap */ + SLP_SAVE_STATE(stackref, stsizediff); + + /* Increment stack and frame pointer by stsizediff */ + __asm__ volatile ( + "add %0, %%sp, %%sp\n\t" + "add %0, %%fp, %%fp" + : : "r" (stsizediff)); + + /* Copy new stack from it's save store on the heap */ + SLP_RESTORE_STATE(); + + __asm__ volatile ("mov %1, %0" : "=r" (err) : "i" (0)); + return err; + } +} + +#endif + +/* + * further self-processing support + */ + +/* + * if you want to add self-inspection tools, place them + * here. See the x86_msvc for the necessary defines. + * These features are highly experimental und not + * essential yet. + */ diff --git a/psets/9/finance/env/lib/python3.12/site-packages/greenlet/platform/switch_x32_unix.h b/psets/9/finance/env/lib/python3.12/site-packages/greenlet/platform/switch_x32_unix.h new file mode 100644 index 0000000..893369c --- /dev/null +++ b/psets/9/finance/env/lib/python3.12/site-packages/greenlet/platform/switch_x32_unix.h @@ -0,0 +1,63 @@ +/* + * this is the internal transfer function. + * + * HISTORY + * 17-Aug-12 Fantix King + * Ported from amd64. + */ + +#define STACK_REFPLUS 1 + +#ifdef SLP_EVAL + +#define STACK_MAGIC 0 + +#define REGS_TO_SAVE "r12", "r13", "r14", "r15" + + +static int +slp_switch(void) +{ + void* ebp; + void* ebx; + unsigned int csr; + unsigned short cw; + int err; + int *stackref, stsizediff; + __asm__ volatile ("" : : : REGS_TO_SAVE); + __asm__ volatile ("fstcw %0" : "=m" (cw)); + __asm__ volatile ("stmxcsr %0" : "=m" (csr)); + __asm__ volatile ("movl %%ebp, %0" : "=m" (ebp)); + __asm__ volatile ("movl %%ebx, %0" : "=m" (ebx)); + __asm__ ("movl %%esp, %0" : "=g" (stackref)); + { + SLP_SAVE_STATE(stackref, stsizediff); + __asm__ volatile ( + "addl %0, %%esp\n" + "addl %0, %%ebp\n" + : + : "r" (stsizediff) + ); + SLP_RESTORE_STATE(); + } + __asm__ volatile ("movl %0, %%ebx" : : "m" (ebx)); + __asm__ volatile ("movl %0, %%ebp" : : "m" (ebp)); + __asm__ volatile ("ldmxcsr %0" : : "m" (csr)); + __asm__ volatile ("fldcw %0" : : "m" (cw)); + __asm__ volatile ("" : : : REGS_TO_SAVE); + __asm__ volatile ("xorl %%eax, %%eax" : "=a" (err)); + return err; +} + +#endif + +/* + * further self-processing support + */ + +/* + * if you want to add self-inspection tools, place them + * here. See the x86_msvc for the necessary defines. + * These features are highly experimental und not + * essential yet. + */ diff --git a/psets/9/finance/env/lib/python3.12/site-packages/greenlet/platform/switch_x64_masm.asm b/psets/9/finance/env/lib/python3.12/site-packages/greenlet/platform/switch_x64_masm.asm new file mode 100644 index 0000000..f5c72a2 --- /dev/null +++ b/psets/9/finance/env/lib/python3.12/site-packages/greenlet/platform/switch_x64_masm.asm @@ -0,0 +1,111 @@ +; +; stack switching code for MASM on x641 +; Kristjan Valur Jonsson, sept 2005 +; + + +;prototypes for our calls +slp_save_state_asm PROTO +slp_restore_state_asm PROTO + + +pushxmm MACRO reg + sub rsp, 16 + .allocstack 16 + movaps [rsp], reg ; faster than movups, but we must be aligned + ; .savexmm128 reg, offset (don't know what offset is, no documentation) +ENDM +popxmm MACRO reg + movaps reg, [rsp] ; faster than movups, but we must be aligned + add rsp, 16 +ENDM + +pushreg MACRO reg + push reg + .pushreg reg +ENDM +popreg MACRO reg + pop reg +ENDM + + +.code +slp_switch PROC FRAME + ;realign stack to 16 bytes after return address push, makes the following faster + sub rsp,8 + .allocstack 8 + + pushxmm xmm15 + pushxmm xmm14 + pushxmm xmm13 + pushxmm xmm12 + pushxmm xmm11 + pushxmm xmm10 + pushxmm xmm9 + pushxmm xmm8 + pushxmm xmm7 + pushxmm xmm6 + + pushreg r15 + pushreg r14 + pushreg r13 + pushreg r12 + + pushreg rbp + pushreg rbx + pushreg rdi + pushreg rsi + + sub rsp, 10h ;allocate the singlefunction argument (must be multiple of 16) + .allocstack 10h +.endprolog + + lea rcx, [rsp+10h] ;load stack base that we are saving + call slp_save_state_asm ;pass stackpointer, return offset in eax + cmp rax, 1 + je EXIT1 + cmp rax, -1 + je EXIT2 + ;actual stack switch: + add rsp, rax + call slp_restore_state_asm + xor rax, rax ;return 0 + +EXIT: + + add rsp, 10h + popreg rsi + popreg rdi + popreg rbx + popreg rbp + + popreg r12 + popreg r13 + popreg r14 + popreg r15 + + popxmm xmm6 + popxmm xmm7 + popxmm xmm8 + popxmm xmm9 + popxmm xmm10 + popxmm xmm11 + popxmm xmm12 + popxmm xmm13 + popxmm xmm14 + popxmm xmm15 + + add rsp, 8 + ret + +EXIT1: + mov rax, 1 + jmp EXIT + +EXIT2: + sar rax, 1 + jmp EXIT + +slp_switch ENDP + +END \ No newline at end of file diff --git a/psets/9/finance/env/lib/python3.12/site-packages/greenlet/platform/switch_x64_masm.obj b/psets/9/finance/env/lib/python3.12/site-packages/greenlet/platform/switch_x64_masm.obj new file mode 100644 index 0000000000000000000000000000000000000000..64e3e6b898ec765d4e37075f7b1635ad24c9efa2 GIT binary patch literal 1078 zcmZ{j&ubG=5XWb`DJB@*%~BA=L%=;Gk}d_~52VO$4J4q2U~MY6&1RFl{E&?scGnt@ zn(9GNy!ihFEO@PV4?T&H9`x2*oO!!jlNJZwd!P4xlX&_;U$Bg3z>p zje>}2kp+MsxE|w5hOUr>YC~(=fz6fwPdZd5+Hlb^P3{;ZO@Yuv96GG&+Gx?QfclNd zhy2KN&~>fNnlHQRR;U1cMyQ?hlQ$~k<0KBbB<0uD2#PTjVo+na7Q;#m=@=3m;xJOa zs2V#)&Db`cY;WzTF9)11;SjkVQWE!?bPTC%x3h3^F2;aBns5!i%m4&-*h69;~AUpZR%rDpm!zuXY+kc zFCz-n*^4&c)5~}y3e?r-Evy*n*(lp9r%ti58Y#l5&)rDjx5EbRd}nC+_8znRzz&#& XZ_Fi+`GM=5Rl{n4%KxAK>jC@)Nz=zi literal 0 HcmV?d00001 diff --git a/psets/9/finance/env/lib/python3.12/site-packages/greenlet/platform/switch_x64_msvc.h b/psets/9/finance/env/lib/python3.12/site-packages/greenlet/platform/switch_x64_msvc.h new file mode 100644 index 0000000..601ea56 --- /dev/null +++ b/psets/9/finance/env/lib/python3.12/site-packages/greenlet/platform/switch_x64_msvc.h @@ -0,0 +1,60 @@ +/* + * this is the internal transfer function. + * + * HISTORY + * 24-Nov-02 Christian Tismer + * needed to add another magic constant to insure + * that f in slp_eval_frame(PyFrameObject *f) + * STACK_REFPLUS will probably be 1 in most cases. + * gets included into the saved stack area. + * 26-Sep-02 Christian Tismer + * again as a result of virtualized stack access, + * the compiler used less registers. Needed to + * explicit mention registers in order to get them saved. + * Thanks to Jeff Senn for pointing this out and help. + * 17-Sep-02 Christian Tismer + * after virtualizing stack save/restore, the + * stack size shrunk a bit. Needed to introduce + * an adjustment STACK_MAGIC per platform. + * 15-Sep-02 Gerd Woetzel + * slightly changed framework for sparc + * 01-Mar-02 Christian Tismer + * Initial final version after lots of iterations for i386. + */ + +/* Avoid alloca redefined warning on mingw64 */ +#ifndef alloca +#define alloca _alloca +#endif + +#define STACK_REFPLUS 1 +#define STACK_MAGIC 0 + +/* Use the generic support for an external assembly language slp_switch function. */ +#define EXTERNAL_ASM + +#ifdef SLP_EVAL +/* This always uses the external masm assembly file. */ +#endif + +/* + * further self-processing support + */ + +/* we have IsBadReadPtr available, so we can peek at objects */ +/* +#define STACKLESS_SPY + +#ifdef IMPLEMENT_STACKLESSMODULE +#include "Windows.h" +#define CANNOT_READ_MEM(p, bytes) IsBadReadPtr(p, bytes) + +static int IS_ON_STACK(void*p) +{ + int stackref; + intptr_t stackbase = ((intptr_t)&stackref) & 0xfffff000; + return (intptr_t)p >= stackbase && (intptr_t)p < stackbase + 0x00100000; +} + +#endif +*/ \ No newline at end of file diff --git a/psets/9/finance/env/lib/python3.12/site-packages/greenlet/platform/switch_x86_msvc.h b/psets/9/finance/env/lib/python3.12/site-packages/greenlet/platform/switch_x86_msvc.h new file mode 100644 index 0000000..0f3a59f --- /dev/null +++ b/psets/9/finance/env/lib/python3.12/site-packages/greenlet/platform/switch_x86_msvc.h @@ -0,0 +1,326 @@ +/* + * this is the internal transfer function. + * + * HISTORY + * 24-Nov-02 Christian Tismer + * needed to add another magic constant to insure + * that f in slp_eval_frame(PyFrameObject *f) + * STACK_REFPLUS will probably be 1 in most cases. + * gets included into the saved stack area. + * 26-Sep-02 Christian Tismer + * again as a result of virtualized stack access, + * the compiler used less registers. Needed to + * explicit mention registers in order to get them saved. + * Thanks to Jeff Senn for pointing this out and help. + * 17-Sep-02 Christian Tismer + * after virtualizing stack save/restore, the + * stack size shrunk a bit. Needed to introduce + * an adjustment STACK_MAGIC per platform. + * 15-Sep-02 Gerd Woetzel + * slightly changed framework for sparc + * 01-Mar-02 Christian Tismer + * Initial final version after lots of iterations for i386. + */ + +#define alloca _alloca + +#define STACK_REFPLUS 1 + +#ifdef SLP_EVAL + +#define STACK_MAGIC 0 + +/* Some magic to quell warnings and keep slp_switch() from crashing when built + with VC90. Disable global optimizations, and the warning: frame pointer + register 'ebp' modified by inline assembly code. + + We used to just disable global optimizations ("g") but upstream stackless + Python, as well as stackman, turn off all optimizations. + +References: +https://github.com/stackless-dev/stackman/blob/dbc72fe5207a2055e658c819fdeab9731dee78b9/stackman/platforms/switch_x86_msvc.h +https://github.com/stackless-dev/stackless/blob/main-slp/Stackless/platf/switch_x86_msvc.h +*/ +#define WIN32_LEAN_AND_MEAN +#include + +#pragma optimize("", off) /* so that autos are stored on the stack */ +#pragma warning(disable:4731) +#pragma warning(disable:4733) /* disable warning about modifying FS[0] */ + +/** + * Most modern compilers and environments handle C++ exceptions without any + * special help from us. MSVC on 32-bit windows is an exception. There, C++ + * exceptions are dealt with using Windows' Structured Exception Handling + * (SEH). + * + * SEH is implemented as a singly linked list of nodes. The + * head of this list is stored in the Thread Information Block, which itself + * is pointed to from the FS register. It's the first field in the structure, + * or offset 0, so we can access it using assembly FS:[0], or the compiler + * intrinsics and field offset information from the headers (as we do below). + * Somewhat unusually, the tail of the list doesn't have prev == NULL, it has + * prev == 0xFFFFFFFF. + * + * SEH was designed for C, and traditionally uses the MSVC compiler + * intrinsincs __try{}/__except{}. It is also utilized for C++ exceptions by + * MSVC; there, every throw of a C++ exception raises a SEH error with the + * ExceptionCode 0xE06D7363; the SEH handler list is then traversed to + * deal with the exception. + * + * If the SEH list is corrupt, then when a C++ exception is thrown the program + * will abruptly exit with exit code 1. This does not use std::terminate(), so + * std::set_terminate() is useless to debug this. + * + * The SEH list is closely tied to the call stack; entering a function that + * uses __try{} or most C++ functions will push a new handler onto the front + * of the list. Returning from the function will remove the handler. Saving + * and restoring the head node of the SEH list (FS:[0]) per-greenlet is NOT + * ENOUGH to make SEH or exceptions work. + * + * Stack switching breaks SEH because the call stack no longer necessarily + * matches the SEH list. For example, given greenlet A that switches to + * greenlet B, at the moment of entering greenlet B, we will have any SEH + * handlers from greenlet A on the SEH list; greenlet B can then add its own + * handlers to the SEH list. When greenlet B switches back to greenlet A, + * greenlet B's handlers would still be on the SEH stack, but when switch() + * returns control to greenlet A, we have replaced the contents of the stack + * in memory, so all the address that greenlet B added to the SEH list are now + * invalid: part of the call stack has been unwound, but the SEH list was out + * of sync with the call stack. The net effect is that exception handling + * stops working. + * + * Thus, when switching greenlets, we need to be sure that the SEH list + * matches the effective call stack, "cutting out" any handlers that were + * pushed by the greenlet that switched out and which are no longer valid. + * + * The easiest way to do this is to capture the SEH list at the time the main + * greenlet for a thread is created, and, when initially starting a greenlet, + * start a new SEH list for it, which contains nothing but the handler + * established for the new greenlet itself, with the tail being the handlers + * for the main greenlet. If we then save and restore the SEH per-greenlet, + * they won't interfere with each others SEH lists. (No greenlet can unwind + * the call stack past the handlers established by the main greenlet). + * + * By observation, a new thread starts with three SEH handlers on the list. By + * the time we get around to creating the main greenlet, though, there can be + * many more, established by transient calls that lead to the creation of the + * main greenlet. Therefore, 3 is a magic constant telling us when to perform + * the initial slice. + * + * All of this can be debugged using a vectored exception handler, which + * operates independently of the SEH handler list, and is called first. + * Walking the SEH list at key points can also be helpful. + * + * References: + * https://en.wikipedia.org/wiki/Win32_Thread_Information_Block + * https://devblogs.microsoft.com/oldnewthing/20100730-00/?p=13273 + * https://docs.microsoft.com/en-us/cpp/cpp/try-except-statement?view=msvc-160 + * https://docs.microsoft.com/en-us/cpp/cpp/structured-exception-handling-c-cpp?view=msvc-160 + * https://docs.microsoft.com/en-us/windows/win32/debug/structured-exception-handling + * https://docs.microsoft.com/en-us/windows/win32/debug/using-a-vectored-exception-handler + * https://bytepointer.com/resources/pietrek_crash_course_depths_of_win32_seh.htm + */ +#define GREENLET_NEEDS_EXCEPTION_STATE_SAVED + + +typedef struct _GExceptionRegistration { + struct _GExceptionRegistration* prev; + void* handler_f; +} GExceptionRegistration; + +static void +slp_set_exception_state(const void *const seh_state) +{ + // Because the stack from from which we do this is ALSO a handler, and + // that one we want to keep, we need to relink the current SEH handler + // frame to point to this one, cutting out the middle men, as it were. + // + // Entering a try block doesn't change the SEH frame, but entering a + // function containing a try block does. + GExceptionRegistration* current_seh_state = (GExceptionRegistration*)__readfsdword(FIELD_OFFSET(NT_TIB, ExceptionList)); + current_seh_state->prev = (GExceptionRegistration*)seh_state; +} + + +static GExceptionRegistration* +x86_slp_get_third_oldest_handler() +{ + GExceptionRegistration* a = NULL; /* Closest to the top */ + GExceptionRegistration* b = NULL; /* second */ + GExceptionRegistration* c = NULL; + GExceptionRegistration* seh_state = (GExceptionRegistration*)__readfsdword(FIELD_OFFSET(NT_TIB, ExceptionList)); + a = b = c = seh_state; + + while (seh_state && seh_state != (GExceptionRegistration*)0xFFFFFFFF) { + if ((void*)seh_state->prev < (void*)100) { + fprintf(stderr, "\tERROR: Broken SEH chain.\n"); + return NULL; + } + a = b; + b = c; + c = seh_state; + + seh_state = seh_state->prev; + } + return a ? a : (b ? b : c); +} + + +static void* +slp_get_exception_state() +{ + // XXX: There appear to be three SEH handlers on the stack already at the + // start of the thread. Is that a guarantee? Almost certainly not. Yet in + // all observed cases it has been three. This is consistent with + // faulthandler off or on, and optimizations off or on. It may not be + // consistent with other operating system versions, though: we only have + // CI on one or two versions (don't ask what there are). + // In theory we could capture the number of handlers on the chain when + // PyInit__greenlet is called: there are probably only the default + // handlers at that point (unless we're embedded and people have used + // __try/__except or a C++ handler)? + return x86_slp_get_third_oldest_handler(); +} + +static int +slp_switch(void) +{ + /* MASM syntax is typically reversed from other assemblers. + It is usually + */ + int *stackref, stsizediff; + /* store the structured exception state for this stack */ + DWORD seh_state = __readfsdword(FIELD_OFFSET(NT_TIB, ExceptionList)); + __asm mov stackref, esp; + /* modify EBX, ESI and EDI in order to get them preserved */ + __asm mov ebx, ebx; + __asm xchg esi, edi; + { + SLP_SAVE_STATE(stackref, stsizediff); + __asm { + mov eax, stsizediff + add esp, eax + add ebp, eax + } + SLP_RESTORE_STATE(); + } + __writefsdword(FIELD_OFFSET(NT_TIB, ExceptionList), seh_state); + return 0; +} + +/* re-enable ebp warning and global optimizations. */ +#pragma optimize("", on) +#pragma warning(default:4731) +#pragma warning(default:4733) /* disable warning about modifying FS[0] */ + + +#endif + +/* + * further self-processing support + */ + +/* we have IsBadReadPtr available, so we can peek at objects */ +#define STACKLESS_SPY + +#ifdef GREENLET_DEBUG + +#define CANNOT_READ_MEM(p, bytes) IsBadReadPtr(p, bytes) + +static int IS_ON_STACK(void*p) +{ + int stackref; + int stackbase = ((int)&stackref) & 0xfffff000; + return (int)p >= stackbase && (int)p < stackbase + 0x00100000; +} + +static void +x86_slp_show_seh_chain() +{ + GExceptionRegistration* seh_state = (GExceptionRegistration*)__readfsdword(FIELD_OFFSET(NT_TIB, ExceptionList)); + fprintf(stderr, "====== SEH Chain ======\n"); + while (seh_state && seh_state != (GExceptionRegistration*)0xFFFFFFFF) { + fprintf(stderr, "\tSEH_chain addr: %p handler: %p prev: %p\n", + seh_state, + seh_state->handler_f, seh_state->prev); + if ((void*)seh_state->prev < (void*)100) { + fprintf(stderr, "\tERROR: Broken chain.\n"); + break; + } + seh_state = seh_state->prev; + } + fprintf(stderr, "====== End SEH Chain ======\n"); + fflush(NULL); + return; +} + +//addVectoredExceptionHandler constants: +//CALL_FIRST means call this exception handler first; +//CALL_LAST means call this exception handler last +#define CALL_FIRST 1 +#define CALL_LAST 0 + +LONG WINAPI +GreenletVectorHandler(PEXCEPTION_POINTERS ExceptionInfo) +{ + // We get one of these for every C++ exception, with code + // E06D7363 + // This is a special value that means "C++ exception from MSVC" + // https://devblogs.microsoft.com/oldnewthing/20100730-00/?p=13273 + // + // Install in the module init function with: + // AddVectoredExceptionHandler(CALL_FIRST, GreenletVectorHandler); + PEXCEPTION_RECORD ExceptionRecord = ExceptionInfo->ExceptionRecord; + + fprintf(stderr, + "GOT VECTORED EXCEPTION:\n" + "\tExceptionCode : %p\n" + "\tExceptionFlags : %p\n" + "\tExceptionAddr : %p\n" + "\tNumberparams : %ld\n", + ExceptionRecord->ExceptionCode, + ExceptionRecord->ExceptionFlags, + ExceptionRecord->ExceptionAddress, + ExceptionRecord->NumberParameters + ); + if (ExceptionRecord->ExceptionFlags & 1) { + fprintf(stderr, "\t\tEH_NONCONTINUABLE\n" ); + } + if (ExceptionRecord->ExceptionFlags & 2) { + fprintf(stderr, "\t\tEH_UNWINDING\n" ); + } + if (ExceptionRecord->ExceptionFlags & 4) { + fprintf(stderr, "\t\tEH_EXIT_UNWIND\n" ); + } + if (ExceptionRecord->ExceptionFlags & 8) { + fprintf(stderr, "\t\tEH_STACK_INVALID\n" ); + } + if (ExceptionRecord->ExceptionFlags & 0x10) { + fprintf(stderr, "\t\tEH_NESTED_CALL\n" ); + } + if (ExceptionRecord->ExceptionFlags & 0x20) { + fprintf(stderr, "\t\tEH_TARGET_UNWIND\n" ); + } + if (ExceptionRecord->ExceptionFlags & 0x40) { + fprintf(stderr, "\t\tEH_COLLIDED_UNWIND\n" ); + } + fprintf(stderr, "\n"); + fflush(NULL); + for(DWORD i = 0; i < ExceptionRecord->NumberParameters; i++) { + fprintf(stderr, "\t\t\tParam %ld: %lX\n", i, ExceptionRecord->ExceptionInformation[i]); + } + + if (ExceptionRecord->NumberParameters == 3) { + fprintf(stderr, "\tAbout to traverse SEH chain\n"); + // C++ Exception records have 3 params. + x86_slp_show_seh_chain(); + } + + return EXCEPTION_CONTINUE_SEARCH; +} + + + + +#endif diff --git a/psets/9/finance/env/lib/python3.12/site-packages/greenlet/platform/switch_x86_unix.h b/psets/9/finance/env/lib/python3.12/site-packages/greenlet/platform/switch_x86_unix.h new file mode 100644 index 0000000..493fa6b --- /dev/null +++ b/psets/9/finance/env/lib/python3.12/site-packages/greenlet/platform/switch_x86_unix.h @@ -0,0 +1,105 @@ +/* + * this is the internal transfer function. + * + * HISTORY + * 3-May-13 Ralf Schmitt + * Add support for strange GCC caller-save decisions + * (ported from switch_aarch64_gcc.h) + * 19-Aug-11 Alexey Borzenkov + * Correctly save ebp, ebx and cw + * 07-Sep-05 (py-dev mailing list discussion) + * removed 'ebx' from the register-saved. !!!! WARNING !!!! + * It means that this file can no longer be compiled statically! + * It is now only suitable as part of a dynamic library! + * 24-Nov-02 Christian Tismer + * needed to add another magic constant to insure + * that f in slp_eval_frame(PyFrameObject *f) + * STACK_REFPLUS will probably be 1 in most cases. + * gets included into the saved stack area. + * 17-Sep-02 Christian Tismer + * after virtualizing stack save/restore, the + * stack size shrunk a bit. Needed to introduce + * an adjustment STACK_MAGIC per platform. + * 15-Sep-02 Gerd Woetzel + * slightly changed framework for spark + * 31-Avr-02 Armin Rigo + * Added ebx, esi and edi register-saves. + * 01-Mar-02 Samual M. Rushing + * Ported from i386. + */ + +#define STACK_REFPLUS 1 + +#ifdef SLP_EVAL + +/* #define STACK_MAGIC 3 */ +/* the above works fine with gcc 2.96, but 2.95.3 wants this */ +#define STACK_MAGIC 0 + +#if __GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 5) +# define ATTR_NOCLONE __attribute__((noclone)) +#else +# define ATTR_NOCLONE +#endif + +static int +slp_switch(void) +{ + int err; +#ifdef _WIN32 + void *seh; +#endif + void *ebp, *ebx; + unsigned short cw; + int *stackref, stsizediff; + __asm__ volatile ("" : : : "esi", "edi"); + __asm__ volatile ("fstcw %0" : "=m" (cw)); + __asm__ volatile ("movl %%ebp, %0" : "=m" (ebp)); + __asm__ volatile ("movl %%ebx, %0" : "=m" (ebx)); +#ifdef _WIN32 + __asm__ volatile ( + "movl %%fs:0x0, %%eax\n" + "movl %%eax, %0\n" + : "=m" (seh) + : + : "eax"); +#endif + __asm__ ("movl %%esp, %0" : "=g" (stackref)); + { + SLP_SAVE_STATE(stackref, stsizediff); + __asm__ volatile ( + "addl %0, %%esp\n" + "addl %0, %%ebp\n" + : + : "r" (stsizediff) + ); + SLP_RESTORE_STATE(); + __asm__ volatile ("xorl %%eax, %%eax" : "=a" (err)); + } +#ifdef _WIN32 + __asm__ volatile ( + "movl %0, %%eax\n" + "movl %%eax, %%fs:0x0\n" + : + : "m" (seh) + : "eax"); +#endif + __asm__ volatile ("movl %0, %%ebx" : : "m" (ebx)); + __asm__ volatile ("movl %0, %%ebp" : : "m" (ebp)); + __asm__ volatile ("fldcw %0" : : "m" (cw)); + __asm__ volatile ("" : : : "esi", "edi"); + return err; +} + +#endif + +/* + * further self-processing support + */ + +/* + * if you want to add self-inspection tools, place them + * here. See the x86_msvc for the necessary defines. + * These features are highly experimental und not + * essential yet. + */ diff --git a/psets/9/finance/env/lib/python3.12/site-packages/greenlet/slp_platformselect.h b/psets/9/finance/env/lib/python3.12/site-packages/greenlet/slp_platformselect.h new file mode 100644 index 0000000..4945648 --- /dev/null +++ b/psets/9/finance/env/lib/python3.12/site-packages/greenlet/slp_platformselect.h @@ -0,0 +1,75 @@ +/* + * Platform Selection for Stackless Python + */ +#ifdef __cplusplus +extern "C" { +#endif + +#if defined(MS_WIN32) && !defined(MS_WIN64) && defined(_M_IX86) && defined(_MSC_VER) +# include "platform/switch_x86_msvc.h" /* MS Visual Studio on X86 */ +#elif defined(MS_WIN64) && defined(_M_X64) && defined(_MSC_VER) || defined(__MINGW64__) +# include "platform/switch_x64_msvc.h" /* MS Visual Studio on X64 */ +#elif defined(MS_WIN64) && defined(_M_ARM64) +# include "platform/switch_arm64_msvc.h" /* MS Visual Studio on ARM64 */ +#elif defined(__GNUC__) && defined(__amd64__) && defined(__ILP32__) +# include "platform/switch_x32_unix.h" /* gcc on amd64 with x32 ABI */ +#elif defined(__GNUC__) && defined(__amd64__) +# include "platform/switch_amd64_unix.h" /* gcc on amd64 */ +#elif defined(__GNUC__) && defined(__i386__) +# include "platform/switch_x86_unix.h" /* gcc on X86 */ +#elif defined(__GNUC__) && defined(__powerpc64__) && (defined(__linux__) || defined(__FreeBSD__)) +# include "platform/switch_ppc64_linux.h" /* gcc on PowerPC 64-bit */ +#elif defined(__GNUC__) && defined(__PPC__) && (defined(__linux__) || defined(__FreeBSD__)) +# include "platform/switch_ppc_linux.h" /* gcc on PowerPC */ +#elif defined(__GNUC__) && defined(__POWERPC__) && defined(__APPLE__) +# include "platform/switch_ppc_macosx.h" /* Apple MacOS X on 32-bit PowerPC */ +#elif defined(__GNUC__) && defined(__powerpc64__) && defined(_AIX) +# include "platform/switch_ppc64_aix.h" /* gcc on AIX/PowerPC 64-bit */ +#elif defined(__GNUC__) && defined(_ARCH_PPC) && defined(_AIX) +# include "platform/switch_ppc_aix.h" /* gcc on AIX/PowerPC */ +#elif defined(__GNUC__) && defined(__powerpc__) && defined(__NetBSD__) +#include "platform/switch_ppc_unix.h" /* gcc on NetBSD/powerpc */ +#elif defined(__GNUC__) && defined(sparc) +# include "platform/switch_sparc_sun_gcc.h" /* SunOS sparc with gcc */ +#elif defined(__SUNPRO_C) && defined(sparc) && defined(sun) +# iiclude "platform/switch_sparc_sun_gcc.h" /* SunStudio on amd64 */ +#elif defined(__SUNPRO_C) && defined(__amd64__) && defined(sun) +# include "platform/switch_amd64_unix.h" /* SunStudio on amd64 */ +#elif defined(__SUNPRO_C) && defined(__i386__) && defined(sun) +# include "platform/switch_x86_unix.h" /* SunStudio on x86 */ +#elif defined(__GNUC__) && defined(__s390__) && defined(__linux__) +# include "platform/switch_s390_unix.h" /* Linux/S390 */ +#elif defined(__GNUC__) && defined(__s390x__) && defined(__linux__) +# include "platform/switch_s390_unix.h" /* Linux/S390 zSeries (64-bit) */ +#elif defined(__GNUC__) && defined(__arm__) +# ifdef __APPLE__ +# include +# endif +# if TARGET_OS_IPHONE +# include "platform/switch_arm32_ios.h" /* iPhone OS on arm32 */ +# else +# include "platform/switch_arm32_gcc.h" /* gcc using arm32 */ +# endif +#elif defined(__GNUC__) && defined(__mips__) && defined(__linux__) +# include "platform/switch_mips_unix.h" /* Linux/MIPS */ +#elif defined(__GNUC__) && defined(__aarch64__) +# include "platform/switch_aarch64_gcc.h" /* Aarch64 ABI */ +#elif defined(__GNUC__) && defined(__mc68000__) +# include "platform/switch_m68k_gcc.h" /* gcc on m68k */ +#elif defined(__GNUC__) && defined(__csky__) +#include "platform/switch_csky_gcc.h" /* gcc on csky */ +# elif defined(__GNUC__) && defined(__riscv) +# include "platform/switch_riscv_unix.h" /* gcc on RISC-V */ +#elif defined(__GNUC__) && defined(__alpha__) +# include "platform/switch_alpha_unix.h" /* gcc on DEC Alpha */ +#elif defined(MS_WIN32) && defined(__llvm__) && defined(__aarch64__) +# include "platform/switch_aarch64_gcc.h" /* LLVM Aarch64 ABI for Windows */ +#elif defined(__GNUC__) && defined(__loongarch64) && defined(__linux__) +# include "platform/switch_loongarch64_linux.h" /* LoongArch64 */ +#elif defined(__GNUC__) && defined(__sh__) +# include "platform/switch_sh_gcc.h" /* SuperH */ +#endif + +#ifdef __cplusplus +}; +#endif diff --git a/psets/9/finance/env/lib/python3.12/site-packages/greenlet/tests/__init__.py b/psets/9/finance/env/lib/python3.12/site-packages/greenlet/tests/__init__.py new file mode 100644 index 0000000..e69392e --- /dev/null +++ b/psets/9/finance/env/lib/python3.12/site-packages/greenlet/tests/__init__.py @@ -0,0 +1,240 @@ +# -*- coding: utf-8 -*- +""" +Tests for greenlet. + +""" +import os +import sys +import unittest + +from gc import collect +from gc import get_objects +from threading import active_count as active_thread_count +from time import sleep +from time import time + +import psutil + +from greenlet import greenlet as RawGreenlet +from greenlet import getcurrent + +from greenlet._greenlet import get_pending_cleanup_count +from greenlet._greenlet import get_total_main_greenlets + +from . import leakcheck + +PY312 = sys.version_info[:2] >= (3, 12) +PY313 = sys.version_info[:2] >= (3, 13) + +WIN = sys.platform.startswith("win") +RUNNING_ON_GITHUB_ACTIONS = os.environ.get('GITHUB_ACTIONS') +RUNNING_ON_TRAVIS = os.environ.get('TRAVIS') or RUNNING_ON_GITHUB_ACTIONS +RUNNING_ON_APPVEYOR = os.environ.get('APPVEYOR') +RUNNING_ON_CI = RUNNING_ON_TRAVIS or RUNNING_ON_APPVEYOR +RUNNING_ON_MANYLINUX = os.environ.get('GREENLET_MANYLINUX') + +class TestCaseMetaClass(type): + # wrap each test method with + # a) leak checks + def __new__(cls, classname, bases, classDict): + # pylint and pep8 fight over what this should be called (mcs or cls). + # pylint gets it right, but we can't scope disable pep8, so we go with + # its convention. + # pylint: disable=bad-mcs-classmethod-argument + check_totalrefcount = True + + # Python 3: must copy, we mutate the classDict. Interestingly enough, + # it doesn't actually error out, but under 3.6 we wind up wrapping + # and re-wrapping the same items over and over and over. + for key, value in list(classDict.items()): + if key.startswith('test') and callable(value): + classDict.pop(key) + if check_totalrefcount: + value = leakcheck.wrap_refcount(value) + classDict[key] = value + return type.__new__(cls, classname, bases, classDict) + + +class TestCase(TestCaseMetaClass( + "NewBase", + (unittest.TestCase,), + {})): + + cleanup_attempt_sleep_duration = 0.001 + cleanup_max_sleep_seconds = 1 + + def wait_for_pending_cleanups(self, + initial_active_threads=None, + initial_main_greenlets=None): + initial_active_threads = initial_active_threads or self.threads_before_test + initial_main_greenlets = initial_main_greenlets or self.main_greenlets_before_test + sleep_time = self.cleanup_attempt_sleep_duration + # NOTE: This is racy! A Python-level thread object may be dead + # and gone, but the C thread may not yet have fired its + # destructors and added to the queue. There's no particular + # way to know that's about to happen. We try to watch the + # Python threads to make sure they, at least, have gone away. + # Counting the main greenlets, which we can easily do deterministically, + # also helps. + + # Always sleep at least once to let other threads run + sleep(sleep_time) + quit_after = time() + self.cleanup_max_sleep_seconds + # TODO: We could add an API that calls us back when a particular main greenlet is deleted? + # It would have to drop the GIL + while ( + get_pending_cleanup_count() + or active_thread_count() > initial_active_threads + or (not self.expect_greenlet_leak + and get_total_main_greenlets() > initial_main_greenlets)): + sleep(sleep_time) + if time() > quit_after: + print("Time limit exceeded.") + print("Threads: Waiting for only", initial_active_threads, + "-->", active_thread_count()) + print("MGlets : Waiting for only", initial_main_greenlets, + "-->", get_total_main_greenlets()) + break + collect() + + def count_objects(self, kind=list, exact_kind=True): + # pylint:disable=unidiomatic-typecheck + # Collect the garbage. + for _ in range(3): + collect() + if exact_kind: + return sum( + 1 + for x in get_objects() + if type(x) is kind + ) + # instances + return sum( + 1 + for x in get_objects() + if isinstance(x, kind) + ) + + greenlets_before_test = 0 + threads_before_test = 0 + main_greenlets_before_test = 0 + expect_greenlet_leak = False + + def count_greenlets(self): + """ + Find all the greenlets and subclasses tracked by the GC. + """ + return self.count_objects(RawGreenlet, False) + + def setUp(self): + # Ensure the main greenlet exists, otherwise the first test + # gets a false positive leak + super().setUp() + getcurrent() + self.threads_before_test = active_thread_count() + self.main_greenlets_before_test = get_total_main_greenlets() + self.wait_for_pending_cleanups(self.threads_before_test, self.main_greenlets_before_test) + self.greenlets_before_test = self.count_greenlets() + + def tearDown(self): + if getattr(self, 'skipTearDown', False): + return + + self.wait_for_pending_cleanups(self.threads_before_test, self.main_greenlets_before_test) + super().tearDown() + + def get_expected_returncodes_for_aborted_process(self): + import signal + # The child should be aborted in an unusual way. On POSIX + # platforms, this is done with abort() and signal.SIGABRT, + # which is reflected in a negative return value; however, on + # Windows, even though we observe the child print "Fatal + # Python error: Aborted" and in older versions of the C + # runtime "This application has requested the Runtime to + # terminate it in an unusual way," it always has an exit code + # of 3. This is interesting because 3 is the error code for + # ERROR_PATH_NOT_FOUND; BUT: the C runtime abort() function + # also uses this code. + # + # If we link to the static C library on Windows, the error + # code changes to '0xc0000409' (hex(3221226505)), which + # apparently is STATUS_STACK_BUFFER_OVERRUN; but "What this + # means is that nowadays when you get a + # STATUS_STACK_BUFFER_OVERRUN, it doesn’t actually mean that + # there is a stack buffer overrun. It just means that the + # application decided to terminate itself with great haste." + # + # + # On windows, we've also seen '0xc0000005' (hex(3221225477)). + # That's "Access Violation" + # + # See + # https://devblogs.microsoft.com/oldnewthing/20110519-00/?p=10623 + # and + # https://docs.microsoft.com/en-us/previous-versions/k089yyh0(v=vs.140)?redirectedfrom=MSDN + # and + # https://devblogs.microsoft.com/oldnewthing/20190108-00/?p=100655 + expected_exit = ( + -signal.SIGABRT, + # But beginning on Python 3.11, the faulthandler + # that prints the C backtraces sometimes segfaults after + # reporting the exception but before printing the stack. + # This has only been seen on linux/gcc. + -signal.SIGSEGV, + ) if not WIN else ( + 3, + 0xc0000409, + 0xc0000005, + ) + return expected_exit + + def get_process_uss(self): + """ + Return the current process's USS in bytes. + + uss is available on Linux, macOS, Windows. Also known as + "Unique Set Size", this is the memory which is unique to a + process and which would be freed if the process was terminated + right now. + + If this is not supported by ``psutil``, this raises the + :exc:`unittest.SkipTest` exception. + """ + try: + return psutil.Process().memory_full_info().uss + except AttributeError as e: + raise unittest.SkipTest("uss not supported") from e + + def run_script(self, script_name, show_output=True): + import subprocess + script = os.path.join( + os.path.dirname(__file__), + script_name, + ) + + try: + return subprocess.check_output([sys.executable, script], + encoding='utf-8', + stderr=subprocess.STDOUT) + except subprocess.CalledProcessError as ex: + if show_output: + print('-----') + print('Failed to run script', script) + print('~~~~~') + print(ex.output) + print('------') + raise + + + def assertScriptRaises(self, script_name, exitcodes=None): + import subprocess + with self.assertRaises(subprocess.CalledProcessError) as exc: + output = self.run_script(script_name, show_output=False) + __traceback_info__ = output + # We're going to fail the assertion if we get here, at least + # preserve the output in the traceback. + + if exitcodes is None: + exitcodes = self.get_expected_returncodes_for_aborted_process() + self.assertIn(exc.exception.returncode, exitcodes) + return exc.exception diff --git a/psets/9/finance/env/lib/python3.12/site-packages/greenlet/tests/__pycache__/__init__.cpython-312.pyc b/psets/9/finance/env/lib/python3.12/site-packages/greenlet/tests/__pycache__/__init__.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..f1fc2bdacf99757e6e8d95fca6489248c08d569d GIT binary patch literal 9015 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 asadr&7A%c$=n`w)Fw<`PpAqgSsQQ0q5CA;@ literal 0 HcmV?d00001 diff --git a/psets/9/finance/env/lib/python3.12/site-packages/greenlet/tests/__pycache__/fail_clearing_run_switches.cpython-312.pyc b/psets/9/finance/env/lib/python3.12/site-packages/greenlet/tests/__pycache__/fail_clearing_run_switches.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..25fd183acb7d1cc464ccfa547543198c212552e2 GIT binary patch literal 2083 zcmb7FK~Eb;6rNe{dN*rhQ%FjI97a_Hc9pUXC{k0km8!NPsVX-LRBC-$*1Kb~X4!RT z$048`jDkey1#aY+V=MYYD)nLnh;+pvQcpcKlt`6&>YH5~JE&@vk^TH;=Djy>zVE&9 zF9QQQg7Nd(x3xcHgnko~?oc|)*#t&t7dfbm9PCIQE`uyf5~8@C?i%-g_d04>uA#Cb zp;_dlHjpFlNy$bz9j_^{mWBwO)t)~>d#R44>Zlv2tieeteAC^?dytP9Wr<4l;Y9D3 zUAwYQmHJ5kPNF*+)vHoB3Pun+>s+F`qyLoYo{iCe$L@G#snWd{MypbBz|tT&{Z5sv zP_k&r-g$2{BQGV`enhOg$1Qq9a?h+-g&nc@?M#JKD zvFekRSU?&cwOB953ati=k_xT4zVG@q9kPW>#7>M(iUdi}XatNmeV4BiuqJm``C?TSHlNb<-v!V@Ip9={waI~jGgtMz`JzDig{#Z;*%G2sxYrs+`6G}i{JELbLeX%*#2 z1sIzi52LizXi(pYPg(Sl-7AYZ#LpkH`XvZ>VLXKR-8P>S zB@(3o?4q4`#d zEqli&Vv#_PF3v-bDpju;E=KCT&*#4Wa(=Ej5chmwLw#%AR*P^g(t%>T$rz-@M0q5+ zi4u(QiIZXCk2Jy$63&$dgXi`_=8^Vc(mx-wYhWzihVTi97b%SKshr00Sq|aB=d#wq z&(yKjgJX4UUmZJ8ueRjpdbXwhCCj*Qia@-~rSZ&T?N}S#*G69=nEW|}@jIs)Qqt>7 zkCqSQ%PssuhuP-s_1llWfPhHd%&q6zgKt0mq@ABQM3bj!gwrj5$9lq#(6wg>Z))q> RhW;y3TJFxs5gLtg{0G@9#ee_+ literal 0 HcmV?d00001 diff --git a/psets/9/finance/env/lib/python3.12/site-packages/greenlet/tests/__pycache__/fail_cpp_exception.cpython-312.pyc b/psets/9/finance/env/lib/python3.12/site-packages/greenlet/tests/__pycache__/fail_cpp_exception.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..0eb09d93e966acbe9fd853b7d082ce413b445484 GIT binary patch literal 1618 zcma)6&1)M+6rb5$t#((kq{_ym4t5u}4N=o-YnL4Ifx)SZ9UBY)nyO@_JUx zjAGd&pq7NjP)MMM$@^_M;)g)1Ml99FthFcVn;1aBf?A z8=%xXfXqRFG^AF~^+W^P#zg>#jMS2WEu?wLm@jbeQdJpH>m89&9Xoy7e@!WaGS!LG za_$>`0an3RpKXDLyb88pA+__hv4DaaB4#-xCPS3@xMDiy$CoadsNtd-^FwU1brNow z&RR$qYE6&_hSw0Y$7u($LDe#yRjc1n^!kO@9HgE zM6ywXAxwDy+pX1ZnJhG2CkTqh3xR#P0HfhE^mfL}jvojMZr=y!QaX=m1m)b$jPKpr6LO@D8jB>(|ymVL?G!J{547>z^!g@^~;*uVV&% zv45GfYTSpx`v(-@azQ2nOElTbT<_&J-SU~cZadhsz0mftU73!~zorwH&&DC9%=;Fc zh_J5$YZEhT&fyiX+|c8hvs`-lL#sv+qt+Fx>|+PJ$U^wG75HmbZJVu!_@m;~v_*Y} zKBzhFhEqY*st|;5fS4tMQtNbainZ+s+B=tdf$Tb7=STzO{a3pfbI*s}ZL#9@Amp7u zXNvX^$4bTcHNkW3d|R7oX*18$Z?)6cTIp+l%93snol6T+r1gPBYBwhZiKMtFk}6YF zWZyK2_7fT>?V_E%6m1c`n1-JigP zV?~9zqdXYOJzUsbc=YM+Qd2*YbeK6z<@bj#e4`(vrkisw^8l(%|Ix^km7l@nAyDqC ze;o}2ZS)u7igC#KpH xi>-;pgY?n^*vaM|Hg+4k%5U1x-$z;Q=M~L!yifI64Sc7~syE({zt2HV{{h8ooe%&3 literal 0 HcmV?d00001 diff --git a/psets/9/finance/env/lib/python3.12/site-packages/greenlet/tests/__pycache__/fail_initialstub_already_started.cpython-312.pyc b/psets/9/finance/env/lib/python3.12/site-packages/greenlet/tests/__pycache__/fail_initialstub_already_started.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..2ed840b87c6eb7275d9086322038d83a50de60d9 GIT binary patch literal 3486 zcmcIm%}*Og6rWkI?e!N1oRWm#bQ2|jrGgs}X;P)FAT%XuYbk|FtuL#^I}kf&?d}dF zSX6QnS|F_iH|VLTs?;DNrTqgcrKeWv#Rw2|#et}~^hN@wp896jYaGW7QKde4o@d_7 zy!ZCad%v0A0|74r`YreA@RA#$KiR-0q1f47;1HTe3W_5ID_k1KfyX&$4rn}w2u_(= z?2Xp{a&Z`U4WqbQaZIAPpzy#w9C{Ba&Pk-WU?=FVq-BRCiF?hJZdfTCu+nF)^uS8* z0W1CBua^kRxM+iev5#=~eI{MAlkx{_mXhQFLJ(|@C z)uZR5LrGOu6C_I1v1mFu7|o8;YZa$l zGw`6{(r+Yb;@T3@JWR~IFq{c94mHp}3{7tamPcE~IGkVO!&|&_s_$0c^e1b4gDpR| z&NrD#o(WA6R?w~=l*}W704!0Q8^@3exI4DwFa$|b>iz9>#JVRid#>ArmhGq48mD_H({0;OQ8lJuV_TWwORbg;H$A0Da8mW_h*3}O^+0!g+IQTw7nDPKug z>L?D%qG8g@*|Sq4#SXNBaxk{%F`_JdCZ$;JSI}~C4C`L(A^-n*SULkvaej{JA=||i zOVkRQfD^N!u^&ZTF~b4nJ&pE=j|L%9Lu!!BGnN2hb_zPFIl+ z0=`(AMr2q6Kf@*UuzHF34ME8OU`a`82sZo}UQnDE)ik0~11HLgkEi2VqA{S+*fDFY zKnz!AFhvs7sI7De%7xcSddT2eNtih=ie|ZLB5cgnSMe3(`U7BjwCM}Zb=`ey@z4+9 z@4{Q5V;iC7l~D6)sP%sLN~o>iZ!3h_Hk-uh-mgF0@`q+)GqJ+4-mUP7?^`!ccCDQ3 zT0Qy3YWUnnxO*ks{ltNrdhi~?fs6RDKQP-j)A#k2(ypGD*tKnWvl%)z-MbZhWh28}9;5Eg>7 zH8V8}p2g0>;g&U_wJ0bYKC>otYzh8Z-;8grZ(RtRQH(`gR)(>1)>yS@jf{zmF(Z}8 z+Q4Lt9fzjZ0h>gd!9)4Jr<~8(x!dS)9=C9qt*H*Q)qwtDOk=t#t+g;2W9((2vnvU# z@q%T6$>DL}%F3*Eaz3-(%yLcS+})xAFPL}WVPSXRdNU<~vUTkpIpL#s`#=6*p#RNC zz2TN5C6kaOjlEqBEL(LKhJnUz2kjJNEC7YCU1BJCtW;4QEzM zs)xpS`WMgD#fQdMEH52gdjb$6@{LKw_Q%x7vU4r!iI2kML4>K#67+qAGgPQ2nKtt7<=|5FnGi}^W;un z9{<5Rr>{=FZ+7xz`sy9%?g+^1n>{jfD?~Qc^1xmd-j{Ni|6mj4~CY8eoQ{B`?cYhhC;A!4PD-GA;B{>c6%%z$d7Hhg;Lk& opFMl`Yys8fbK4$orM=)H>~CE|k?s90kB~E;nrm4{jb=*x1E2ncV*mgE literal 0 HcmV?d00001 diff --git a/psets/9/finance/env/lib/python3.12/site-packages/greenlet/tests/__pycache__/fail_slp_switch.cpython-312.pyc b/psets/9/finance/env/lib/python3.12/site-packages/greenlet/tests/__pycache__/fail_slp_switch.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..34a8280f62708680e3a3bd6b933db66153ac8ead GIT binary patch literal 1311 zcmc%|O-ma=bY?TzB&%udm)iEwr4%$sooeZ!P)Z9zp+ZjW!CaPgce2^IPL`RC5(SB( z=+T>h!D4?%p%;Ue$l{^UQ*PSy)Kh1S@Ueur%ZKYXE$a zi~@8{biWB=2e_aFTGC`jJx^Ef{6n5BRvzk>QF3l#ZJu?eZvla@(72VL>xcGWuMyAA(+qw z9Qd<1Y($kBeLOxfiMbzTjc=78*K0x7)~UA+wD}T4>}D75-6cqsXob?@Ue%lfzOl;*4dvHOI1; zT;Vt!GM`3F4$E0aan4d7h;P27y&BoG0ePir2|XqkJsuRR;*g(4-Xe_E7?XeMMIDf8 z*=O@Lw;qt^Y*?_eV|-OyCn*TwDM~@q?FVq+R0mMs*YEE>_yq9hOs-&)o>6 literal 0 HcmV?d00001 diff --git a/psets/9/finance/env/lib/python3.12/site-packages/greenlet/tests/__pycache__/fail_switch_three_greenlets.cpython-312.pyc b/psets/9/finance/env/lib/python3.12/site-packages/greenlet/tests/__pycache__/fail_switch_three_greenlets.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..3415a6fa8ca81b412d8749446c522f5db39724eb GIT binary patch literal 1727 zcmaJ>-)kd99G}_DZjw#T%Wdyc&g&gpp_Zu4+DZ{Yl+(5#9(_1Y(IA9%cbaTWHeq&h zXTu2*Pplx?x4TCXU!?dS_y-8SG&D!*(uacj&=;xAn@@gcHk+nB&M(Y&_WPahulaty zv%g)qpd+APJ0DhlNg(ux5MlyZ((rHC9wHZ&kc(ZVj!VEx3ao^iu!&0^ppxpUz%^F` zo>UOUwcN;iVx#H~jzo;4jWTgK`lMQHQ&OI4lN{S5s8XAHGKxF4kePHh6?m0EvHd1^Gd<1%j#Uq`M#*WQABk(PuQ`*q zCmgPTD|%Hswu?+3Dp+!d>&?_%FDc2t}KNLEG^O$a7b)c2?7z_{I_j2 zd~U7Socfm2bUnXfIl=PFRx5y3Td!Fgo^SgOwWxpBs(T+>txaBS`mYohm#o0!bfINC zpV$=|SaIhpP6P1Vu)TUYuAvIpm1BdT*xC%!5@!K3%Rn8^zzPQeE$)VRS2tW!CoZbaJ;TZ!dTQXLY#?TP^d-GnE^r` zR`4dUsQEAUN&awZx_j%ucy?gS^^CbaV}4*1dq#0!EccA%J>%8xy8y(lKGP@H1tJTN zu01AmEDJHtz#%Rw;rIwXCgG@!p9CC?C~jhH{5;|l0O@}p3bYZg7YGwm#4ZXZeuuIJ zKOtFFeCZ|8Wp)KlZ@>z!1M8wcNp?V{dt@30Za~Z)F$ZM6N9G@sf^remwLU? zblY|M2D=72ku~@N*l_}5{EwnyGRz{JJ5%6>3uRCM literal 0 HcmV?d00001 diff --git a/psets/9/finance/env/lib/python3.12/site-packages/greenlet/tests/__pycache__/fail_switch_three_greenlets2.cpython-312.pyc b/psets/9/finance/env/lib/python3.12/site-packages/greenlet/tests/__pycache__/fail_switch_three_greenlets2.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..a4517d19eb2f37ab8d53f7e4a2ac58802ce69b05 GIT binary patch literal 2581 zcmbVN%WoS+7@uA5!>@IkbskM=lT9H+7Sx-#>H&nP3P~VJ6sc{>!xw9_JK5NE*4FGg zC94)W0;%BwzBSyc-cW_qzkqWkF1Bpsu*xA4aNt&w8yA>a@2;KV(5fTNxAXYs=b7*K z`#%3H2vLCBQ~PtBWdZn&O#H@pgX1F#fCoSWS)frGU8J(uW@+3*T1a7ZkYzRIYmntM z7F%B9unp4yQU%e6>V6^j7^9I!0oRA_%z7>4eV;6Ss!urZ2|>Cr+ zc!XhWo%V6u`v_VD#vXfjqQEK0QU6T#G~`$xAoeikhUTRt4{DOKUK?r4;j8I{GKM+{&ujO9<8;;Bh~Ggv|qB1$%{1 zFboD7br)zfA+(o0i(t4-3+dS75%nYYEmoPu`Riy@W0a5;_UDC|Kk9xp)@J~p>>_f# zh}$5=uQ;rQ6cr+(6^C8DaqYwT1$$7>Nb9JyDY<*=6+^Y-k>&YopUg|HM~ZWJ1kFm( zG96ASm!Y9KY#HIOIdMP0rJSB|XxzEZN{VtA1?i?q@<#f5OWrgrc}}sQA*&@VZ|JgW zUYU{0CZmIg~AE;*2)0Q{UOxD~OxPDTac4unYi&q-rl_#4`ajv@LDWX2~#>3n7WTwSj-j5BT0Swun;-B!&t5aME5*)*L zEg-WG(S6fCkjXs?|EY1WMrg(*)MGJ20=j@{^h!cNW9Gj!4&rMg@^6Wf#1P6*1e+9% zhWyp%_;TUVS-d-rySao-75wg{V!)R$+!myUAT@=HZ6VbVQf*tW ztIIuPt=E&6T1?s}%Z~dJ+*I<0%@d2IYR5moH3Zjs$z6{75A1cy*vU1|NpX)UI)Ml@ z?XG3)i2K!N)4?!3w1j2a?tJVKiRlj~Jf1cqFpa@KJ)NhMx@qO00(4V6XuOYpE7Ef5?thKWnoi4R)lq z)nvyB!t*PK40nHVXK~kPG8d}UKH%>sb`rJ7-t6v|EinEoV5>$=X@Rr*FY>E%ukBrL ofeFvCo)~X36J5mE-u3#xL<>mX{#Q$V_Q=l_YSX`fb8dkC1s(4T{Qv*} literal 0 HcmV?d00001 diff --git a/psets/9/finance/env/lib/python3.12/site-packages/greenlet/tests/__pycache__/fail_switch_two_greenlets.cpython-312.pyc b/psets/9/finance/env/lib/python3.12/site-packages/greenlet/tests/__pycache__/fail_switch_two_greenlets.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..af8d9689873b6f32f69dec87638d272e00db88c4 GIT binary patch literal 1698 zcmaJ>&2Jk;6rWkouI;r8PSe^%3T0CSkwu$rf;b>mNQER)M3qC;qT-9S?2er^_O3NM zZit1DD+RSk2y!b&)Elb!KajY@sw;<84wevya%$rnC*I6@ZO5cM>AjhGe&4^h{{7rJ z9RdB;{=B-HKDz*9lMtL$)$vnCvsYg7?#1AWmBWl@@($ol31P(-b|0Pfa8t}S)=4M(4UL`wm0qR&Ivq{z{5I- zM~II`jR3SN{u({TziK}qjQDuyEbk~5=E6@>O?c1HWRO$w64UYaP?2nh>g`)MKH1o8 zXVW(~ZhW?3$Y+s+YLmGh53^C_W$u@&YoP+HMVcZGiN&fxAgVR~3CxDa&2@`Y&$NBV z^{S>Fd~nTd1~6*#L$l&~mSti_8MvHYZCdu1R+R>3JUNro z06Z&}TQA2o>_QPSd@IepFfCCQAhQfq@fvV&6+{Oelk~&oL$YwN{*)~Im7G5+EI!O0 zr}Q7w-=)9Lh+oY^vh>q>k1P$r0iD7_d_IDQk3pQqBVJ#OBmycJNUCY^ZF0s4)KU{& ze5;9iXDGG@q$eAYm}H#Nl8F{jRJYq{SljAqnYFyz?c6QOTTJeJq-rm0TJ<_WV)&Jc zK|Ke~k#$jHq6a3*4^#1QL%mA*XuU(NX^AywqKjV;%L;Sx*Ar?{baoyddEnqWh-mch z^+vmOkym8A%$J>lHI$vRrn2yIf{sTbT&M#MdhkkXtP0DHDY$_;}=szq+v0 z^@i`X>hvS_21F5i6MO^WMFL~|Qc*D(W)aQ})O1HV5@PWBg--T_X!!C;PQ%M5IR(G{ zB8BkzPO6XQx@hj8*h7m0HQ%}0SMyype{k=qdPz9XY6eJokiMVZ&-{VZL+z~|GL9n6 Jw;4Hve*s*3WSsy2 literal 0 HcmV?d00001 diff --git a/psets/9/finance/env/lib/python3.12/site-packages/greenlet/tests/__pycache__/leakcheck.cpython-312.pyc b/psets/9/finance/env/lib/python3.12/site-packages/greenlet/tests/__pycache__/leakcheck.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..abbb6694e2adcb100486076c3712403389c43d5a GIT binary patch literal 11563 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 LIDWpJf%ty_6IoLG42&a?oso(5+y#Wlp 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 QE^=J=>fA$uwI$=f0Vy`JE&u=k literal 0 HcmV?d00001 diff --git a/psets/9/finance/env/lib/python3.12/site-packages/greenlet/tests/__pycache__/test_generator.cpython-312.pyc b/psets/9/finance/env/lib/python3.12/site-packages/greenlet/tests/__pycache__/test_generator.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..87e8930c8b94490391aede2b56199df1717a1a8c GIT binary patch literal 3071 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 VFyC(9bH{1N(%wJ8)1Jk${{z~Pv~mCd literal 0 HcmV?d00001 diff --git a/psets/9/finance/env/lib/python3.12/site-packages/greenlet/tests/__pycache__/test_greenlet.cpython-312.pyc b/psets/9/finance/env/lib/python3.12/site-packages/greenlet/tests/__pycache__/test_greenlet.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..9a28501b31135db1a5812ce3b7c6295664361769 GIT binary patch literal 74876 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 literal 0 HcmV?d00001 diff --git a/psets/9/finance/env/lib/python3.12/site-packages/greenlet/tests/__pycache__/test_greenlet_trash.cpython-312.pyc b/psets/9/finance/env/lib/python3.12/site-packages/greenlet/tests/__pycache__/test_greenlet_trash.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..1143cc9dc87830491445639bfe8f440172d91862 GIT binary patch literal 6778 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 G#Qy?uM}=wt literal 0 HcmV?d00001 diff --git a/psets/9/finance/env/lib/python3.12/site-packages/greenlet/tests/__pycache__/test_leaks.cpython-312.pyc b/psets/9/finance/env/lib/python3.12/site-packages/greenlet/tests/__pycache__/test_leaks.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..4cb7098b4baff3545554ba9fc5338e2a83664dca GIT binary patch literal 19454 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 a-(kzssVwWyu}v!5G|L8oHDUc^k^c|6%W!!B literal 0 HcmV?d00001 diff --git a/psets/9/finance/env/lib/python3.12/site-packages/greenlet/tests/__pycache__/test_stack_saved.cpython-312.pyc b/psets/9/finance/env/lib/python3.12/site-packages/greenlet/tests/__pycache__/test_stack_saved.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..6d6534081cc5215e5951f436c60f1a99adcf2f39 GIT binary patch literal 1350 zcmah}%}*0i5TCbQ>Qc58RG<(c1iUOCUD23mLWo8UL=sM3>}9j=zLwVQw!XJTOG?6_ zi7lFNGL#cnO#cVZCY~A~C99r1aWg3<#*^=LTP%Vy$Tzwk< zfB?R6r9~Z0p&ntv7MNfn3!-2Orq4ntAu1pcU>;1d0A>dkDn1V%_2rP_KjO;L5sL{5 za-}DjIuCS;4G-gSZsb(I%-9xSh$0iBf{6;if(VMw6}g|$!f~v~9-gRfv(wk&7C0x? zq`(2EsnS$8#5^Qh7ixo)#H7DXZHgwUG-DwsiZNsg1!)bnWjgBuc~oguvL@t(Wan8( ztClq%tEKC#J@0GJ`wxt8QN91qjo|z~Fs}>xkORfHM0i_H&5+OH3VZ6ajJ-o!P=e&i zMA%W2*y(xGX(AD@=x9k1Tt9u8aExVF)~KT!&o!#AV3RG7n9>tAO8Far3nX5XINl8j;R_a z7~2+hREKRDZSeNAkxb4NV_Dl+9p`Hp;iyygSu1Vm7M+W55FaS*W9;WT9LhbLi>1Y~ zSPLuFuyP}u0;4h(pT4<~q8rut9FN%kf zT$938DO|o<8=R;PPVC;_mmYP0GL$I$V4_D>kvbiUZ7tx^{+*~Lvym`z-?l)AG zhRQQ#eP0@F(|6{!=XPiIrRhVdb5klwZv%gl^zMvokL>myNRy7r4QALnyyq0qUaMG38;nSrJKyy<8ytKjL`| safv7P+9%C=`R2$qcE&f34lwrJhY ziP~fPn=>lcjQ2tOkm%SVzm zADmTG?HjVHq|ElF#E*UOxAu2SQ9Rowm4`Ueum7unPxJ>4P9oOER4Yo`LTc(53Y;ez1aL;V8V=CD38{uKF z`=QXi2<^x+Jz82@JP2w&X4FWe|KW%YHTW!5pI~vV@p@D_HBe8CV2~TjyA(E z$NSa&rUd#xb-0QqS`X~e*45h(iSdbL%EIL|!QWyA#02p>K$o_cLY+@JYe-6l$S$JU z&}<_tvaF@!`*YCtBDut$BNypCKB05v^SY3cbA=dZY`Gr#V6dd+ipp`u%IqFtA(##e zg3xKEBGvYy1Cf(V6=YTIc&kuO$p!UrM#9@EA{OCkw3jUD`X z;)^98iAoEEvtK=KY<}W_+vh5d^yA=Gax1!@|25suvyJfJp2y&bIkzATrZDaJ4+iCe z?lJJnqS#2#1yw0zSTo${G^_JWQB~Ba1jU?vpf=yirn<|(@zqlxE|Ue$>)*ZmD9 z?_WK2h0aA9uJ@1jU(H|P=fu#gxMfP*GTAhlo)LH9tL$iYyf7Wv<$C)_+-0b58Eg?~ z25d6`&#w%&NO7a2c?(6>b$xXB>WBt2t|EPXGX<&%t5EHCpn`Q#O|X&BoNZNDc+PfBUW1fUT4u%ldg;Y*1GqfEs zk7>J+6FRRBsk*3KN+olpOc`!92Hu3f07ON@Xwt%9Or^!m2WaFV^>%2ko&kZR_J+4x zqz>7n4jQBu;8pY1iNcM-&C=cXr<(VS@$*g1W9rQ}ColY|>9zUjw#hffPd|=s`-g`_ zcR%q!`{!x{^lPyGP|s%mK{EwuuB{bbu+1p8fpD=|G}sK&tTfe`yYay|e1%LFfyvPq zV)EUC)6ILQBl}!*2C{z^imu-v-2LXtKI)nTj1dfz@WZdrBv>dlNM$1wW>zg4`T(O0 z^O{v9c{G}?V$svWHuz4GuhS!VR0#as#qm{LkNe-8=Sr`P+hTa-{ZN^3dS8c6b&z(M zPi7n7qkGikY)?W2>AG=oTdwDMNZeFm*1cl&ZZKrH^)vGL;WcT zBp3$-^S%JVuI3D4U2hm|xE;8A;8St7{q3ptx2Lxpo)M3Ld&L)%^p5wIcShV%b+4;` z^GH0h(#hJ4`X_AQ&%Dl!TPuS9*n7pBp%6)mBh;vIP~&Rb>xe0N$5U>Y|Fq_mg!<8> zW@iEx!n+ADL#W4$m2Dx(F@7v=8Jw~i2^&!@&|f`9qQQr<>R0^QUpdxl!+vBf4e)t1 z>#kxm*8>_tYPiZUS%G&;Y2}icWkHf(l)*;hEH0br3YY1u9CDjp z4Kv|nwyda0t(+{gTo&^ELee}ka0G0fJAgpD9(6ID)^NuGxT+I~hCmS}APyDU?UE0d0oC>jhAw;T%=GLJ%65|rjeHm6R zN|`PegAdsoAeOJR>*ZJ4g}Z3Pkg(FZP~-Jeqo*eQk3u^QpAe%=#39jLF?6QvO%O4^ z=`t~$*F&bG{6NmBipmaP8+4#-FN)VuVB}(W)|iiBB+T$MgB=2)bJte6slWq_y z_K7*CBpo&Pai`%)*W9?u>o2s=hjAQKAgp-4Ve@Rm&Z&l-(+zD`geAe_Z(WK||1R*y zk>;_!tKYlA%|i~`cX#7Vxa|rz7v3-%ZkY-HlAiG-vhS}| z-^<vXV*7tElSiWTEDqY43hy-u@*v!NqKp51m*>P=zGbPs9d!t>I};f7 zBB5QSc1%-?1K`|hT^VHESiv|(#X)Kjy5(shzeLhPsT)7wVU4S3wio#k&12;0D%PCA zINB#;E3NOfc-8iDiAtw|{q~ro_2*bxg2T+gA{=x|#X(h*`V>i)G$yB%J~)|_%6)ky zr2#*`4#VpHvqJ;sF;tDOW_0U6ekr94Xt{F940+p(=8)=|5ASgXQFR`ks5njQ3}}l% z#!|VIw8uo_DHkid+!UK0tVFB5g6J9GIkW6>EUDW&w)B6b0CxI)5bK25&ES0Ft2Y~#Jp8{w*(pTX zdv26<_Z;FM9P%9FRzca{VJ2UeEpvukbueUO5T;ZuH53Ad);LXYp5(7#ui!wOm-|wc zP8&a}ZK#Z+Zbki?RA!R3b8v^)!lN~DbtD;SIohaIP_waWmNfHUFmhi(sl4h23ykA< z4V|gyK&%HNbB&vpc+LWcxV8!MFEc@HJ?;F1c27^IFA)pqVlr8hi%K%72a?HRIXzgw zdMKI1^LX43ds-L1Lq$)5E<{Dodvr1Cg}QkTf*;4cY$sd{66=JaJ2fLWqxf&4G><_bV rLpyZR>T4h%2&VMUB=FQrXv<$n^MXL>!6k8!(gYpb@{|}AW5|C2n3z(= literal 0 HcmV?d00001 diff --git a/psets/9/finance/env/lib/python3.12/site-packages/greenlet/tests/__pycache__/test_tracing.cpython-312.pyc b/psets/9/finance/env/lib/python3.12/site-packages/greenlet/tests/__pycache__/test_tracing.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..b8a774b2a3a807f3512642998c52c622ffc55965 GIT binary patch literal 13609 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 I2PhK%57hw?qW}N^ literal 0 HcmV?d00001 diff --git a/psets/9/finance/env/lib/python3.12/site-packages/greenlet/tests/__pycache__/test_version.cpython-312.pyc b/psets/9/finance/env/lib/python3.12/site-packages/greenlet/tests/__pycache__/test_version.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..7a35604464f2dd3f76b48d080767b10be7c8c773 GIT binary patch literal 2557 zcmbUjZA?>F^xpT;4=5A`gdxtd>Rdx;Rbr~qVTO_!qr?p)QfFQseHUyg@74Ei`RH17 zi%T#uvuw$V*@u{z=)#Zv*$=Z{i@%n*WF=^1ZT{dcr>J1>e?M=>wEU3Q}+ajo=8zjOKvmBAi9@2|mID zk532@0kDt|M;sC7n#>h(ap+y7h?kM#AkI0y=r-b>-~-O5>?43puRLIAi4-MLY$U1a z6j;?sJ*HA=Fr`LmOjEmoWA2}{3L(%n<5^= zV`!Z3M`PHJ_8v%;58|0jE*s*0D8N5*&mNoGIIhm4w z17E$EaYUgRdXRub~N7F&G+AY3Qg-i5iM(N=zLJMU8#CLrH^BBXl4HNyuuHgorvCO2h_2 z$q9O1Q`>`k_J)iYC2dJLIxG(nBQ&HFq9zCpQ8wr-D2*0JUobgg*0E|xiZ%lNDC}Zo zmkzHVjzMNwvN@E{qH@CM2ySG^2AA;*fJ3$<@g9bKw#n%VnBe-1BhY0CA@$kUM= zx7gU68=d8*Kb%!&`{o;3bHY+%(+%f!=MB$w&#Y2tY|V)_$9vs-M_gzO=ETLC`n+e_ zGjsYujo;q1W4dE@=fm2!7PtC7JF)CVTeh#(pxTx~OZe`N`Ie3!o9A0jJ~-7==_eW>F481a8m=$E4L{pS`*V&_Cib)MR%M^4XE2ap# zv7}ikTV2+5AtfhFmwm!!rDUIyB(bJ5NMcamR@{k2F2Q+YVtQigs5VR_D`*oBLL6&> zt?xj+nHhT4pMCnZ|7;63XpFA_Ttd&dYWD|t*~hz2<6j$E?;Kxf2u~ebtw3$Nzw4gs z{^3}mp=-*sROP*P=E|8|;z5;v_QGOAV}5jc^z-rj*}g&v{h6W7&b+RgYYa z^RC93##{Rz`NQ-6@I%-Bzg9P)n%AEp3|lOEYObBUa>4(&EIox>ulxkwTg^x7dsC*y8{Bd z=IlzsHLsAQ5lu;1SKcE@tmH+B9s+OQBK>thRd`|XocG<9w_QCaiD@Z z98A%a4$gJ>hEeu!(?n@_siVet*Ix7JPdb}wF>)BN8iPit=-xgRf@oL y9V*7!p@%`h-Ued_04M~;f1o!Xqn%Gs#c#;{7_~n^-c?sKK2WIL`6mKwdHDxYK|_E5 literal 0 HcmV?d00001 diff --git a/psets/9/finance/env/lib/python3.12/site-packages/greenlet/tests/__pycache__/test_weakref.cpython-312.pyc b/psets/9/finance/env/lib/python3.12/site-packages/greenlet/tests/__pycache__/test_weakref.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..11ea90b96cd9ac5b59b9a06c88707919c550ad81 GIT binary patch literal 2741 zcmbVO-Af!-6u)<7b{*GQGe%9fAF&!u(k0euVl6EMiKHdcfTd}n#D^}EnY$Zx+}+NM zu`UsW3fWBqrqHrV`jEaE{43h0LZ6ncC=&~X_9bt@O(4xv&$+X+?yeF^F6?ja$GPX6 zd+s^EyMIKZ5d!V^+|`sL67mlYf)=WFDx=UT5|fzJB9s1?PEtM=CIwS4MN6EOCM8M) za*3GIGBHC;+5mmnCPND}9)5(~iANMLPCfZc=C~JihZ#5>G+e}1=>aGbM$iZtpvz=Z zGzCD(6ahmEQat1-Uom~=3QM9Y#|ZY~ehGePyz(OeI1c+4saunn7GS!m3FIc-sLpLv zB^L!Z2mzT6H*J7nAWz9nGTpj=9drtTj7c`CRw-E^abcq2;OJ~8{3=%filolf{aX2P zYA&K_+}+dyv*_9v`^=#*H-~{Lfu4Wo$*HuSHkiiJH#BSNnwDK~uV>Q3Lub!v&XmjE&FaRCo??!cvKdQT%+*}H zB#w!BxHg+5hq4QveBRP$ubKL2ZoK|7hfq3UGTp2RpSLoGZaJev{&b*ss5T#H!b3QC zt|hWQU@Opx3!WUvdtqmO$~CS-3euE=_uOko0loG{y}1uw%^xf#rx##}?5MFVwXdZ1 z{W4fqwfxw&5?vWDjNkcmyR$1l?t2#UTB_0TL+pd^4w8 zanX|;W+m;T=q$}(t&-l}s`DND;+5-pvHzH@&ItE&R}fpfpU5QIwQ{*|d9A%1d#9|# z^K?g!tV9ZtJIc1KY{{{b99!$S*STtL%KhB=gDY+wbT%aL0ku|FRd`WNElAy3ic_~G z5Sf;P-rhHm=T(Te-_+_WyRiywysdcH#!|4m5RM>pBOF6`4InPqG3>t%;NW3`pm+12 zLm?RM)D0FSYVO4Tz&Fd_9Xjs=K$0k(81<; zJo#3PlKG@BT;_~PxT9+_1O}6EQrxQPG$WiwZE*M+)@Wi>fn|-TvCVs zR7d_+yNYc;w5^TZySS~`qohF{_w!DG-18>^4OeYZ-vevxAg>k6M&ddRQzepmt~KF0%VpFkD(Hvri7!UaFH zT>;6r zNhD@7=A4CnC6T}<#b2@C0C()S5KbZBjq&|{RMp;7w`h#(I*Zv#9QDWwld>qF9B2@|URMUFj@ P-lV7Re)yEYha3AJC&4Ax literal 0 HcmV?d00001 diff --git a/psets/9/finance/env/lib/python3.12/site-packages/greenlet/tests/_test_extension.c b/psets/9/finance/env/lib/python3.12/site-packages/greenlet/tests/_test_extension.c new file mode 100644 index 0000000..05e81c0 --- /dev/null +++ b/psets/9/finance/env/lib/python3.12/site-packages/greenlet/tests/_test_extension.c @@ -0,0 +1,231 @@ +/* This is a set of functions used by test_extension_interface.py to test the + * Greenlet C API. + */ + +#include "../greenlet.h" + +#ifndef Py_RETURN_NONE +# define Py_RETURN_NONE return Py_INCREF(Py_None), Py_None +#endif + +#define TEST_MODULE_NAME "_test_extension" + +static PyObject* +test_switch(PyObject* self, PyObject* greenlet) +{ + PyObject* result = NULL; + + if (greenlet == NULL || !PyGreenlet_Check(greenlet)) { + PyErr_BadArgument(); + return NULL; + } + + result = PyGreenlet_Switch((PyGreenlet*)greenlet, NULL, NULL); + if (result == NULL) { + if (!PyErr_Occurred()) { + PyErr_SetString(PyExc_AssertionError, + "greenlet.switch() failed for some reason."); + } + return NULL; + } + Py_INCREF(result); + return result; +} + +static PyObject* +test_switch_kwargs(PyObject* self, PyObject* args, PyObject* kwargs) +{ + PyGreenlet* g = NULL; + PyObject* result = NULL; + + PyArg_ParseTuple(args, "O!", &PyGreenlet_Type, &g); + + if (g == NULL || !PyGreenlet_Check(g)) { + PyErr_BadArgument(); + return NULL; + } + + result = PyGreenlet_Switch(g, NULL, kwargs); + if (result == NULL) { + if (!PyErr_Occurred()) { + PyErr_SetString(PyExc_AssertionError, + "greenlet.switch() failed for some reason."); + } + return NULL; + } + Py_XINCREF(result); + return result; +} + +static PyObject* +test_getcurrent(PyObject* self) +{ + PyGreenlet* g = PyGreenlet_GetCurrent(); + if (g == NULL || !PyGreenlet_Check(g) || !PyGreenlet_ACTIVE(g)) { + PyErr_SetString(PyExc_AssertionError, + "getcurrent() returned an invalid greenlet"); + Py_XDECREF(g); + return NULL; + } + Py_DECREF(g); + Py_RETURN_NONE; +} + +static PyObject* +test_setparent(PyObject* self, PyObject* arg) +{ + PyGreenlet* current; + PyGreenlet* greenlet = NULL; + + if (arg == NULL || !PyGreenlet_Check(arg)) { + PyErr_BadArgument(); + return NULL; + } + if ((current = PyGreenlet_GetCurrent()) == NULL) { + return NULL; + } + greenlet = (PyGreenlet*)arg; + if (PyGreenlet_SetParent(greenlet, current)) { + Py_DECREF(current); + return NULL; + } + Py_DECREF(current); + if (PyGreenlet_Switch(greenlet, NULL, NULL) == NULL) { + return NULL; + } + Py_RETURN_NONE; +} + +static PyObject* +test_new_greenlet(PyObject* self, PyObject* callable) +{ + PyObject* result = NULL; + PyGreenlet* greenlet = PyGreenlet_New(callable, NULL); + + if (!greenlet) { + return NULL; + } + + result = PyGreenlet_Switch(greenlet, NULL, NULL); + Py_CLEAR(greenlet); + if (result == NULL) { + return NULL; + } + + Py_INCREF(result); + return result; +} + +static PyObject* +test_raise_dead_greenlet(PyObject* self) +{ + PyErr_SetString(PyExc_GreenletExit, "test GreenletExit exception."); + return NULL; +} + +static PyObject* +test_raise_greenlet_error(PyObject* self) +{ + PyErr_SetString(PyExc_GreenletError, "test greenlet.error exception"); + return NULL; +} + +static PyObject* +test_throw(PyObject* self, PyGreenlet* g) +{ + const char msg[] = "take that sucka!"; + PyObject* msg_obj = Py_BuildValue("s", msg); + PyGreenlet_Throw(g, PyExc_ValueError, msg_obj, NULL); + Py_DECREF(msg_obj); + if (PyErr_Occurred()) { + return NULL; + } + Py_RETURN_NONE; +} + +static PyObject* +test_throw_exact(PyObject* self, PyObject* args) +{ + PyGreenlet* g = NULL; + PyObject* typ = NULL; + PyObject* val = NULL; + PyObject* tb = NULL; + + if (!PyArg_ParseTuple(args, "OOOO:throw", &g, &typ, &val, &tb)) { + return NULL; + } + + PyGreenlet_Throw(g, typ, val, tb); + if (PyErr_Occurred()) { + return NULL; + } + Py_RETURN_NONE; +} + +static PyMethodDef test_methods[] = { + {"test_switch", + (PyCFunction)test_switch, + METH_O, + "Switch to the provided greenlet sending provided arguments, and \n" + "return the results."}, + {"test_switch_kwargs", + (PyCFunction)test_switch_kwargs, + METH_VARARGS | METH_KEYWORDS, + "Switch to the provided greenlet sending the provided keyword args."}, + {"test_getcurrent", + (PyCFunction)test_getcurrent, + METH_NOARGS, + "Test PyGreenlet_GetCurrent()"}, + {"test_setparent", + (PyCFunction)test_setparent, + METH_O, + "Se the parent of the provided greenlet and switch to it."}, + {"test_new_greenlet", + (PyCFunction)test_new_greenlet, + METH_O, + "Test PyGreenlet_New()"}, + {"test_raise_dead_greenlet", + (PyCFunction)test_raise_dead_greenlet, + METH_NOARGS, + "Just raise greenlet.GreenletExit"}, + {"test_raise_greenlet_error", + (PyCFunction)test_raise_greenlet_error, + METH_NOARGS, + "Just raise greenlet.error"}, + {"test_throw", + (PyCFunction)test_throw, + METH_O, + "Throw a ValueError at the provided greenlet"}, + {"test_throw_exact", + (PyCFunction)test_throw_exact, + METH_VARARGS, + "Throw exactly the arguments given at the provided greenlet"}, + {NULL, NULL, 0, NULL} +}; + + +#define INITERROR return NULL + +static struct PyModuleDef moduledef = {PyModuleDef_HEAD_INIT, + TEST_MODULE_NAME, + NULL, + 0, + test_methods, + NULL, + NULL, + NULL, + NULL}; + +PyMODINIT_FUNC +PyInit__test_extension(void) +{ + PyObject* module = NULL; + module = PyModule_Create(&moduledef); + + if (module == NULL) { + return NULL; + } + + PyGreenlet_Import(); + return module; +} diff --git a/psets/9/finance/env/lib/python3.12/site-packages/greenlet/tests/_test_extension.cpython-312-x86_64-linux-gnu.so b/psets/9/finance/env/lib/python3.12/site-packages/greenlet/tests/_test_extension.cpython-312-x86_64-linux-gnu.so new file mode 100644 index 0000000000000000000000000000000000000000..4413bee73d99eab4c175abf16cdb248bebbd1daf GIT binary patch literal 37168 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 B5A6T| literal 0 HcmV?d00001 diff --git a/psets/9/finance/env/lib/python3.12/site-packages/greenlet/tests/_test_extension_cpp.cpp b/psets/9/finance/env/lib/python3.12/site-packages/greenlet/tests/_test_extension_cpp.cpp new file mode 100644 index 0000000..5cbe6a7 --- /dev/null +++ b/psets/9/finance/env/lib/python3.12/site-packages/greenlet/tests/_test_extension_cpp.cpp @@ -0,0 +1,226 @@ +/* This is a set of functions used to test C++ exceptions are not + * broken during greenlet switches + */ + +#include "../greenlet.h" +#include "../greenlet_compiler_compat.hpp" +#include +#include + +struct exception_t { + int depth; + exception_t(int depth) : depth(depth) {} +}; + +/* Functions are called via pointers to prevent inlining */ +static void (*p_test_exception_throw_nonstd)(int depth); +static void (*p_test_exception_throw_std)(); +static PyObject* (*p_test_exception_switch_recurse)(int depth, int left); + +static void +test_exception_throw_nonstd(int depth) +{ + throw exception_t(depth); +} + +static void +test_exception_throw_std() +{ + throw std::runtime_error("Thrown from an extension."); +} + +static PyObject* +test_exception_switch_recurse(int depth, int left) +{ + if (left > 0) { + return p_test_exception_switch_recurse(depth, left - 1); + } + + PyObject* result = NULL; + PyGreenlet* self = PyGreenlet_GetCurrent(); + if (self == NULL) + return NULL; + + try { + if (PyGreenlet_Switch(PyGreenlet_GET_PARENT(self), NULL, NULL) == NULL) { + Py_DECREF(self); + return NULL; + } + p_test_exception_throw_nonstd(depth); + PyErr_SetString(PyExc_RuntimeError, + "throwing C++ exception didn't work"); + } + catch (const exception_t& e) { + if (e.depth != depth) + PyErr_SetString(PyExc_AssertionError, "depth mismatch"); + else + result = PyLong_FromLong(depth); + } + catch (...) { + PyErr_SetString(PyExc_RuntimeError, "unexpected C++ exception"); + } + + Py_DECREF(self); + return result; +} + +/* test_exception_switch(int depth) + * - recurses depth times + * - switches to parent inside try/catch block + * - throws an exception that (expected to be caught in the same function) + * - verifies depth matches (exceptions shouldn't be caught in other greenlets) + */ +static PyObject* +test_exception_switch(PyObject* UNUSED(self), PyObject* args) +{ + int depth; + if (!PyArg_ParseTuple(args, "i", &depth)) + return NULL; + return p_test_exception_switch_recurse(depth, depth); +} + + +static PyObject* +py_test_exception_throw_nonstd(PyObject* self, PyObject* args) +{ + if (!PyArg_ParseTuple(args, "")) + return NULL; + p_test_exception_throw_nonstd(0); + PyErr_SetString(PyExc_AssertionError, "unreachable code running after throw"); + return NULL; +} + +static PyObject* +py_test_exception_throw_std(PyObject* self, PyObject* args) +{ + if (!PyArg_ParseTuple(args, "")) + return NULL; + p_test_exception_throw_std(); + PyErr_SetString(PyExc_AssertionError, "unreachable code running after throw"); + return NULL; +} + +static PyObject* +py_test_call(PyObject* self, PyObject* arg) +{ + PyObject* noargs = PyTuple_New(0); + PyObject* ret = PyObject_Call(arg, noargs, nullptr); + Py_DECREF(noargs); + return ret; +} + + + +/* test_exception_switch_and_do_in_g2(g2func) + * - creates new greenlet g2 to run g2func + * - switches to g2 inside try/catch block + * - verifies that no exception has been caught + * + * it is used together with test_exception_throw to verify that unhandled + * exceptions thrown in one greenlet do not propagate to other greenlet nor + * segfault the process. + */ +static PyObject* +test_exception_switch_and_do_in_g2(PyObject* self, PyObject* args) +{ + PyObject* g2func = NULL; + PyObject* result = NULL; + + if (!PyArg_ParseTuple(args, "O", &g2func)) + return NULL; + PyGreenlet* g2 = PyGreenlet_New(g2func, NULL); + if (!g2) { + return NULL; + } + + try { + result = PyGreenlet_Switch(g2, NULL, NULL); + if (!result) { + return NULL; + } + } + catch (const exception_t& e) { + /* if we are here the memory can be already corrupted and the program + * might crash before below py-level exception might become printed. + * -> print something to stderr to make it clear that we had entered + * this catch block. + * See comments in inner_bootstrap() + */ +#if defined(WIN32) || defined(_WIN32) + fprintf(stderr, "C++ exception unexpectedly caught in g1\n"); + PyErr_SetString(PyExc_AssertionError, "C++ exception unexpectedly caught in g1"); + Py_XDECREF(result); + return NULL; +#else + throw; +#endif + } + + Py_XDECREF(result); + Py_RETURN_NONE; +} + +static PyMethodDef test_methods[] = { + {"test_exception_switch", + (PyCFunction)&test_exception_switch, + METH_VARARGS, + "Switches to parent twice, to test exception handling and greenlet " + "switching."}, + {"test_exception_switch_and_do_in_g2", + (PyCFunction)&test_exception_switch_and_do_in_g2, + METH_VARARGS, + "Creates new greenlet g2 to run g2func and switches to it inside try/catch " + "block. Used together with test_exception_throw to verify that unhandled " + "C++ exceptions thrown in a greenlet doe not corrupt memory."}, + {"test_exception_throw_nonstd", + (PyCFunction)&py_test_exception_throw_nonstd, + METH_VARARGS, + "Throws non-standard C++ exception. Calling this function directly should abort the process." + }, + {"test_exception_throw_std", + (PyCFunction)&py_test_exception_throw_std, + METH_VARARGS, + "Throws standard C++ exception. Calling this function directly should abort the process." + }, + {"test_call", + (PyCFunction)&py_test_call, + METH_O, + "Call the given callable. Unlike calling it directly, this creates a " + "new C-level stack frame, which may be helpful in testing." + }, + {NULL, NULL, 0, NULL} +}; + + +static struct PyModuleDef moduledef = {PyModuleDef_HEAD_INIT, + "greenlet.tests._test_extension_cpp", + NULL, + 0, + test_methods, + NULL, + NULL, + NULL, + NULL}; + +PyMODINIT_FUNC +PyInit__test_extension_cpp(void) +{ + PyObject* module = NULL; + + module = PyModule_Create(&moduledef); + + if (module == NULL) { + return NULL; + } + + PyGreenlet_Import(); + if (_PyGreenlet_API == NULL) { + return NULL; + } + + p_test_exception_throw_nonstd = test_exception_throw_nonstd; + p_test_exception_throw_std = test_exception_throw_std; + p_test_exception_switch_recurse = test_exception_switch_recurse; + + return module; +} diff --git a/psets/9/finance/env/lib/python3.12/site-packages/greenlet/tests/_test_extension_cpp.cpython-312-x86_64-linux-gnu.so b/psets/9/finance/env/lib/python3.12/site-packages/greenlet/tests/_test_extension_cpp.cpython-312-x86_64-linux-gnu.so new file mode 100644 index 0000000000000000000000000000000000000000..e7b30ca4baa8cd4b5b8e48c2787cca9b7cd99da5 GIT binary patch literal 57800 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 appearing to return, even though +# it has yet to run. +print('In main with', x, flush=True) +g.switch() +print('RESULTS', results) diff --git a/psets/9/finance/env/lib/python3.12/site-packages/greenlet/tests/fail_cpp_exception.py b/psets/9/finance/env/lib/python3.12/site-packages/greenlet/tests/fail_cpp_exception.py new file mode 100644 index 0000000..fa4dc2e --- /dev/null +++ b/psets/9/finance/env/lib/python3.12/site-packages/greenlet/tests/fail_cpp_exception.py @@ -0,0 +1,33 @@ +# -*- coding: utf-8 -*- +""" +Helper for testing a C++ exception throw aborts the process. + +Takes one argument, the name of the function in :mod:`_test_extension_cpp` to call. +""" +import sys +import greenlet +from greenlet.tests import _test_extension_cpp +print('fail_cpp_exception is running') + +def run_unhandled_exception_in_greenlet_aborts(): + def _(): + _test_extension_cpp.test_exception_switch_and_do_in_g2( + _test_extension_cpp.test_exception_throw_nonstd + ) + g1 = greenlet.greenlet(_) + g1.switch() + + +func_name = sys.argv[1] +try: + func = getattr(_test_extension_cpp, func_name) +except AttributeError: + if func_name == run_unhandled_exception_in_greenlet_aborts.__name__: + func = run_unhandled_exception_in_greenlet_aborts + elif func_name == 'run_as_greenlet_target': + g = greenlet.greenlet(_test_extension_cpp.test_exception_throw_std) + func = g.switch + else: + raise +print('raising', func, flush=True) +func() diff --git a/psets/9/finance/env/lib/python3.12/site-packages/greenlet/tests/fail_initialstub_already_started.py b/psets/9/finance/env/lib/python3.12/site-packages/greenlet/tests/fail_initialstub_already_started.py new file mode 100644 index 0000000..c1a44ef --- /dev/null +++ b/psets/9/finance/env/lib/python3.12/site-packages/greenlet/tests/fail_initialstub_already_started.py @@ -0,0 +1,78 @@ +""" +Testing initialstub throwing an already started exception. +""" + +import greenlet + +a = None +b = None +c = None +main = greenlet.getcurrent() + +# If we switch into a dead greenlet, +# we go looking for its parents. +# if a parent is not yet started, we start it. + +results = [] + +def a_run(*args): + #results.append('A') + results.append(('Begin A', args)) + + +def c_run(): + results.append('Begin C') + b.switch('From C') + results.append('C done') + +class A(greenlet.greenlet): pass + +class B(greenlet.greenlet): + doing_it = False + def __getattribute__(self, name): + if name == 'run' and not self.doing_it: + assert greenlet.getcurrent() is c + self.doing_it = True + results.append('Switch to b from B.__getattribute__ in ' + + type(greenlet.getcurrent()).__name__) + b.switch() + results.append('B.__getattribute__ back from main in ' + + type(greenlet.getcurrent()).__name__) + if name == 'run': + name = '_B_run' + return object.__getattribute__(self, name) + + def _B_run(self, *arg): + results.append(('Begin B', arg)) + results.append('_B_run switching to main') + main.switch('From B') + +class C(greenlet.greenlet): + pass +a = A(a_run) +b = B(parent=a) +c = C(c_run, b) + +# Start a child; while running, it will start B, +# but starting B will ALSO start B. +result = c.switch() +results.append(('main from c', result)) + +# Switch back to C, which was in the middle of switching +# already. This will throw the ``GreenletStartedWhileInPython`` +# exception, which results in parent A getting started (B is finished) +c.switch() + +results.append(('A dead?', a.dead, 'B dead?', b.dead, 'C dead?', c.dead)) + +# A and B should both be dead now. +assert a.dead +assert b.dead +assert not c.dead + +result = c.switch() +results.append(('main from c.2', result)) +# Now C is dead +assert c.dead + +print("RESULTS:", results) diff --git a/psets/9/finance/env/lib/python3.12/site-packages/greenlet/tests/fail_slp_switch.py b/psets/9/finance/env/lib/python3.12/site-packages/greenlet/tests/fail_slp_switch.py new file mode 100644 index 0000000..0990526 --- /dev/null +++ b/psets/9/finance/env/lib/python3.12/site-packages/greenlet/tests/fail_slp_switch.py @@ -0,0 +1,29 @@ +# -*- coding: utf-8 -*- +""" +A test helper for seeing what happens when slp_switch() +fails. +""" +# pragma: no cover + +import greenlet + + +print('fail_slp_switch is running', flush=True) + +runs = [] +def func(): + runs.append(1) + greenlet.getcurrent().parent.switch() + runs.append(2) + greenlet.getcurrent().parent.switch() + runs.append(3) + +g = greenlet._greenlet.UnswitchableGreenlet(func) +g.switch() +assert runs == [1] +g.switch() +assert runs == [1, 2] +g.force_slp_switch_error = True + +# This should crash. +g.switch() diff --git a/psets/9/finance/env/lib/python3.12/site-packages/greenlet/tests/fail_switch_three_greenlets.py b/psets/9/finance/env/lib/python3.12/site-packages/greenlet/tests/fail_switch_three_greenlets.py new file mode 100644 index 0000000..e151b19 --- /dev/null +++ b/psets/9/finance/env/lib/python3.12/site-packages/greenlet/tests/fail_switch_three_greenlets.py @@ -0,0 +1,44 @@ +""" +Uses a trace function to switch greenlets at unexpected times. + +In the trace function, we switch from the current greenlet to another +greenlet, which switches +""" +import greenlet + +g1 = None +g2 = None + +switch_to_g2 = False + +def tracefunc(*args): + print('TRACE', *args) + global switch_to_g2 + if switch_to_g2: + switch_to_g2 = False + g2.switch() + print('\tLEAVE TRACE', *args) + +def g1_run(): + print('In g1_run') + global switch_to_g2 + switch_to_g2 = True + from_parent = greenlet.getcurrent().parent.switch() + print('Return to g1_run') + print('From parent', from_parent) + +def g2_run(): + #g1.switch() + greenlet.getcurrent().parent.switch() + +greenlet.settrace(tracefunc) + +g1 = greenlet.greenlet(g1_run) +g2 = greenlet.greenlet(g2_run) + +# This switch didn't actually finish! +# And if it did, it would raise TypeError +# because g1_run() doesn't take any arguments. +g1.switch(1) +print('Back in main') +g1.switch(2) diff --git a/psets/9/finance/env/lib/python3.12/site-packages/greenlet/tests/fail_switch_three_greenlets2.py b/psets/9/finance/env/lib/python3.12/site-packages/greenlet/tests/fail_switch_three_greenlets2.py new file mode 100644 index 0000000..1f6b66b --- /dev/null +++ b/psets/9/finance/env/lib/python3.12/site-packages/greenlet/tests/fail_switch_three_greenlets2.py @@ -0,0 +1,55 @@ +""" +Like fail_switch_three_greenlets, but the call into g1_run would actually be +valid. +""" +import greenlet + +g1 = None +g2 = None + +switch_to_g2 = True + +results = [] + +def tracefunc(*args): + results.append(('trace', args[0])) + print('TRACE', *args) + global switch_to_g2 + if switch_to_g2: + switch_to_g2 = False + g2.switch('g2 from tracefunc') + print('\tLEAVE TRACE', *args) + +def g1_run(arg): + results.append(('g1 arg', arg)) + print('In g1_run') + from_parent = greenlet.getcurrent().parent.switch('from g1_run') + results.append(('g1 from parent', from_parent)) + return 'g1 done' + +def g2_run(arg): + #g1.switch() + results.append(('g2 arg', arg)) + parent = greenlet.getcurrent().parent.switch('from g2_run') + global switch_to_g2 + switch_to_g2 = False + results.append(('g2 from parent', parent)) + return 'g2 done' + + +greenlet.settrace(tracefunc) + +g1 = greenlet.greenlet(g1_run) +g2 = greenlet.greenlet(g2_run) + +x = g1.switch('g1 from main') +results.append(('main g1', x)) +print('Back in main', x) +x = g1.switch('g2 from main') +results.append(('main g2', x)) +print('back in amain again', x) +x = g1.switch('g1 from main 2') +results.append(('main g1.2', x)) +x = g2.switch() +results.append(('main g2.2', x)) +print("RESULTS:", results) diff --git a/psets/9/finance/env/lib/python3.12/site-packages/greenlet/tests/fail_switch_two_greenlets.py b/psets/9/finance/env/lib/python3.12/site-packages/greenlet/tests/fail_switch_two_greenlets.py new file mode 100644 index 0000000..3e52345 --- /dev/null +++ b/psets/9/finance/env/lib/python3.12/site-packages/greenlet/tests/fail_switch_two_greenlets.py @@ -0,0 +1,41 @@ +""" +Uses a trace function to switch greenlets at unexpected times. + +In the trace function, we switch from the current greenlet to another +greenlet, which switches +""" +import greenlet + +g1 = None +g2 = None + +switch_to_g2 = False + +def tracefunc(*args): + print('TRACE', *args) + global switch_to_g2 + if switch_to_g2: + switch_to_g2 = False + g2.switch() + print('\tLEAVE TRACE', *args) + +def g1_run(): + print('In g1_run') + global switch_to_g2 + switch_to_g2 = True + greenlet.getcurrent().parent.switch() + print('Return to g1_run') + print('Falling off end of g1_run') + +def g2_run(): + g1.switch() + print('Falling off end of g2') + +greenlet.settrace(tracefunc) + +g1 = greenlet.greenlet(g1_run) +g2 = greenlet.greenlet(g2_run) + +g1.switch() +print('Falling off end of main') +g2.switch() diff --git a/psets/9/finance/env/lib/python3.12/site-packages/greenlet/tests/leakcheck.py b/psets/9/finance/env/lib/python3.12/site-packages/greenlet/tests/leakcheck.py new file mode 100644 index 0000000..a5152fb --- /dev/null +++ b/psets/9/finance/env/lib/python3.12/site-packages/greenlet/tests/leakcheck.py @@ -0,0 +1,319 @@ +# Copyright (c) 2018 gevent community +# Copyright (c) 2021 greenlet community +# +# This was originally part of gevent's test suite. The main author +# (Jason Madden) vendored a copy of it into greenlet. +# +# Permission is hereby granted, free of charge, to any person obtaining a copy +# of this software and associated documentation files (the "Software"), to deal +# in the Software without restriction, including without limitation the rights +# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +# copies of the Software, and to permit persons to whom the Software is +# furnished to do so, subject to the following conditions: +# +# The above copyright notice and this permission notice shall be included in +# all copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +# THE SOFTWARE. +from __future__ import print_function + +import os +import sys +import gc + +from functools import wraps +import unittest + + +import objgraph + +# graphviz 0.18 (Nov 7 2021), available only on Python 3.6 and newer, +# has added type hints (sigh). It wants to use ``typing.Literal`` for +# some stuff, but that's only available on Python 3.9+. If that's not +# found, it creates a ``unittest.mock.MagicMock`` object and annotates +# with that. These are GC'able objects, and doing almost *anything* +# with them results in an explosion of objects. For example, trying to +# compare them for equality creates new objects. This causes our +# leakchecks to fail, with reports like: +# +# greenlet.tests.leakcheck.LeakCheckError: refcount increased by [337, 1333, 343, 430, 530, 643, 769] +# _Call 1820 +546 +# dict 4094 +76 +# MagicProxy 585 +73 +# tuple 2693 +66 +# _CallList 24 +3 +# weakref 1441 +1 +# function 5996 +1 +# type 736 +1 +# cell 592 +1 +# MagicMock 8 +1 +# +# To avoid this, we *could* filter this type of object out early. In +# principle it could leak, but we don't use mocks in greenlet, so it +# doesn't leak from us. However, a further issue is that ``MagicMock`` +# objects have subobjects that are also GC'able, like ``_Call``, and +# those create new mocks of their own too. So we'd have to filter them +# as well, and they're not public. That's OK, we can workaround the +# problem by being very careful to never compare by equality or other +# user-defined operators, only using object identity or other builtin +# functions. + +RUNNING_ON_GITHUB_ACTIONS = os.environ.get('GITHUB_ACTIONS') +RUNNING_ON_TRAVIS = os.environ.get('TRAVIS') or RUNNING_ON_GITHUB_ACTIONS +RUNNING_ON_APPVEYOR = os.environ.get('APPVEYOR') +RUNNING_ON_CI = RUNNING_ON_TRAVIS or RUNNING_ON_APPVEYOR +RUNNING_ON_MANYLINUX = os.environ.get('GREENLET_MANYLINUX') +SKIP_LEAKCHECKS = RUNNING_ON_MANYLINUX or os.environ.get('GREENLET_SKIP_LEAKCHECKS') +SKIP_FAILING_LEAKCHECKS = os.environ.get('GREENLET_SKIP_FAILING_LEAKCHECKS') +ONLY_FAILING_LEAKCHECKS = os.environ.get('GREENLET_ONLY_FAILING_LEAKCHECKS') + +def ignores_leakcheck(func): + """ + Ignore the given object during leakchecks. + + Can be applied to a method, in which case the method will run, but + will not be subject to leak checks. + + If applied to a class, the entire class will be skipped during leakchecks. This + is intended to be used for classes that are very slow and cause problems such as + test timeouts; typically it will be used for classes that are subclasses of a base + class and specify variants of behaviour (such as pool sizes). + """ + func.ignore_leakcheck = True + return func + +def fails_leakcheck(func): + """ + Mark that the function is known to leak. + """ + func.fails_leakcheck = True + if SKIP_FAILING_LEAKCHECKS: + func = unittest.skip("Skipping known failures")(func) + return func + +class LeakCheckError(AssertionError): + pass + +if hasattr(sys, 'getobjects'): + # In a Python build with ``--with-trace-refs``, make objgraph + # trace *all* the objects, not just those that are tracked by the + # GC + class _MockGC(object): + def get_objects(self): + return sys.getobjects(0) # pylint:disable=no-member + def __getattr__(self, name): + return getattr(gc, name) + objgraph.gc = _MockGC() + fails_strict_leakcheck = fails_leakcheck +else: + def fails_strict_leakcheck(func): + """ + Decorator for a function that is known to fail when running + strict (``sys.getobjects()``) leakchecks. + + This type of leakcheck finds all objects, even those, such as + strings, which are not tracked by the garbage collector. + """ + return func + +class ignores_types_in_strict_leakcheck(object): + def __init__(self, types): + self.types = types + def __call__(self, func): + func.leakcheck_ignore_types = self.types + return func + +class _RefCountChecker(object): + + # Some builtin things that we ignore + # XXX: Those things were ignored by gevent, but they're important here, + # presumably. + IGNORED_TYPES = () #(tuple, dict, types.FrameType, types.TracebackType) + + def __init__(self, testcase, function): + self.testcase = testcase + self.function = function + self.deltas = [] + self.peak_stats = {} + self.ignored_types = () + + # The very first time we are called, we have already been + # self.setUp() by the test runner, so we don't need to do it again. + self.needs_setUp = False + + def _include_object_p(self, obj): + # pylint:disable=too-many-return-statements + # + # See the comment block at the top. We must be careful to + # avoid invoking user-defined operations. + if obj is self: + return False + kind = type(obj) + # ``self._include_object_p == obj`` returns NotImplemented + # for non-function objects, which causes the interpreter + # to try to reverse the order of arguments...which leads + # to the explosion of mock objects. We don't want that, so we implement + # the check manually. + if kind == type(self._include_object_p): + try: + # pylint:disable=not-callable + exact_method_equals = self._include_object_p.__eq__(obj) + except AttributeError: + # Python 2.7 methods may only have __cmp__, and that raises a + # TypeError for non-method arguments + # pylint:disable=no-member + exact_method_equals = self._include_object_p.__cmp__(obj) == 0 + + if exact_method_equals is not NotImplemented and exact_method_equals: + return False + + # Similarly, we need to check identity in our __dict__ to avoid mock explosions. + for x in self.__dict__.values(): + if obj is x: + return False + + + if kind in self.ignored_types or kind in self.IGNORED_TYPES: + return False + + return True + + def _growth(self): + return objgraph.growth(limit=None, peak_stats=self.peak_stats, + filter=self._include_object_p) + + def _report_diff(self, growth): + if not growth: + return "" + + lines = [] + width = max(len(name) for name, _, _ in growth) + for name, count, delta in growth: + lines.append('%-*s%9d %+9d' % (width, name, count, delta)) + + diff = '\n'.join(lines) + return diff + + + def _run_test(self, args, kwargs): + gc_enabled = gc.isenabled() + gc.disable() + + if self.needs_setUp: + self.testcase.setUp() + self.testcase.skipTearDown = False + try: + self.function(self.testcase, *args, **kwargs) + finally: + self.testcase.tearDown() + self.testcase.doCleanups() + self.testcase.skipTearDown = True + self.needs_setUp = True + if gc_enabled: + gc.enable() + + def _growth_after(self): + # Grab post snapshot + # pylint:disable=no-member + if 'urlparse' in sys.modules: + sys.modules['urlparse'].clear_cache() + if 'urllib.parse' in sys.modules: + sys.modules['urllib.parse'].clear_cache() + + return self._growth() + + def _check_deltas(self, growth): + # Return false when we have decided there is no leak, + # true if we should keep looping, raises an assertion + # if we have decided there is a leak. + + deltas = self.deltas + if not deltas: + # We haven't run yet, no data, keep looping + return True + + if gc.garbage: + raise LeakCheckError("Generated uncollectable garbage %r" % (gc.garbage,)) + + + # the following configurations are classified as "no leak" + # [0, 0] + # [x, 0, 0] + # [... a, b, c, d] where a+b+c+d = 0 + # + # the following configurations are classified as "leak" + # [... z, z, z] where z > 0 + + if deltas[-2:] == [0, 0] and len(deltas) in (2, 3): + return False + + if deltas[-3:] == [0, 0, 0]: + return False + + if len(deltas) >= 4 and sum(deltas[-4:]) == 0: + return False + + if len(deltas) >= 3 and deltas[-1] > 0 and deltas[-1] == deltas[-2] and deltas[-2] == deltas[-3]: + diff = self._report_diff(growth) + raise LeakCheckError('refcount increased by %r\n%s' % (deltas, diff)) + + # OK, we don't know for sure yet. Let's search for more + if sum(deltas[-3:]) <= 0 or sum(deltas[-4:]) <= 0 or deltas[-4:].count(0) >= 2: + # this is suspicious, so give a few more runs + limit = 11 + else: + limit = 7 + if len(deltas) >= limit: + raise LeakCheckError('refcount increased by %r\n%s' + % (deltas, + self._report_diff(growth))) + + # We couldn't decide yet, keep going + return True + + def __call__(self, args, kwargs): + for _ in range(3): + gc.collect() + + expect_failure = getattr(self.function, 'fails_leakcheck', False) + if expect_failure: + self.testcase.expect_greenlet_leak = True + self.ignored_types = getattr(self.function, "leakcheck_ignore_types", ()) + + # Capture state before; the incremental will be + # updated by each call to _growth_after + growth = self._growth() + + try: + while self._check_deltas(growth): + self._run_test(args, kwargs) + + growth = self._growth_after() + + self.deltas.append(sum((stat[2] for stat in growth))) + except LeakCheckError: + if not expect_failure: + raise + else: + if expect_failure: + raise LeakCheckError("Expected %s to leak but it did not." % (self.function,)) + +def wrap_refcount(method): + if getattr(method, 'ignore_leakcheck', False) or SKIP_LEAKCHECKS: + return method + + @wraps(method) + def wrapper(self, *args, **kwargs): # pylint:disable=too-many-branches + if getattr(self, 'ignore_leakcheck', False): + raise unittest.SkipTest("This class ignored during leakchecks") + if ONLY_FAILING_LEAKCHECKS and not getattr(method, 'fails_leakcheck', False): + raise unittest.SkipTest("Only running tests that fail leakchecks.") + return _RefCountChecker(self, method)(args, kwargs) + + return wrapper diff --git a/psets/9/finance/env/lib/python3.12/site-packages/greenlet/tests/test_contextvars.py b/psets/9/finance/env/lib/python3.12/site-packages/greenlet/tests/test_contextvars.py new file mode 100644 index 0000000..9a16f67 --- /dev/null +++ b/psets/9/finance/env/lib/python3.12/site-packages/greenlet/tests/test_contextvars.py @@ -0,0 +1,310 @@ +from __future__ import print_function + +import gc +import sys +import unittest + +from functools import partial +from unittest import skipUnless +from unittest import skipIf + +from greenlet import greenlet +from greenlet import getcurrent +from . import TestCase + + +try: + from contextvars import Context + from contextvars import ContextVar + from contextvars import copy_context + # From the documentation: + # + # Important: Context Variables should be created at the top module + # level and never in closures. Context objects hold strong + # references to context variables which prevents context variables + # from being properly garbage collected. + ID_VAR = ContextVar("id", default=None) + VAR_VAR = ContextVar("var", default=None) + ContextVar = None +except ImportError: + Context = ContextVar = copy_context = None + +# We don't support testing if greenlet's built-in context var support is disabled. +@skipUnless(Context is not None, "ContextVar not supported") +class ContextVarsTests(TestCase): + def _new_ctx_run(self, *args, **kwargs): + return copy_context().run(*args, **kwargs) + + def _increment(self, greenlet_id, callback, counts, expect): + ctx_var = ID_VAR + if expect is None: + self.assertIsNone(ctx_var.get()) + else: + self.assertEqual(ctx_var.get(), expect) + ctx_var.set(greenlet_id) + for _ in range(2): + counts[ctx_var.get()] += 1 + callback() + + def _test_context(self, propagate_by): + # pylint:disable=too-many-branches + ID_VAR.set(0) + + callback = getcurrent().switch + counts = dict((i, 0) for i in range(5)) + + lets = [ + greenlet(partial( + partial( + copy_context().run, + self._increment + ) if propagate_by == "run" else self._increment, + greenlet_id=i, + callback=callback, + counts=counts, + expect=( + i - 1 if propagate_by == "share" else + 0 if propagate_by in ("set", "run") else None + ) + )) + for i in range(1, 5) + ] + + for let in lets: + if propagate_by == "set": + let.gr_context = copy_context() + elif propagate_by == "share": + let.gr_context = getcurrent().gr_context + + for i in range(2): + counts[ID_VAR.get()] += 1 + for let in lets: + let.switch() + + if propagate_by == "run": + # Must leave each context.run() in reverse order of entry + for let in reversed(lets): + let.switch() + else: + # No context.run(), so fine to exit in any order. + for let in lets: + let.switch() + + for let in lets: + self.assertTrue(let.dead) + # When using run(), we leave the run() as the greenlet dies, + # and there's no context "underneath". When not using run(), + # gr_context still reflects the context the greenlet was + # running in. + if propagate_by == 'run': + self.assertIsNone(let.gr_context) + else: + self.assertIsNotNone(let.gr_context) + + + if propagate_by == "share": + self.assertEqual(counts, {0: 1, 1: 1, 2: 1, 3: 1, 4: 6}) + else: + self.assertEqual(set(counts.values()), set([2])) + + def test_context_propagated_by_context_run(self): + self._new_ctx_run(self._test_context, "run") + + def test_context_propagated_by_setting_attribute(self): + self._new_ctx_run(self._test_context, "set") + + def test_context_not_propagated(self): + self._new_ctx_run(self._test_context, None) + + def test_context_shared(self): + self._new_ctx_run(self._test_context, "share") + + def test_break_ctxvars(self): + let1 = greenlet(copy_context().run) + let2 = greenlet(copy_context().run) + let1.switch(getcurrent().switch) + let2.switch(getcurrent().switch) + # Since let2 entered the current context and let1 exits its own, the + # interpreter emits: + # RuntimeError: cannot exit context: thread state references a different context object + let1.switch() + + def test_not_broken_if_using_attribute_instead_of_context_run(self): + let1 = greenlet(getcurrent().switch) + let2 = greenlet(getcurrent().switch) + let1.gr_context = copy_context() + let2.gr_context = copy_context() + let1.switch() + let2.switch() + let1.switch() + let2.switch() + + def test_context_assignment_while_running(self): + # pylint:disable=too-many-statements + ID_VAR.set(None) + + def target(): + self.assertIsNone(ID_VAR.get()) + self.assertIsNone(gr.gr_context) + + # Context is created on first use + ID_VAR.set(1) + self.assertIsInstance(gr.gr_context, Context) + self.assertEqual(ID_VAR.get(), 1) + self.assertEqual(gr.gr_context[ID_VAR], 1) + + # Clearing the context makes it get re-created as another + # empty context when next used + old_context = gr.gr_context + gr.gr_context = None # assign None while running + self.assertIsNone(ID_VAR.get()) + self.assertIsNone(gr.gr_context) + ID_VAR.set(2) + self.assertIsInstance(gr.gr_context, Context) + self.assertEqual(ID_VAR.get(), 2) + self.assertEqual(gr.gr_context[ID_VAR], 2) + + new_context = gr.gr_context + getcurrent().parent.switch((old_context, new_context)) + # parent switches us back to old_context + + self.assertEqual(ID_VAR.get(), 1) + gr.gr_context = new_context # assign non-None while running + self.assertEqual(ID_VAR.get(), 2) + + getcurrent().parent.switch() + # parent switches us back to no context + self.assertIsNone(ID_VAR.get()) + self.assertIsNone(gr.gr_context) + gr.gr_context = old_context + self.assertEqual(ID_VAR.get(), 1) + + getcurrent().parent.switch() + # parent switches us back to no context + self.assertIsNone(ID_VAR.get()) + self.assertIsNone(gr.gr_context) + + gr = greenlet(target) + + with self.assertRaisesRegex(AttributeError, "can't delete context attribute"): + del gr.gr_context + + self.assertIsNone(gr.gr_context) + old_context, new_context = gr.switch() + self.assertIs(new_context, gr.gr_context) + self.assertEqual(old_context[ID_VAR], 1) + self.assertEqual(new_context[ID_VAR], 2) + self.assertEqual(new_context.run(ID_VAR.get), 2) + gr.gr_context = old_context # assign non-None while suspended + gr.switch() + self.assertIs(gr.gr_context, new_context) + gr.gr_context = None # assign None while suspended + gr.switch() + self.assertIs(gr.gr_context, old_context) + gr.gr_context = None + gr.switch() + self.assertIsNone(gr.gr_context) + + # Make sure there are no reference leaks + gr = None + gc.collect() + self.assertEqual(sys.getrefcount(old_context), 2) + self.assertEqual(sys.getrefcount(new_context), 2) + + def test_context_assignment_different_thread(self): + import threading + VAR_VAR.set(None) + ctx = Context() + + is_running = threading.Event() + should_suspend = threading.Event() + did_suspend = threading.Event() + should_exit = threading.Event() + holder = [] + + def greenlet_in_thread_fn(): + VAR_VAR.set(1) + is_running.set() + should_suspend.wait(10) + VAR_VAR.set(2) + getcurrent().parent.switch() + holder.append(VAR_VAR.get()) + + def thread_fn(): + gr = greenlet(greenlet_in_thread_fn) + gr.gr_context = ctx + holder.append(gr) + gr.switch() + did_suspend.set() + should_exit.wait(10) + gr.switch() + del gr + greenlet() # trigger cleanup + + thread = threading.Thread(target=thread_fn, daemon=True) + thread.start() + is_running.wait(10) + gr = holder[0] + + # Can't access or modify context if the greenlet is running + # in a different thread + with self.assertRaisesRegex(ValueError, "running in a different"): + getattr(gr, 'gr_context') + with self.assertRaisesRegex(ValueError, "running in a different"): + gr.gr_context = None + + should_suspend.set() + did_suspend.wait(10) + + # OK to access and modify context if greenlet is suspended + self.assertIs(gr.gr_context, ctx) + self.assertEqual(gr.gr_context[VAR_VAR], 2) + gr.gr_context = None + + should_exit.set() + thread.join(10) + + self.assertEqual(holder, [gr, None]) + + # Context can still be accessed/modified when greenlet is dead: + self.assertIsNone(gr.gr_context) + gr.gr_context = ctx + self.assertIs(gr.gr_context, ctx) + + # Otherwise we leak greenlets on some platforms. + # XXX: Should be able to do this automatically + del holder[:] + gr = None + thread = None + + def test_context_assignment_wrong_type(self): + g = greenlet() + with self.assertRaisesRegex(TypeError, + "greenlet context must be a contextvars.Context or None"): + g.gr_context = self + + +@skipIf(Context is not None, "ContextVar supported") +class NoContextVarsTests(TestCase): + def test_contextvars_errors(self): + let1 = greenlet(getcurrent().switch) + self.assertFalse(hasattr(let1, 'gr_context')) + with self.assertRaises(AttributeError): + getattr(let1, 'gr_context') + + with self.assertRaises(AttributeError): + let1.gr_context = None + + let1.switch() + + with self.assertRaises(AttributeError): + getattr(let1, 'gr_context') + + with self.assertRaises(AttributeError): + let1.gr_context = None + + del let1 + + +if __name__ == '__main__': + unittest.main() diff --git a/psets/9/finance/env/lib/python3.12/site-packages/greenlet/tests/test_cpp.py b/psets/9/finance/env/lib/python3.12/site-packages/greenlet/tests/test_cpp.py new file mode 100644 index 0000000..2d0cc9c --- /dev/null +++ b/psets/9/finance/env/lib/python3.12/site-packages/greenlet/tests/test_cpp.py @@ -0,0 +1,73 @@ +from __future__ import print_function +from __future__ import absolute_import + +import subprocess +import unittest + +import greenlet +from . import _test_extension_cpp +from . import TestCase +from . import WIN + +class CPPTests(TestCase): + def test_exception_switch(self): + greenlets = [] + for i in range(4): + g = greenlet.greenlet(_test_extension_cpp.test_exception_switch) + g.switch(i) + greenlets.append(g) + for i, g in enumerate(greenlets): + self.assertEqual(g.switch(), i) + + def _do_test_unhandled_exception(self, target): + import os + import sys + script = os.path.join( + os.path.dirname(__file__), + 'fail_cpp_exception.py', + ) + args = [sys.executable, script, target.__name__ if not isinstance(target, str) else target] + __traceback_info__ = args + with self.assertRaises(subprocess.CalledProcessError) as exc: + subprocess.check_output( + args, + encoding='utf-8', + stderr=subprocess.STDOUT + ) + + ex = exc.exception + expected_exit = self.get_expected_returncodes_for_aborted_process() + self.assertIn(ex.returncode, expected_exit) + self.assertIn('fail_cpp_exception is running', ex.output) + return ex.output + + + def test_unhandled_nonstd_exception_aborts(self): + # verify that plain unhandled throw aborts + self._do_test_unhandled_exception(_test_extension_cpp.test_exception_throw_nonstd) + + def test_unhandled_std_exception_aborts(self): + # verify that plain unhandled throw aborts + self._do_test_unhandled_exception(_test_extension_cpp.test_exception_throw_std) + + @unittest.skipIf(WIN, "XXX: This does not crash on Windows") + # Meaning the exception is getting lost somewhere... + def test_unhandled_std_exception_as_greenlet_function_aborts(self): + # verify that plain unhandled throw aborts + output = self._do_test_unhandled_exception('run_as_greenlet_target') + self.assertIn( + # We really expect this to be prefixed with "greenlet: Unhandled C++ exception:" + # as added by our handler for std::exception (see TUserGreenlet.cpp), but + # that's not correct everywhere --- our handler never runs before std::terminate + # gets called (for example, on arm32). + 'Thrown from an extension.', + output + ) + + def test_unhandled_exception_in_greenlet_aborts(self): + # verify that unhandled throw called in greenlet aborts too + self._do_test_unhandled_exception('run_unhandled_exception_in_greenlet_aborts') + + +if __name__ == '__main__': + unittest.main() diff --git a/psets/9/finance/env/lib/python3.12/site-packages/greenlet/tests/test_extension_interface.py b/psets/9/finance/env/lib/python3.12/site-packages/greenlet/tests/test_extension_interface.py new file mode 100644 index 0000000..34b6656 --- /dev/null +++ b/psets/9/finance/env/lib/python3.12/site-packages/greenlet/tests/test_extension_interface.py @@ -0,0 +1,115 @@ +from __future__ import print_function +from __future__ import absolute_import + +import sys + +import greenlet +from . import _test_extension +from . import TestCase + +# pylint:disable=c-extension-no-member + +class CAPITests(TestCase): + def test_switch(self): + self.assertEqual( + 50, _test_extension.test_switch(greenlet.greenlet(lambda: 50))) + + def test_switch_kwargs(self): + def adder(x, y): + return x * y + g = greenlet.greenlet(adder) + self.assertEqual(6, _test_extension.test_switch_kwargs(g, x=3, y=2)) + + def test_setparent(self): + # pylint:disable=disallowed-name + def foo(): + def bar(): + greenlet.getcurrent().parent.switch() + + # This final switch should go back to the main greenlet, since + # the test_setparent() function in the C extension should have + # reparented this greenlet. + greenlet.getcurrent().parent.switch() + raise AssertionError("Should never have reached this code") + child = greenlet.greenlet(bar) + child.switch() + greenlet.getcurrent().parent.switch(child) + greenlet.getcurrent().parent.throw( + AssertionError("Should never reach this code")) + foo_child = greenlet.greenlet(foo).switch() + self.assertEqual(None, _test_extension.test_setparent(foo_child)) + + def test_getcurrent(self): + _test_extension.test_getcurrent() + + def test_new_greenlet(self): + self.assertEqual(-15, _test_extension.test_new_greenlet(lambda: -15)) + + def test_raise_greenlet_dead(self): + self.assertRaises( + greenlet.GreenletExit, _test_extension.test_raise_dead_greenlet) + + def test_raise_greenlet_error(self): + self.assertRaises( + greenlet.error, _test_extension.test_raise_greenlet_error) + + def test_throw(self): + seen = [] + + def foo(): # pylint:disable=disallowed-name + try: + greenlet.getcurrent().parent.switch() + except ValueError: + seen.append(sys.exc_info()[1]) + except greenlet.GreenletExit: + raise AssertionError + g = greenlet.greenlet(foo) + g.switch() + _test_extension.test_throw(g) + self.assertEqual(len(seen), 1) + self.assertTrue( + isinstance(seen[0], ValueError), + "ValueError was not raised in foo()") + self.assertEqual( + str(seen[0]), + 'take that sucka!', + "message doesn't match") + + def test_non_traceback_param(self): + with self.assertRaises(TypeError) as exc: + _test_extension.test_throw_exact( + greenlet.getcurrent(), + Exception, + Exception(), + self + ) + self.assertEqual(str(exc.exception), + "throw() third argument must be a traceback object") + + def test_instance_of_wrong_type(self): + with self.assertRaises(TypeError) as exc: + _test_extension.test_throw_exact( + greenlet.getcurrent(), + Exception(), + BaseException(), + None, + ) + + self.assertEqual(str(exc.exception), + "instance exception may not have a separate value") + + def test_not_throwable(self): + with self.assertRaises(TypeError) as exc: + _test_extension.test_throw_exact( + greenlet.getcurrent(), + "abc", + None, + None, + ) + self.assertEqual(str(exc.exception), + "exceptions must be classes, or instances, not str") + + +if __name__ == '__main__': + import unittest + unittest.main() diff --git a/psets/9/finance/env/lib/python3.12/site-packages/greenlet/tests/test_gc.py b/psets/9/finance/env/lib/python3.12/site-packages/greenlet/tests/test_gc.py new file mode 100644 index 0000000..994addb --- /dev/null +++ b/psets/9/finance/env/lib/python3.12/site-packages/greenlet/tests/test_gc.py @@ -0,0 +1,86 @@ +import gc + +import weakref + +import greenlet + + +from . import TestCase +from .leakcheck import fails_leakcheck +# These only work with greenlet gc support +# which is no longer optional. +assert greenlet.GREENLET_USE_GC + +class GCTests(TestCase): + def test_dead_circular_ref(self): + o = weakref.ref(greenlet.greenlet(greenlet.getcurrent).switch()) + gc.collect() + if o() is not None: + import sys + print("O IS NOT NONE.", sys.getrefcount(o())) + self.assertIsNone(o()) + self.assertFalse(gc.garbage, gc.garbage) + + def test_circular_greenlet(self): + class circular_greenlet(greenlet.greenlet): + self = None + o = circular_greenlet() + o.self = o + o = weakref.ref(o) + gc.collect() + self.assertIsNone(o()) + self.assertFalse(gc.garbage, gc.garbage) + + def test_inactive_ref(self): + class inactive_greenlet(greenlet.greenlet): + def __init__(self): + greenlet.greenlet.__init__(self, run=self.run) + + def run(self): + pass + o = inactive_greenlet() + o = weakref.ref(o) + gc.collect() + self.assertIsNone(o()) + self.assertFalse(gc.garbage, gc.garbage) + + @fails_leakcheck + def test_finalizer_crash(self): + # This test is designed to crash when active greenlets + # are made garbage collectable, until the underlying + # problem is resolved. How does it work: + # - order of object creation is important + # - array is created first, so it is moved to unreachable first + # - we create a cycle between a greenlet and this array + # - we create an object that participates in gc, is only + # referenced by a greenlet, and would corrupt gc lists + # on destruction, the easiest is to use an object with + # a finalizer + # - because array is the first object in unreachable it is + # cleared first, which causes all references to greenlet + # to disappear and causes greenlet to be destroyed, but since + # it is still live it causes a switch during gc, which causes + # an object with finalizer to be destroyed, which causes stack + # corruption and then a crash + + class object_with_finalizer(object): + def __del__(self): + pass + array = [] + parent = greenlet.getcurrent() + def greenlet_body(): + greenlet.getcurrent().object = object_with_finalizer() + try: + parent.switch() + except greenlet.GreenletExit: + print("Got greenlet exit!") + finally: + del greenlet.getcurrent().object + g = greenlet.greenlet(greenlet_body) + g.array = array + array.append(g) + g.switch() + del array + del g + greenlet.getcurrent() + gc.collect() diff --git a/psets/9/finance/env/lib/python3.12/site-packages/greenlet/tests/test_generator.py b/psets/9/finance/env/lib/python3.12/site-packages/greenlet/tests/test_generator.py new file mode 100644 index 0000000..ca4a644 --- /dev/null +++ b/psets/9/finance/env/lib/python3.12/site-packages/greenlet/tests/test_generator.py @@ -0,0 +1,59 @@ + +from greenlet import greenlet + +from . import TestCase + +class genlet(greenlet): + parent = None + def __init__(self, *args, **kwds): + self.args = args + self.kwds = kwds + + def run(self): + fn, = self.fn + fn(*self.args, **self.kwds) + + def __iter__(self): + return self + + def __next__(self): + self.parent = greenlet.getcurrent() + result = self.switch() + if self: + return result + + raise StopIteration + + next = __next__ + + +def Yield(value): + g = greenlet.getcurrent() + while not isinstance(g, genlet): + if g is None: + raise RuntimeError('yield outside a genlet') + g = g.parent + g.parent.switch(value) + + +def generator(func): + class Generator(genlet): + fn = (func,) + return Generator + +# ____________________________________________________________ + + +class GeneratorTests(TestCase): + def test_generator(self): + seen = [] + + def g(n): + for i in range(n): + seen.append(i) + Yield(i) + g = generator(g) + for _ in range(3): + for j in g(5): + seen.append(j) + self.assertEqual(seen, 3 * [0, 0, 1, 1, 2, 2, 3, 3, 4, 4]) diff --git a/psets/9/finance/env/lib/python3.12/site-packages/greenlet/tests/test_generator_nested.py b/psets/9/finance/env/lib/python3.12/site-packages/greenlet/tests/test_generator_nested.py new file mode 100644 index 0000000..8d752a6 --- /dev/null +++ b/psets/9/finance/env/lib/python3.12/site-packages/greenlet/tests/test_generator_nested.py @@ -0,0 +1,168 @@ + +from greenlet import greenlet +from . import TestCase +from .leakcheck import fails_leakcheck + +class genlet(greenlet): + parent = None + def __init__(self, *args, **kwds): + self.args = args + self.kwds = kwds + self.child = None + + def run(self): + # Note the function is packed in a tuple + # to avoid creating a bound method for it. + fn, = self.fn + fn(*self.args, **self.kwds) + + def __iter__(self): + return self + + def set_child(self, child): + self.child = child + + def __next__(self): + if self.child: + child = self.child + while child.child: + tmp = child + child = child.child + tmp.child = None + + result = child.switch() + else: + self.parent = greenlet.getcurrent() + result = self.switch() + + if self: + return result + + raise StopIteration + + next = __next__ + +def Yield(value, level=1): + g = greenlet.getcurrent() + + while level != 0: + if not isinstance(g, genlet): + raise RuntimeError('yield outside a genlet') + if level > 1: + g.parent.set_child(g) + g = g.parent + level -= 1 + + g.switch(value) + + +def Genlet(func): + class TheGenlet(genlet): + fn = (func,) + return TheGenlet + +# ____________________________________________________________ + + +def g1(n, seen): + for i in range(n): + seen.append(i + 1) + yield i + + +def g2(n, seen): + for i in range(n): + seen.append(i + 1) + Yield(i) + +g2 = Genlet(g2) + + +def nested(i): + Yield(i) + + +def g3(n, seen): + for i in range(n): + seen.append(i + 1) + nested(i) +g3 = Genlet(g3) + + +def a(n): + if n == 0: + return + for ii in ax(n - 1): + Yield(ii) + Yield(n) +ax = Genlet(a) + + +def perms(l): + if len(l) > 1: + for e in l: + # No syntactical sugar for generator expressions + x = [Yield([e] + p) for p in perms([x for x in l if x != e])] + assert x + else: + Yield(l) +perms = Genlet(perms) + + +def gr1(n): + for ii in range(1, n): + Yield(ii) + Yield(ii * ii, 2) + +gr1 = Genlet(gr1) + + +def gr2(n, seen): + for ii in gr1(n): + seen.append(ii) + +gr2 = Genlet(gr2) + + +class NestedGeneratorTests(TestCase): + def test_layered_genlets(self): + seen = [] + for ii in gr2(5, seen): + seen.append(ii) + self.assertEqual(seen, [1, 1, 2, 4, 3, 9, 4, 16]) + + @fails_leakcheck + def test_permutations(self): + gen_perms = perms(list(range(4))) + permutations = list(gen_perms) + self.assertEqual(len(permutations), 4 * 3 * 2 * 1) + self.assertIn([0, 1, 2, 3], permutations) + self.assertIn([3, 2, 1, 0], permutations) + res = [] + for ii in zip(perms(list(range(4))), perms(list(range(3)))): + res.append(ii) + self.assertEqual( + res, + [([0, 1, 2, 3], [0, 1, 2]), ([0, 1, 3, 2], [0, 2, 1]), + ([0, 2, 1, 3], [1, 0, 2]), ([0, 2, 3, 1], [1, 2, 0]), + ([0, 3, 1, 2], [2, 0, 1]), ([0, 3, 2, 1], [2, 1, 0])]) + # XXX Test to make sure we are working as a generator expression + + def test_genlet_simple(self): + for g in g1, g2, g3: + seen = [] + for _ in range(3): + for j in g(5, seen): + seen.append(j) + self.assertEqual(seen, 3 * [1, 0, 2, 1, 3, 2, 4, 3, 5, 4]) + + def test_genlet_bad(self): + try: + Yield(10) + except RuntimeError: + pass + + def test_nested_genlets(self): + seen = [] + for ii in ax(5): + seen.append(ii) diff --git a/psets/9/finance/env/lib/python3.12/site-packages/greenlet/tests/test_greenlet.py b/psets/9/finance/env/lib/python3.12/site-packages/greenlet/tests/test_greenlet.py new file mode 100644 index 0000000..c4aabea --- /dev/null +++ b/psets/9/finance/env/lib/python3.12/site-packages/greenlet/tests/test_greenlet.py @@ -0,0 +1,1324 @@ +import gc +import sys +import time +import threading +import unittest + +from abc import ABCMeta +from abc import abstractmethod + +import greenlet +from greenlet import greenlet as RawGreenlet +from . import TestCase +from . import RUNNING_ON_MANYLINUX +from . import PY313 +from .leakcheck import fails_leakcheck + + +# We manually manage locks in many tests +# pylint:disable=consider-using-with +# pylint:disable=too-many-public-methods +# This module is quite large. +# TODO: Refactor into separate test files. For example, +# put all the regression tests that used to produce +# crashes in test_greenlet_no_crash; put tests that DO deliberately crash +# the interpreter into test_greenlet_crash. +# pylint:disable=too-many-lines + +class SomeError(Exception): + pass + + +def fmain(seen): + try: + greenlet.getcurrent().parent.switch() + except: + seen.append(sys.exc_info()[0]) + raise + raise SomeError + + +def send_exception(g, exc): + # note: send_exception(g, exc) can be now done with g.throw(exc). + # the purpose of this test is to explicitly check the propagation rules. + def crasher(exc): + raise exc + g1 = RawGreenlet(crasher, parent=g) + g1.switch(exc) + + +class TestGreenlet(TestCase): + + def _do_simple_test(self): + lst = [] + + def f(): + lst.append(1) + greenlet.getcurrent().parent.switch() + lst.append(3) + g = RawGreenlet(f) + lst.append(0) + g.switch() + lst.append(2) + g.switch() + lst.append(4) + self.assertEqual(lst, list(range(5))) + + def test_simple(self): + self._do_simple_test() + + def test_switch_no_run_raises_AttributeError(self): + g = RawGreenlet() + with self.assertRaises(AttributeError) as exc: + g.switch() + + self.assertIn("run", str(exc.exception)) + + def test_throw_no_run_raises_AttributeError(self): + g = RawGreenlet() + with self.assertRaises(AttributeError) as exc: + g.throw(SomeError) + + self.assertIn("run", str(exc.exception)) + + def test_parent_equals_None(self): + g = RawGreenlet(parent=None) + self.assertIsNotNone(g) + self.assertIs(g.parent, greenlet.getcurrent()) + + def test_run_equals_None(self): + g = RawGreenlet(run=None) + self.assertIsNotNone(g) + self.assertIsNone(g.run) + + def test_two_children(self): + lst = [] + + def f(): + lst.append(1) + greenlet.getcurrent().parent.switch() + lst.extend([1, 1]) + g = RawGreenlet(f) + h = RawGreenlet(f) + g.switch() + self.assertEqual(len(lst), 1) + h.switch() + self.assertEqual(len(lst), 2) + h.switch() + self.assertEqual(len(lst), 4) + self.assertEqual(h.dead, True) + g.switch() + self.assertEqual(len(lst), 6) + self.assertEqual(g.dead, True) + + def test_two_recursive_children(self): + lst = [] + + def f(): + lst.append('b') + greenlet.getcurrent().parent.switch() + + def g(): + lst.append('a') + g = RawGreenlet(f) + g.switch() + lst.append('c') + + g = RawGreenlet(g) + self.assertEqual(sys.getrefcount(g), 2) + g.switch() + self.assertEqual(lst, ['a', 'b', 'c']) + # Just the one in this frame, plus the one on the stack we pass to the function + self.assertEqual(sys.getrefcount(g), 2) + + def test_threads(self): + success = [] + + def f(): + self._do_simple_test() + success.append(True) + ths = [threading.Thread(target=f) for i in range(10)] + for th in ths: + th.start() + for th in ths: + th.join(10) + self.assertEqual(len(success), len(ths)) + + def test_exception(self): + seen = [] + g1 = RawGreenlet(fmain) + g2 = RawGreenlet(fmain) + g1.switch(seen) + g2.switch(seen) + g2.parent = g1 + + self.assertEqual(seen, []) + #with self.assertRaises(SomeError): + # p("***Switching back") + # g2.switch() + # Creating this as a bound method can reveal bugs that + # are hidden on newer versions of Python that avoid creating + # bound methods for direct expressions; IOW, don't use the `with` + # form! + self.assertRaises(SomeError, g2.switch) + self.assertEqual(seen, [SomeError]) + + value = g2.switch() + self.assertEqual(value, ()) + self.assertEqual(seen, [SomeError]) + + value = g2.switch(25) + self.assertEqual(value, 25) + self.assertEqual(seen, [SomeError]) + + + def test_send_exception(self): + seen = [] + g1 = RawGreenlet(fmain) + g1.switch(seen) + self.assertRaises(KeyError, send_exception, g1, KeyError) + self.assertEqual(seen, [KeyError]) + + def test_dealloc(self): + seen = [] + g1 = RawGreenlet(fmain) + g2 = RawGreenlet(fmain) + g1.switch(seen) + g2.switch(seen) + self.assertEqual(seen, []) + del g1 + gc.collect() + self.assertEqual(seen, [greenlet.GreenletExit]) + del g2 + gc.collect() + self.assertEqual(seen, [greenlet.GreenletExit, greenlet.GreenletExit]) + + def test_dealloc_catches_GreenletExit_throws_other(self): + def run(): + try: + greenlet.getcurrent().parent.switch() + except greenlet.GreenletExit: + raise SomeError from None + + g = RawGreenlet(run) + g.switch() + # Destroying the only reference to the greenlet causes it + # to get GreenletExit; when it in turn raises, even though we're the parent + # we don't get the exception, it just gets printed. + # When we run on 3.8 only, we can use sys.unraisablehook + oldstderr = sys.stderr + from io import StringIO + stderr = sys.stderr = StringIO() + try: + del g + finally: + sys.stderr = oldstderr + + v = stderr.getvalue() + self.assertIn("Exception", v) + self.assertIn('ignored', v) + self.assertIn("SomeError", v) + + + @unittest.skipIf( + PY313 and RUNNING_ON_MANYLINUX, + "Sometimes flaky (getting one GreenletExit in the second list)" + # Probably due to funky timing interactions? + # TODO: FIXME Make that work. + ) + + def test_dealloc_other_thread(self): + seen = [] + someref = [] + + bg_glet_created_running_and_no_longer_ref_in_bg = threading.Event() + fg_ref_released = threading.Event() + bg_should_be_clear = threading.Event() + ok_to_exit_bg_thread = threading.Event() + + def f(): + g1 = RawGreenlet(fmain) + g1.switch(seen) + someref.append(g1) + del g1 + gc.collect() + + bg_glet_created_running_and_no_longer_ref_in_bg.set() + fg_ref_released.wait(3) + + RawGreenlet() # trigger release + bg_should_be_clear.set() + ok_to_exit_bg_thread.wait(3) + RawGreenlet() # One more time + + t = threading.Thread(target=f) + t.start() + bg_glet_created_running_and_no_longer_ref_in_bg.wait(10) + + self.assertEqual(seen, []) + self.assertEqual(len(someref), 1) + del someref[:] + gc.collect() + # g1 is not released immediately because it's from another thread + self.assertEqual(seen, []) + fg_ref_released.set() + bg_should_be_clear.wait(3) + try: + self.assertEqual(seen, [greenlet.GreenletExit]) + finally: + ok_to_exit_bg_thread.set() + t.join(10) + del seen[:] + del someref[:] + + def test_frame(self): + def f1(): + f = sys._getframe(0) # pylint:disable=protected-access + self.assertEqual(f.f_back, None) + greenlet.getcurrent().parent.switch(f) + return "meaning of life" + g = RawGreenlet(f1) + frame = g.switch() + self.assertTrue(frame is g.gr_frame) + self.assertTrue(g) + + from_g = g.switch() + self.assertFalse(g) + self.assertEqual(from_g, 'meaning of life') + self.assertEqual(g.gr_frame, None) + + def test_thread_bug(self): + def runner(x): + g = RawGreenlet(lambda: time.sleep(x)) + g.switch() + t1 = threading.Thread(target=runner, args=(0.2,)) + t2 = threading.Thread(target=runner, args=(0.3,)) + t1.start() + t2.start() + t1.join(10) + t2.join(10) + + def test_switch_kwargs(self): + def run(a, b): + self.assertEqual(a, 4) + self.assertEqual(b, 2) + return 42 + x = RawGreenlet(run).switch(a=4, b=2) + self.assertEqual(x, 42) + + def test_switch_kwargs_to_parent(self): + def run(x): + greenlet.getcurrent().parent.switch(x=x) + greenlet.getcurrent().parent.switch(2, x=3) + return x, x ** 2 + g = RawGreenlet(run) + self.assertEqual({'x': 3}, g.switch(3)) + self.assertEqual(((2,), {'x': 3}), g.switch()) + self.assertEqual((3, 9), g.switch()) + + def test_switch_to_another_thread(self): + data = {} + created_event = threading.Event() + done_event = threading.Event() + + def run(): + data['g'] = RawGreenlet(lambda: None) + created_event.set() + done_event.wait(10) + thread = threading.Thread(target=run) + thread.start() + created_event.wait(10) + with self.assertRaises(greenlet.error): + data['g'].switch() + done_event.set() + thread.join(10) + # XXX: Should handle this automatically + data.clear() + + def test_exc_state(self): + def f(): + try: + raise ValueError('fun') + except: # pylint:disable=bare-except + exc_info = sys.exc_info() + RawGreenlet(h).switch() + self.assertEqual(exc_info, sys.exc_info()) + + def h(): + self.assertEqual(sys.exc_info(), (None, None, None)) + + RawGreenlet(f).switch() + + def test_instance_dict(self): + def f(): + greenlet.getcurrent().test = 42 + def deldict(g): + del g.__dict__ + def setdict(g, value): + g.__dict__ = value + g = RawGreenlet(f) + self.assertEqual(g.__dict__, {}) + g.switch() + self.assertEqual(g.test, 42) + self.assertEqual(g.__dict__, {'test': 42}) + g.__dict__ = g.__dict__ + self.assertEqual(g.__dict__, {'test': 42}) + self.assertRaises(TypeError, deldict, g) + self.assertRaises(TypeError, setdict, g, 42) + + def test_running_greenlet_has_no_run(self): + has_run = [] + def func(): + has_run.append( + hasattr(greenlet.getcurrent(), 'run') + ) + + g = RawGreenlet(func) + g.switch() + self.assertEqual(has_run, [False]) + + def test_deepcopy(self): + import copy + self.assertRaises(TypeError, copy.copy, RawGreenlet()) + self.assertRaises(TypeError, copy.deepcopy, RawGreenlet()) + + def test_parent_restored_on_kill(self): + hub = RawGreenlet(lambda: None) + main = greenlet.getcurrent() + result = [] + def worker(): + try: + # Wait to be killed by going back to the test. + main.switch() + except greenlet.GreenletExit: + # Resurrect and switch to parent + result.append(greenlet.getcurrent().parent) + result.append(greenlet.getcurrent()) + hub.switch() + g = RawGreenlet(worker, parent=hub) + g.switch() + # delete the only reference, thereby raising GreenletExit + del g + self.assertTrue(result) + self.assertIs(result[0], main) + self.assertIs(result[1].parent, hub) + # Delete them, thereby breaking the cycle between the greenlet + # and the frame, which otherwise would never be collectable + # XXX: We should be able to automatically fix this. + del result[:] + hub = None + main = None + + def test_parent_return_failure(self): + # No run causes AttributeError on switch + g1 = RawGreenlet() + # Greenlet that implicitly switches to parent + g2 = RawGreenlet(lambda: None, parent=g1) + # AttributeError should propagate to us, no fatal errors + with self.assertRaises(AttributeError): + g2.switch() + + def test_throw_exception_not_lost(self): + class mygreenlet(RawGreenlet): + def __getattribute__(self, name): + try: + raise Exception # pylint:disable=broad-exception-raised + except: # pylint:disable=bare-except + pass + return RawGreenlet.__getattribute__(self, name) + g = mygreenlet(lambda: None) + self.assertRaises(SomeError, g.throw, SomeError()) + + @fails_leakcheck + def _do_test_throw_to_dead_thread_doesnt_crash(self, wait_for_cleanup=False): + result = [] + def worker(): + greenlet.getcurrent().parent.switch() + + def creator(): + g = RawGreenlet(worker) + g.switch() + result.append(g) + if wait_for_cleanup: + # Let this greenlet eventually be cleaned up. + g.switch() + greenlet.getcurrent() + t = threading.Thread(target=creator) + t.start() + t.join(10) + del t + # But, depending on the operating system, the thread + # deallocator may not actually have run yet! So we can't be + # sure about the error message unless we wait. + if wait_for_cleanup: + self.wait_for_pending_cleanups() + with self.assertRaises(greenlet.error) as exc: + result[0].throw(SomeError) + + if not wait_for_cleanup: + s = str(exc.exception) + self.assertTrue( + s == "cannot switch to a different thread (which happens to have exited)" + or 'Cannot switch' in s + ) + else: + self.assertEqual( + str(exc.exception), + "cannot switch to a different thread (which happens to have exited)", + ) + + if hasattr(result[0].gr_frame, 'clear'): + # The frame is actually executing (it thinks), we can't clear it. + with self.assertRaises(RuntimeError): + result[0].gr_frame.clear() + # Unfortunately, this doesn't actually clear the references, they're in the + # fast local array. + if not wait_for_cleanup: + # f_locals has no clear method in Python 3.13 + if hasattr(result[0].gr_frame.f_locals, 'clear'): + result[0].gr_frame.f_locals.clear() + else: + self.assertIsNone(result[0].gr_frame) + + del creator + worker = None + del result[:] + # XXX: we ought to be able to automatically fix this. + # See issue 252 + self.expect_greenlet_leak = True # direct us not to wait for it to go away + + @fails_leakcheck + def test_throw_to_dead_thread_doesnt_crash(self): + self._do_test_throw_to_dead_thread_doesnt_crash() + + def test_throw_to_dead_thread_doesnt_crash_wait(self): + self._do_test_throw_to_dead_thread_doesnt_crash(True) + + @fails_leakcheck + def test_recursive_startup(self): + class convoluted(RawGreenlet): + def __init__(self): + RawGreenlet.__init__(self) + self.count = 0 + def __getattribute__(self, name): + if name == 'run' and self.count == 0: + self.count = 1 + self.switch(43) + return RawGreenlet.__getattribute__(self, name) + def run(self, value): + while True: + self.parent.switch(value) + g = convoluted() + self.assertEqual(g.switch(42), 43) + # Exits the running greenlet, otherwise it leaks + # XXX: We should be able to automatically fix this + #g.throw(greenlet.GreenletExit) + #del g + self.expect_greenlet_leak = True + + def test_threaded_updatecurrent(self): + # released when main thread should execute + lock1 = threading.Lock() + lock1.acquire() + # released when another thread should execute + lock2 = threading.Lock() + lock2.acquire() + class finalized(object): + def __del__(self): + # happens while in green_updatecurrent() in main greenlet + # should be very careful not to accidentally call it again + # at the same time we must make sure another thread executes + lock2.release() + lock1.acquire() + # now ts_current belongs to another thread + def deallocator(): + greenlet.getcurrent().parent.switch() + def fthread(): + lock2.acquire() + greenlet.getcurrent() + del g[0] + lock1.release() + lock2.acquire() + greenlet.getcurrent() + lock1.release() + main = greenlet.getcurrent() + g = [RawGreenlet(deallocator)] + g[0].bomb = finalized() + g[0].switch() + t = threading.Thread(target=fthread) + t.start() + # let another thread grab ts_current and deallocate g[0] + lock2.release() + lock1.acquire() + # this is the corner stone + # getcurrent() will notice that ts_current belongs to another thread + # and start the update process, which would notice that g[0] should + # be deallocated, and that will execute an object's finalizer. Now, + # that object will let another thread run so it can grab ts_current + # again, which would likely crash the interpreter if there's no + # check for this case at the end of green_updatecurrent(). This test + # passes if getcurrent() returns correct result, but it's likely + # to randomly crash if it's not anyway. + self.assertEqual(greenlet.getcurrent(), main) + # wait for another thread to complete, just in case + t.join(10) + + def test_dealloc_switch_args_not_lost(self): + seen = [] + def worker(): + # wait for the value + value = greenlet.getcurrent().parent.switch() + # delete all references to ourself + del worker[0] + initiator.parent = greenlet.getcurrent().parent + # switch to main with the value, but because + # ts_current is the last reference to us we + # return here immediately, where we resurrect ourself. + try: + greenlet.getcurrent().parent.switch(value) + finally: + seen.append(greenlet.getcurrent()) + def initiator(): + return 42 # implicitly falls thru to parent + + worker = [RawGreenlet(worker)] + + worker[0].switch() # prime worker + initiator = RawGreenlet(initiator, worker[0]) + value = initiator.switch() + self.assertTrue(seen) + self.assertEqual(value, 42) + + def test_tuple_subclass(self): + # The point of this test is to see what happens when a custom + # tuple subclass is used as an object passed directly to the C + # function ``green_switch``; part of ``green_switch`` checks + # the ``len()`` of the ``args`` tuple, and that can call back + # into Python. Here, when it calls back into Python, we + # recursively enter ``green_switch`` again. + + # This test is really only relevant on Python 2. The builtin + # `apply` function directly passes the given args tuple object + # to the underlying function, whereas the Python 3 version + # unpacks and repacks into an actual tuple. This could still + # happen using the C API on Python 3 though. We should write a + # builtin version of apply() ourself. + def _apply(func, a, k): + func(*a, **k) + + class mytuple(tuple): + def __len__(self): + greenlet.getcurrent().switch() + return tuple.__len__(self) + args = mytuple() + kwargs = dict(a=42) + def switchapply(): + _apply(greenlet.getcurrent().parent.switch, args, kwargs) + g = RawGreenlet(switchapply) + self.assertEqual(g.switch(), kwargs) + + def test_abstract_subclasses(self): + AbstractSubclass = ABCMeta( + 'AbstractSubclass', + (RawGreenlet,), + {'run': abstractmethod(lambda self: None)}) + + class BadSubclass(AbstractSubclass): + pass + + class GoodSubclass(AbstractSubclass): + def run(self): + pass + + GoodSubclass() # should not raise + self.assertRaises(TypeError, BadSubclass) + + def test_implicit_parent_with_threads(self): + if not gc.isenabled(): + return # cannot test with disabled gc + N = gc.get_threshold()[0] + if N < 50: + return # cannot test with such a small N + def attempt(): + lock1 = threading.Lock() + lock1.acquire() + lock2 = threading.Lock() + lock2.acquire() + recycled = [False] + def another_thread(): + lock1.acquire() # wait for gc + greenlet.getcurrent() # update ts_current + lock2.release() # release gc + t = threading.Thread(target=another_thread) + t.start() + class gc_callback(object): + def __del__(self): + lock1.release() + lock2.acquire() + recycled[0] = True + class garbage(object): + def __init__(self): + self.cycle = self + self.callback = gc_callback() + l = [] + x = range(N*2) + current = greenlet.getcurrent() + g = garbage() + for _ in x: + g = None # lose reference to garbage + if recycled[0]: + # gc callback called prematurely + t.join(10) + return False + last = RawGreenlet() + if recycled[0]: + break # yes! gc called in green_new + l.append(last) # increase allocation counter + else: + # gc callback not called when expected + gc.collect() + if recycled[0]: + t.join(10) + return False + self.assertEqual(last.parent, current) + for g in l: + self.assertEqual(g.parent, current) + return True + for _ in range(5): + if attempt(): + break + + def test_issue_245_reference_counting_subclass_no_threads(self): + # https://github.com/python-greenlet/greenlet/issues/245 + # Before the fix, this crashed pretty reliably on + # Python 3.10, at least on macOS; but much less reliably on other + # interpreters (memory layout must have changed). + # The threaded test crashed more reliably on more interpreters. + from greenlet import getcurrent + from greenlet import GreenletExit + + class Greenlet(RawGreenlet): + pass + + initial_refs = sys.getrefcount(Greenlet) + # This has to be an instance variable because + # Python 2 raises a SyntaxError if we delete a local + # variable referenced in an inner scope. + self.glets = [] # pylint:disable=attribute-defined-outside-init + + def greenlet_main(): + try: + getcurrent().parent.switch() + except GreenletExit: + self.glets.append(getcurrent()) + + # Before the + for _ in range(10): + Greenlet(greenlet_main).switch() + + del self.glets + self.assertEqual(sys.getrefcount(Greenlet), initial_refs) + + @unittest.skipIf( + PY313 and RUNNING_ON_MANYLINUX, + "The manylinux images appear to hang on this test on 3.13rc2" + # Or perhaps I just got tired of waiting for the 450s timeout. + # Still, it shouldn't take anywhere near that long. Does not reproduce in + # Ubuntu images, on macOS or Windows. + ) + def test_issue_245_reference_counting_subclass_threads(self): + # https://github.com/python-greenlet/greenlet/issues/245 + from threading import Thread + from threading import Event + + from greenlet import getcurrent + + class MyGreenlet(RawGreenlet): + pass + + glets = [] + ref_cleared = Event() + + def greenlet_main(): + getcurrent().parent.switch() + + def thread_main(greenlet_running_event): + mine = MyGreenlet(greenlet_main) + glets.append(mine) + # The greenlets being deleted must be active + mine.switch() + # Don't keep any reference to it in this thread + del mine + # Let main know we published our greenlet. + greenlet_running_event.set() + # Wait for main to let us know the references are + # gone and the greenlet objects no longer reachable + ref_cleared.wait(10) + # The creating thread must call getcurrent() (or a few other + # greenlet APIs) because that's when the thread-local list of dead + # greenlets gets cleared. + getcurrent() + + # We start with 3 references to the subclass: + # - This module + # - Its __mro__ + # - The __subclassess__ attribute of greenlet + # - (If we call gc.get_referents(), we find four entries, including + # some other tuple ``(greenlet)`` that I'm not sure about but must be part + # of the machinery.) + # + # On Python 3.10 it's often enough to just run 3 threads; on Python 2.7, + # more threads are needed, and the results are still + # non-deterministic. Presumably the memory layouts are different + initial_refs = sys.getrefcount(MyGreenlet) + thread_ready_events = [] + for _ in range( + initial_refs + 45 + ): + event = Event() + thread = Thread(target=thread_main, args=(event,)) + thread_ready_events.append(event) + thread.start() + + + for done_event in thread_ready_events: + done_event.wait(10) + + + del glets[:] + ref_cleared.set() + # Let any other thread run; it will crash the interpreter + # if not fixed (or silently corrupt memory and we possibly crash + # later). + self.wait_for_pending_cleanups() + self.assertEqual(sys.getrefcount(MyGreenlet), initial_refs) + + def test_falling_off_end_switches_to_unstarted_parent_raises_error(self): + def no_args(): + return 13 + + parent_never_started = RawGreenlet(no_args) + + def leaf(): + return 42 + + child = RawGreenlet(leaf, parent_never_started) + + # Because the run function takes to arguments + with self.assertRaises(TypeError): + child.switch() + + def test_falling_off_end_switches_to_unstarted_parent_works(self): + def one_arg(x): + return (x, 24) + + parent_never_started = RawGreenlet(one_arg) + + def leaf(): + return 42 + + child = RawGreenlet(leaf, parent_never_started) + + result = child.switch() + self.assertEqual(result, (42, 24)) + + def test_switch_to_dead_greenlet_with_unstarted_perverse_parent(self): + class Parent(RawGreenlet): + def __getattribute__(self, name): + if name == 'run': + raise SomeError + + + parent_never_started = Parent() + seen = [] + child = RawGreenlet(lambda: seen.append(42), parent_never_started) + # Because we automatically start the parent when the child is + # finished + with self.assertRaises(SomeError): + child.switch() + + self.assertEqual(seen, [42]) + + with self.assertRaises(SomeError): + child.switch() + self.assertEqual(seen, [42]) + + def test_switch_to_dead_greenlet_reparent(self): + seen = [] + parent_never_started = RawGreenlet(lambda: seen.append(24)) + child = RawGreenlet(lambda: seen.append(42)) + + child.switch() + self.assertEqual(seen, [42]) + + child.parent = parent_never_started + # This actually is the same as switching to the parent. + result = child.switch() + self.assertIsNone(result) + self.assertEqual(seen, [42, 24]) + + def test_can_access_f_back_of_suspended_greenlet(self): + # This tests our frame rewriting to work around Python 3.12+ having + # some interpreter frames on the C stack. It will crash in the absence + # of that logic. + main = greenlet.getcurrent() + + def outer(): + inner() + + def inner(): + main.switch(sys._getframe(0)) + + hub = RawGreenlet(outer) + # start it + hub.switch() + + # start another greenlet to make sure we aren't relying on + # anything in `hub` still being on the C stack + unrelated = RawGreenlet(lambda: None) + unrelated.switch() + + # now it is suspended + self.assertIsNotNone(hub.gr_frame) + self.assertEqual(hub.gr_frame.f_code.co_name, "inner") + self.assertIsNotNone(hub.gr_frame.f_back) + self.assertEqual(hub.gr_frame.f_back.f_code.co_name, "outer") + # The next line is what would crash + self.assertIsNone(hub.gr_frame.f_back.f_back) + + def test_get_stack_with_nested_c_calls(self): + from functools import partial + from . import _test_extension_cpp + + def recurse(v): + if v > 0: + return v * _test_extension_cpp.test_call(partial(recurse, v - 1)) + return greenlet.getcurrent().parent.switch() + + gr = RawGreenlet(recurse) + gr.switch(5) + frame = gr.gr_frame + for i in range(5): + self.assertEqual(frame.f_locals["v"], i) + frame = frame.f_back + self.assertEqual(frame.f_locals["v"], 5) + self.assertIsNone(frame.f_back) + self.assertEqual(gr.switch(10), 1200) # 1200 = 5! * 10 + + def test_frames_always_exposed(self): + # On Python 3.12 this will crash if we don't set the + # gr_frames_always_exposed attribute. More background: + # https://github.com/python-greenlet/greenlet/issues/388 + main = greenlet.getcurrent() + + def outer(): + inner(sys._getframe(0)) + + def inner(frame): + main.switch(frame) + + gr = RawGreenlet(outer) + frame = gr.switch() + + # Do something else to clobber the part of the C stack used by `gr`, + # so we can't skate by on "it just happened to still be there" + unrelated = RawGreenlet(lambda: None) + unrelated.switch() + + self.assertEqual(frame.f_code.co_name, "outer") + # The next line crashes on 3.12 if we haven't exposed the frames. + self.assertIsNone(frame.f_back) + + +class TestGreenletSetParentErrors(TestCase): + def test_threaded_reparent(self): + data = {} + created_event = threading.Event() + done_event = threading.Event() + + def run(): + data['g'] = RawGreenlet(lambda: None) + created_event.set() + done_event.wait(10) + + def blank(): + greenlet.getcurrent().parent.switch() + + thread = threading.Thread(target=run) + thread.start() + created_event.wait(10) + g = RawGreenlet(blank) + g.switch() + with self.assertRaises(ValueError) as exc: + g.parent = data['g'] + done_event.set() + thread.join(10) + + self.assertEqual(str(exc.exception), "parent cannot be on a different thread") + + def test_unexpected_reparenting(self): + another = [] + def worker(): + g = RawGreenlet(lambda: None) + another.append(g) + g.switch() + t = threading.Thread(target=worker) + t.start() + t.join(10) + # The first time we switch (running g_initialstub(), which is + # when we look up the run attribute) we attempt to change the + # parent to one from another thread (which also happens to be + # dead). ``g_initialstub()`` should detect this and raise a + # greenlet error. + # + # EXCEPT: With the fix for #252, this is actually detected + # sooner, when setting the parent itself. Prior to that fix, + # the main greenlet from the background thread kept a valid + # value for ``run_info``, and appeared to be a valid parent + # until we actually started the greenlet. But now that it's + # cleared, this test is catching whether ``green_setparent`` + # can detect the dead thread. + # + # Further refactoring once again changes this back to a greenlet.error + # + # We need to wait for the cleanup to happen, but we're + # deliberately leaking a main greenlet here. + self.wait_for_pending_cleanups(initial_main_greenlets=self.main_greenlets_before_test + 1) + + class convoluted(RawGreenlet): + def __getattribute__(self, name): + if name == 'run': + self.parent = another[0] # pylint:disable=attribute-defined-outside-init + return RawGreenlet.__getattribute__(self, name) + g = convoluted(lambda: None) + with self.assertRaises(greenlet.error) as exc: + g.switch() + self.assertEqual(str(exc.exception), + "cannot switch to a different thread (which happens to have exited)") + del another[:] + + def test_unexpected_reparenting_thread_running(self): + # Like ``test_unexpected_reparenting``, except the background thread is + # actually still alive. + another = [] + switched_to_greenlet = threading.Event() + keep_main_alive = threading.Event() + def worker(): + g = RawGreenlet(lambda: None) + another.append(g) + g.switch() + switched_to_greenlet.set() + keep_main_alive.wait(10) + class convoluted(RawGreenlet): + def __getattribute__(self, name): + if name == 'run': + self.parent = another[0] # pylint:disable=attribute-defined-outside-init + return RawGreenlet.__getattribute__(self, name) + + t = threading.Thread(target=worker) + t.start() + + switched_to_greenlet.wait(10) + try: + g = convoluted(lambda: None) + + with self.assertRaises(greenlet.error) as exc: + g.switch() + self.assertIn("Cannot switch to a different thread", str(exc.exception)) + self.assertIn("Expected", str(exc.exception)) + self.assertIn("Current", str(exc.exception)) + finally: + keep_main_alive.set() + t.join(10) + # XXX: Should handle this automatically. + del another[:] + + def test_cannot_delete_parent(self): + worker = RawGreenlet(lambda: None) + self.assertIs(worker.parent, greenlet.getcurrent()) + + with self.assertRaises(AttributeError) as exc: + del worker.parent + self.assertEqual(str(exc.exception), "can't delete attribute") + + def test_cannot_delete_parent_of_main(self): + with self.assertRaises(AttributeError) as exc: + del greenlet.getcurrent().parent + self.assertEqual(str(exc.exception), "can't delete attribute") + + + def test_main_greenlet_parent_is_none(self): + # assuming we're in a main greenlet here. + self.assertIsNone(greenlet.getcurrent().parent) + + def test_set_parent_wrong_types(self): + def bg(): + # Go back to main. + greenlet.getcurrent().parent.switch() + + def check(glet): + for p in None, 1, self, "42": + with self.assertRaises(TypeError) as exc: + glet.parent = p + + self.assertEqual( + str(exc.exception), + "GreenletChecker: Expected any type of greenlet, not " + type(p).__name__) + + # First, not running + g = RawGreenlet(bg) + self.assertFalse(g) + check(g) + + # Then when running. + g.switch() + self.assertTrue(g) + check(g) + + # Let it finish + g.switch() + + + def test_trivial_cycle(self): + glet = RawGreenlet(lambda: None) + with self.assertRaises(ValueError) as exc: + glet.parent = glet + self.assertEqual(str(exc.exception), "cyclic parent chain") + + def test_trivial_cycle_main(self): + # This used to produce a ValueError, but we catch it earlier than that now. + with self.assertRaises(AttributeError) as exc: + greenlet.getcurrent().parent = greenlet.getcurrent() + self.assertEqual(str(exc.exception), "cannot set the parent of a main greenlet") + + def test_deeper_cycle(self): + g1 = RawGreenlet(lambda: None) + g2 = RawGreenlet(lambda: None) + g3 = RawGreenlet(lambda: None) + + g1.parent = g2 + g2.parent = g3 + with self.assertRaises(ValueError) as exc: + g3.parent = g1 + self.assertEqual(str(exc.exception), "cyclic parent chain") + + +class TestRepr(TestCase): + + def assertEndsWith(self, got, suffix): + self.assertTrue(got.endswith(suffix), (got, suffix)) + + def test_main_while_running(self): + r = repr(greenlet.getcurrent()) + self.assertEndsWith(r, " current active started main>") + + def test_main_in_background(self): + main = greenlet.getcurrent() + def run(): + return repr(main) + + g = RawGreenlet(run) + r = g.switch() + self.assertEndsWith(r, ' suspended active started main>') + + def test_initial(self): + r = repr(RawGreenlet()) + self.assertEndsWith(r, ' pending>') + + def test_main_from_other_thread(self): + main = greenlet.getcurrent() + + class T(threading.Thread): + original_main = thread_main = None + main_glet = None + def run(self): + self.original_main = repr(main) + self.main_glet = greenlet.getcurrent() + self.thread_main = repr(self.main_glet) + + t = T() + t.start() + t.join(10) + + self.assertEndsWith(t.original_main, ' suspended active started main>') + self.assertEndsWith(t.thread_main, ' current active started main>') + # give the machinery time to notice the death of the thread, + # and clean it up. Note that we don't use + # ``expect_greenlet_leak`` or wait_for_pending_cleanups, + # because at this point we know we have an extra greenlet + # still reachable. + for _ in range(3): + time.sleep(0.001) + + # In the past, main greenlets, even from dead threads, never + # really appear dead. We have fixed that, and we also report + # that the thread is dead in the repr. (Do this multiple times + # to make sure that we don't self-modify and forget our state + # in the C++ code). + for _ in range(3): + self.assertTrue(t.main_glet.dead) + r = repr(t.main_glet) + self.assertEndsWith(r, ' (thread exited) dead>') + + def test_dead(self): + g = RawGreenlet(lambda: None) + g.switch() + self.assertEndsWith(repr(g), ' dead>') + self.assertNotIn('suspended', repr(g)) + self.assertNotIn('started', repr(g)) + self.assertNotIn('active', repr(g)) + + def test_formatting_produces_native_str(self): + # https://github.com/python-greenlet/greenlet/issues/218 + # %s formatting on Python 2 was producing unicode, not str. + + g_dead = RawGreenlet(lambda: None) + g_not_started = RawGreenlet(lambda: None) + g_cur = greenlet.getcurrent() + + for g in g_dead, g_not_started, g_cur: + + self.assertIsInstance( + '%s' % (g,), + str + ) + self.assertIsInstance( + '%r' % (g,), + str, + ) + + +class TestMainGreenlet(TestCase): + # Tests some implementation details, and relies on some + # implementation details. + + def _check_current_is_main(self): + # implementation detail + assert 'main' in repr(greenlet.getcurrent()) + + t = type(greenlet.getcurrent()) + assert 'main' not in repr(t) + return t + + def test_main_greenlet_type_can_be_subclassed(self): + main_type = self._check_current_is_main() + subclass = type('subclass', (main_type,), {}) + self.assertIsNotNone(subclass) + + def test_main_greenlet_is_greenlet(self): + self._check_current_is_main() + self.assertIsInstance(greenlet.getcurrent(), RawGreenlet) + + + +class TestBrokenGreenlets(TestCase): + # Tests for things that used to, or still do, terminate the interpreter. + # This often means doing unsavory things. + + def test_failed_to_initialstub(self): + def func(): + raise AssertionError("Never get here") + + + g = greenlet._greenlet.UnswitchableGreenlet(func) + g.force_switch_error = True + + with self.assertRaisesRegex(SystemError, + "Failed to switch stacks into a greenlet for the first time."): + g.switch() + + def test_failed_to_switch_into_running(self): + runs = [] + def func(): + runs.append(1) + greenlet.getcurrent().parent.switch() + runs.append(2) + greenlet.getcurrent().parent.switch() + runs.append(3) # pragma: no cover + + g = greenlet._greenlet.UnswitchableGreenlet(func) + g.switch() + self.assertEqual(runs, [1]) + g.switch() + self.assertEqual(runs, [1, 2]) + g.force_switch_error = True + + with self.assertRaisesRegex(SystemError, + "Failed to switch stacks into a running greenlet."): + g.switch() + + # If we stopped here, we would fail the leakcheck, because we've left + # the ``inner_bootstrap()`` C frame and its descendents hanging around, + # which have a bunch of Python references. They'll never get cleaned up + # if we don't let the greenlet finish. + g.force_switch_error = False + g.switch() + self.assertEqual(runs, [1, 2, 3]) + + def test_failed_to_slp_switch_into_running(self): + ex = self.assertScriptRaises('fail_slp_switch.py') + + self.assertIn('fail_slp_switch is running', ex.output) + self.assertIn(ex.returncode, self.get_expected_returncodes_for_aborted_process()) + + def test_reentrant_switch_two_greenlets(self): + # Before we started capturing the arguments in g_switch_finish, this could crash. + output = self.run_script('fail_switch_two_greenlets.py') + self.assertIn('In g1_run', output) + self.assertIn('TRACE', output) + self.assertIn('LEAVE TRACE', output) + self.assertIn('Falling off end of main', output) + self.assertIn('Falling off end of g1_run', output) + self.assertIn('Falling off end of g2', output) + + def test_reentrant_switch_three_greenlets(self): + # On debug builds of greenlet, this used to crash with an assertion error; + # on non-debug versions, it ran fine (which it should not do!). + # Now it always crashes correctly with a TypeError + ex = self.assertScriptRaises('fail_switch_three_greenlets.py', exitcodes=(1,)) + + self.assertIn('TypeError', ex.output) + self.assertIn('positional arguments', ex.output) + + def test_reentrant_switch_three_greenlets2(self): + # This actually passed on debug and non-debug builds. It + # should probably have been triggering some debug assertions + # but it didn't. + # + # I think the fixes for the above test also kicked in here. + output = self.run_script('fail_switch_three_greenlets2.py') + self.assertIn( + "RESULTS: [('trace', 'switch'), " + "('trace', 'switch'), ('g2 arg', 'g2 from tracefunc'), " + "('trace', 'switch'), ('main g1', 'from g2_run'), ('trace', 'switch'), " + "('g1 arg', 'g1 from main'), ('trace', 'switch'), ('main g2', 'from g1_run'), " + "('trace', 'switch'), ('g1 from parent', 'g1 from main 2'), ('trace', 'switch'), " + "('main g1.2', 'g1 done'), ('trace', 'switch'), ('g2 from parent', ()), " + "('trace', 'switch'), ('main g2.2', 'g2 done')]", + output + ) + + def test_reentrant_switch_GreenletAlreadyStartedInPython(self): + output = self.run_script('fail_initialstub_already_started.py') + + self.assertIn( + "RESULTS: ['Begin C', 'Switch to b from B.__getattribute__ in C', " + "('Begin B', ()), '_B_run switching to main', ('main from c', 'From B'), " + "'B.__getattribute__ back from main in C', ('Begin A', (None,)), " + "('A dead?', True, 'B dead?', True, 'C dead?', False), " + "'C done', ('main from c.2', None)]", + output + ) + + def test_reentrant_switch_run_callable_has_del(self): + output = self.run_script('fail_clearing_run_switches.py') + self.assertIn( + "RESULTS [" + "('G.__getattribute__', 'run'), ('RunCallable', '__del__'), " + "('main: g.switch()', 'from RunCallable'), ('run_func', 'enter')" + "]", + output + ) + +if __name__ == '__main__': + unittest.main() diff --git a/psets/9/finance/env/lib/python3.12/site-packages/greenlet/tests/test_greenlet_trash.py b/psets/9/finance/env/lib/python3.12/site-packages/greenlet/tests/test_greenlet_trash.py new file mode 100644 index 0000000..c1fc137 --- /dev/null +++ b/psets/9/finance/env/lib/python3.12/site-packages/greenlet/tests/test_greenlet_trash.py @@ -0,0 +1,187 @@ +# -*- coding: utf-8 -*- +""" +Tests for greenlets interacting with the CPython trash can API. + +The CPython trash can API is not designed to be re-entered from a +single thread. But this can happen using greenlets, if something +during the object deallocation process switches greenlets, and this second +greenlet then causes the trash can to get entered again. Here, we do this +very explicitly, but in other cases (like gevent) it could be arbitrarily more +complicated: for example, a weakref callback might try to acquire a lock that's +already held by another greenlet; that would allow a greenlet switch to occur. + +See https://github.com/gevent/gevent/issues/1909 + +This test is fragile and relies on details of the CPython +implementation (like most of the rest of this package): + + - We enter the trashcan and deferred deallocation after + ``_PyTrash_UNWIND_LEVEL`` calls. This constant, defined in + CPython's object.c, is generally 50. That's basically how many objects are required to + get us into the deferred deallocation situation. + + - The test fails by hitting an ``assert()`` in object.c; if the + build didn't enable assert, then we don't catch this. + + - If the test fails in that way, the interpreter crashes. +""" +from __future__ import print_function, absolute_import, division + +import unittest + + +class TestTrashCanReEnter(unittest.TestCase): + + def test_it(self): + try: + # pylint:disable-next=no-name-in-module + from greenlet._greenlet import get_tstate_trash_delete_nesting # pylint:disable=unused-import + except ImportError: + import sys + # Python 3.13 has not "trash delete nesting" anymore (but "delete later") + assert sys.version_info[:2] >= (3, 13) + self.skipTest("get_tstate_trash_delete_nesting is not available.") + + # Try several times to trigger it, because it isn't 100% + # reliable. + for _ in range(10): + self.check_it() + + def check_it(self): # pylint:disable=too-many-statements + import greenlet + from greenlet._greenlet import get_tstate_trash_delete_nesting # pylint:disable=no-name-in-module + main = greenlet.getcurrent() + + assert get_tstate_trash_delete_nesting() == 0 + + # We expect to be in deferred deallocation after this many + # deallocations have occurred. TODO: I wish we had a better way to do + # this --- that was before get_tstate_trash_delete_nesting; perhaps + # we can use that API to do better? + TRASH_UNWIND_LEVEL = 50 + # How many objects to put in a container; it's the container that + # queues objects for deferred deallocation. + OBJECTS_PER_CONTAINER = 500 + + class Dealloc: # define the class here because we alter class variables each time we run. + """ + An object with a ``__del__`` method. When it starts getting deallocated + from a deferred trash can run, it switches greenlets, allocates more objects + which then also go in the trash can. If we don't save state appropriately, + nesting gets out of order and we can crash the interpreter. + """ + + #: Has our deallocation actually run and switched greenlets? + #: When it does, this will be set to the current greenlet. This should + #: be happening in the main greenlet, so we check that down below. + SPAWNED = False + + #: Has the background greenlet run? + BG_RAN = False + + BG_GLET = None + + #: How many of these things have ever been allocated. + CREATED = 0 + + #: How many of these things have ever been deallocated. + DESTROYED = 0 + + #: How many were destroyed not in the main greenlet. There should always + #: be some. + #: If the test is broken or things change in the trashcan implementation, + #: this may not be correct. + DESTROYED_BG = 0 + + def __init__(self, sequence_number): + """ + :param sequence_number: The ordinal of this object during + one particular creation run. This is used to detect (guess, really) + when we have entered the trash can's deferred deallocation. + """ + self.i = sequence_number + Dealloc.CREATED += 1 + + def __del__(self): + if self.i == TRASH_UNWIND_LEVEL and not self.SPAWNED: + Dealloc.SPAWNED = greenlet.getcurrent() + other = Dealloc.BG_GLET = greenlet.greenlet(background_greenlet) + x = other.switch() + assert x == 42 + # It's important that we don't switch back to the greenlet, + # we leave it hanging there in an incomplete state. But we don't let it + # get collected, either. If we complete it now, while we're still + # in the scope of the initial trash can, things work out and we + # don't see the problem. We need this greenlet to complete + # at some point in the future, after we've exited this trash can invocation. + del other + elif self.i == 40 and greenlet.getcurrent() is not main: + Dealloc.BG_RAN = True + try: + main.switch(42) + except greenlet.GreenletExit as ex: + # We expect this; all references to us go away + # while we're still running, and we need to finish deleting + # ourself. + Dealloc.BG_RAN = type(ex) + del ex + + # Record the fact that we're dead last of all. This ensures that + # we actually get returned too. + Dealloc.DESTROYED += 1 + if greenlet.getcurrent() is not main: + Dealloc.DESTROYED_BG += 1 + + + def background_greenlet(): + # We direct through a second function, instead of + # directly calling ``make_some()``, so that we have complete + # control over when these objects are destroyed: we need them + # to be destroyed in the context of the background greenlet + t = make_some() + del t # Triggere deletion. + + def make_some(): + t = () + i = OBJECTS_PER_CONTAINER + while i: + # Nest the tuples; it's the recursion that gets us + # into trash. + t = (Dealloc(i), t) + i -= 1 + return t + + + some = make_some() + self.assertEqual(Dealloc.CREATED, OBJECTS_PER_CONTAINER) + self.assertEqual(Dealloc.DESTROYED, 0) + + # If we're going to crash, it should be on the following line. + # We only crash if ``assert()`` is enabled, of course. + del some + + # For non-debug builds of CPython, we won't crash. The best we can do is check + # the nesting level explicitly. + self.assertEqual(0, get_tstate_trash_delete_nesting()) + + # Discard this, raising GreenletExit into where it is waiting. + Dealloc.BG_GLET = None + # The same nesting level maintains. + self.assertEqual(0, get_tstate_trash_delete_nesting()) + + # We definitely cleaned some up in the background + self.assertGreater(Dealloc.DESTROYED_BG, 0) + + # Make sure all the cleanups happened. + self.assertIs(Dealloc.SPAWNED, main) + self.assertTrue(Dealloc.BG_RAN) + self.assertEqual(Dealloc.BG_RAN, greenlet.GreenletExit) + self.assertEqual(Dealloc.CREATED, Dealloc.DESTROYED ) + self.assertEqual(Dealloc.CREATED, OBJECTS_PER_CONTAINER * 2) + + import gc + gc.collect() + + +if __name__ == '__main__': + unittest.main() diff --git a/psets/9/finance/env/lib/python3.12/site-packages/greenlet/tests/test_leaks.py b/psets/9/finance/env/lib/python3.12/site-packages/greenlet/tests/test_leaks.py new file mode 100644 index 0000000..ed1fa71 --- /dev/null +++ b/psets/9/finance/env/lib/python3.12/site-packages/greenlet/tests/test_leaks.py @@ -0,0 +1,443 @@ +# -*- coding: utf-8 -*- +""" +Testing scenarios that may have leaked. +""" +from __future__ import print_function, absolute_import, division + +import sys +import gc + +import time +import weakref +import threading + + +import greenlet +from . import TestCase +from .leakcheck import fails_leakcheck +from .leakcheck import ignores_leakcheck +from .leakcheck import RUNNING_ON_MANYLINUX + +# pylint:disable=protected-access + +assert greenlet.GREENLET_USE_GC # Option to disable this was removed in 1.0 + +class HasFinalizerTracksInstances(object): + EXTANT_INSTANCES = set() + def __init__(self, msg): + self.msg = sys.intern(msg) + self.EXTANT_INSTANCES.add(id(self)) + def __del__(self): + self.EXTANT_INSTANCES.remove(id(self)) + def __repr__(self): + return "" % ( + id(self), self.msg + ) + @classmethod + def reset(cls): + cls.EXTANT_INSTANCES.clear() + + +class TestLeaks(TestCase): + + def test_arg_refs(self): + args = ('a', 'b', 'c') + refcount_before = sys.getrefcount(args) + # pylint:disable=unnecessary-lambda + g = greenlet.greenlet( + lambda *args: greenlet.getcurrent().parent.switch(*args)) + for _ in range(100): + g.switch(*args) + self.assertEqual(sys.getrefcount(args), refcount_before) + + def test_kwarg_refs(self): + kwargs = {} + # pylint:disable=unnecessary-lambda + g = greenlet.greenlet( + lambda **kwargs: greenlet.getcurrent().parent.switch(**kwargs)) + for _ in range(100): + g.switch(**kwargs) + self.assertEqual(sys.getrefcount(kwargs), 2) + + + @staticmethod + def __recycle_threads(): + # By introducing a thread that does sleep we allow other threads, + # that have triggered their __block condition, but did not have a + # chance to deallocate their thread state yet, to finally do so. + # The way it works is by requiring a GIL switch (different thread), + # which does a GIL release (sleep), which might do a GIL switch + # to finished threads and allow them to clean up. + def worker(): + time.sleep(0.001) + t = threading.Thread(target=worker) + t.start() + time.sleep(0.001) + t.join(10) + + def test_threaded_leak(self): + gg = [] + def worker(): + # only main greenlet present + gg.append(weakref.ref(greenlet.getcurrent())) + for _ in range(2): + t = threading.Thread(target=worker) + t.start() + t.join(10) + del t + greenlet.getcurrent() # update ts_current + self.__recycle_threads() + greenlet.getcurrent() # update ts_current + gc.collect() + greenlet.getcurrent() # update ts_current + for g in gg: + self.assertIsNone(g()) + + def test_threaded_adv_leak(self): + gg = [] + def worker(): + # main and additional *finished* greenlets + ll = greenlet.getcurrent().ll = [] + def additional(): + ll.append(greenlet.getcurrent()) + for _ in range(2): + greenlet.greenlet(additional).switch() + gg.append(weakref.ref(greenlet.getcurrent())) + for _ in range(2): + t = threading.Thread(target=worker) + t.start() + t.join(10) + del t + greenlet.getcurrent() # update ts_current + self.__recycle_threads() + greenlet.getcurrent() # update ts_current + gc.collect() + greenlet.getcurrent() # update ts_current + for g in gg: + self.assertIsNone(g()) + + def assertClocksUsed(self): + used = greenlet._greenlet.get_clocks_used_doing_optional_cleanup() + self.assertGreaterEqual(used, 0) + # we don't lose the value + greenlet._greenlet.enable_optional_cleanup(True) + used2 = greenlet._greenlet.get_clocks_used_doing_optional_cleanup() + self.assertEqual(used, used2) + self.assertGreater(greenlet._greenlet.CLOCKS_PER_SEC, 1) + + def _check_issue251(self, + manually_collect_background=True, + explicit_reference_to_switch=False): + # See https://github.com/python-greenlet/greenlet/issues/251 + # Killing a greenlet (probably not the main one) + # in one thread from another thread would + # result in leaking a list (the ts_delkey list). + # We no longer use lists to hold that stuff, though. + + # For the test to be valid, even empty lists have to be tracked by the + # GC + + assert gc.is_tracked([]) + HasFinalizerTracksInstances.reset() + greenlet.getcurrent() + greenlets_before = self.count_objects(greenlet.greenlet, exact_kind=False) + + background_glet_running = threading.Event() + background_glet_killed = threading.Event() + background_greenlets = [] + + # XXX: Switching this to a greenlet subclass that overrides + # run results in all callers failing the leaktest; that + # greenlet instance is leaked. There's a bound method for + # run() living on the stack of the greenlet in g_initialstub, + # and since we don't manually switch back to the background + # greenlet to let it "fall off the end" and exit the + # g_initialstub function, it never gets cleaned up. Making the + # garbage collector aware of this bound method (making it an + # attribute of the greenlet structure and traversing into it) + # doesn't help, for some reason. + def background_greenlet(): + # Throw control back to the main greenlet. + jd = HasFinalizerTracksInstances("DELETING STACK OBJECT") + greenlet._greenlet.set_thread_local( + 'test_leaks_key', + HasFinalizerTracksInstances("DELETING THREAD STATE")) + # Explicitly keeping 'switch' in a local variable + # breaks this test in all versions + if explicit_reference_to_switch: + s = greenlet.getcurrent().parent.switch + s([jd]) + else: + greenlet.getcurrent().parent.switch([jd]) + + bg_main_wrefs = [] + + def background_thread(): + glet = greenlet.greenlet(background_greenlet) + bg_main_wrefs.append(weakref.ref(glet.parent)) + + background_greenlets.append(glet) + glet.switch() # Be sure it's active. + # Control is ours again. + del glet # Delete one reference from the thread it runs in. + background_glet_running.set() + background_glet_killed.wait(10) + + # To trigger the background collection of the dead + # greenlet, thus clearing out the contents of the list, we + # need to run some APIs. See issue 252. + if manually_collect_background: + greenlet.getcurrent() + + + t = threading.Thread(target=background_thread) + t.start() + background_glet_running.wait(10) + greenlet.getcurrent() + lists_before = self.count_objects(list, exact_kind=True) + + assert len(background_greenlets) == 1 + self.assertFalse(background_greenlets[0].dead) + # Delete the last reference to the background greenlet + # from a different thread. This puts it in the background thread's + # ts_delkey list. + del background_greenlets[:] + background_glet_killed.set() + + # Now wait for the background thread to die. + t.join(10) + del t + # As part of the fix for 252, we need to cycle the ceval.c + # interpreter loop to be sure it has had a chance to process + # the pending call. + self.wait_for_pending_cleanups() + + lists_after = self.count_objects(list, exact_kind=True) + greenlets_after = self.count_objects(greenlet.greenlet, exact_kind=False) + + # On 2.7, we observe that lists_after is smaller than + # lists_before. No idea what lists got cleaned up. All the + # Python 3 versions match exactly. + self.assertLessEqual(lists_after, lists_before) + # On versions after 3.6, we've successfully cleaned up the + # greenlet references thanks to the internal "vectorcall" + # protocol; prior to that, there is a reference path through + # the ``greenlet.switch`` method still on the stack that we + # can't reach to clean up. The C code goes through terrific + # lengths to clean that up. + if not explicit_reference_to_switch \ + and greenlet._greenlet.get_clocks_used_doing_optional_cleanup() is not None: + # If cleanup was disabled, though, we may not find it. + self.assertEqual(greenlets_after, greenlets_before) + if manually_collect_background: + # TODO: Figure out how to make this work! + # The one on the stack is still leaking somehow + # in the non-manually-collect state. + self.assertEqual(HasFinalizerTracksInstances.EXTANT_INSTANCES, set()) + else: + # The explicit reference prevents us from collecting it + # and it isn't always found by the GC either for some + # reason. The entire frame is leaked somehow, on some + # platforms (e.g., MacPorts builds of Python (all + # versions!)), but not on other platforms (the linux and + # windows builds on GitHub actions and Appveyor). So we'd + # like to write a test that proves that the main greenlet + # sticks around, and we can on my machine (macOS 11.6, + # MacPorts builds of everything) but we can't write that + # same test on other platforms. However, hopefully iteration + # done by leakcheck will find it. + pass + + if greenlet._greenlet.get_clocks_used_doing_optional_cleanup() is not None: + self.assertClocksUsed() + + def test_issue251_killing_cross_thread_leaks_list(self): + self._check_issue251() + + def test_issue251_with_cleanup_disabled(self): + greenlet._greenlet.enable_optional_cleanup(False) + try: + self._check_issue251() + finally: + greenlet._greenlet.enable_optional_cleanup(True) + + @fails_leakcheck + def test_issue251_issue252_need_to_collect_in_background(self): + # Between greenlet 1.1.2 and the next version, this was still + # failing because the leak of the list still exists when we + # don't call a greenlet API before exiting the thread. The + # proximate cause is that neither of the two greenlets from + # the background thread are actually being destroyed, even + # though the GC is in fact visiting both objects. It's not + # clear where that leak is? For some reason the thread-local + # dict holding it isn't being cleaned up. + # + # The leak, I think, is in the CPYthon internal function that + # calls into green_switch(). The argument tuple is still on + # the C stack somewhere and can't be reached? That doesn't + # make sense, because the tuple should be collectable when + # this object goes away. + # + # Note that this test sometimes spuriously passes on Linux, + # for some reason, but I've never seen it pass on macOS. + self._check_issue251(manually_collect_background=False) + + @fails_leakcheck + def test_issue251_issue252_need_to_collect_in_background_cleanup_disabled(self): + self.expect_greenlet_leak = True + greenlet._greenlet.enable_optional_cleanup(False) + try: + self._check_issue251(manually_collect_background=False) + finally: + greenlet._greenlet.enable_optional_cleanup(True) + + @fails_leakcheck + def test_issue251_issue252_explicit_reference_not_collectable(self): + self._check_issue251( + manually_collect_background=False, + explicit_reference_to_switch=True) + + UNTRACK_ATTEMPTS = 100 + + def _only_test_some_versions(self): + # We're only looking for this problem specifically on 3.11, + # and this set of tests is relatively fragile, depending on + # OS and memory management details. So we want to run it on 3.11+ + # (obviously) but not every older 3.x version in order to reduce + # false negatives. At the moment, those false results seem to have + # resolved, so we are actually running this on 3.8+ + assert sys.version_info[0] >= 3 + if sys.version_info[:2] < (3, 8): + self.skipTest('Only observed on 3.11') + if RUNNING_ON_MANYLINUX: + self.skipTest("Slow and not worth repeating here") + + @ignores_leakcheck + # Because we're just trying to track raw memory, not objects, and running + # the leakcheck makes an already slow test slower. + def test_untracked_memory_doesnt_increase(self): + # See https://github.com/gevent/gevent/issues/1924 + # and https://github.com/python-greenlet/greenlet/issues/328 + self._only_test_some_versions() + def f(): + return 1 + + ITER = 10000 + def run_it(): + for _ in range(ITER): + greenlet.greenlet(f).switch() + + # Establish baseline + for _ in range(3): + run_it() + + # uss: (Linux, macOS, Windows): aka "Unique Set Size", this is + # the memory which is unique to a process and which would be + # freed if the process was terminated right now. + uss_before = self.get_process_uss() + + for count in range(self.UNTRACK_ATTEMPTS): + uss_before = max(uss_before, self.get_process_uss()) + run_it() + + uss_after = self.get_process_uss() + if uss_after <= uss_before and count > 1: + break + + self.assertLessEqual(uss_after, uss_before) + + def _check_untracked_memory_thread(self, deallocate_in_thread=True): + self._only_test_some_versions() + # Like the above test, but what if there are a bunch of + # unfinished greenlets in a thread that dies? + # Does it matter if we deallocate in the thread or not? + EXIT_COUNT = [0] + + def f(): + try: + greenlet.getcurrent().parent.switch() + except greenlet.GreenletExit: + EXIT_COUNT[0] += 1 + raise + return 1 + + ITER = 10000 + def run_it(): + glets = [] + for _ in range(ITER): + # Greenlet starts, switches back to us. + # We keep a strong reference to the greenlet though so it doesn't + # get a GreenletExit exception. + g = greenlet.greenlet(f) + glets.append(g) + g.switch() + + return glets + + test = self + + class ThreadFunc: + uss_before = uss_after = 0 + glets = () + ITER = 2 + def __call__(self): + self.uss_before = test.get_process_uss() + + for _ in range(self.ITER): + self.glets += tuple(run_it()) + + for g in self.glets: + test.assertIn('suspended active', str(g)) + # Drop them. + if deallocate_in_thread: + self.glets = () + self.uss_after = test.get_process_uss() + + # Establish baseline + uss_before = uss_after = None + for count in range(self.UNTRACK_ATTEMPTS): + EXIT_COUNT[0] = 0 + thread_func = ThreadFunc() + t = threading.Thread(target=thread_func) + t.start() + t.join(30) + self.assertFalse(t.is_alive()) + + if uss_before is None: + uss_before = thread_func.uss_before + + uss_before = max(uss_before, thread_func.uss_before) + if deallocate_in_thread: + self.assertEqual(thread_func.glets, ()) + self.assertEqual(EXIT_COUNT[0], ITER * thread_func.ITER) + + del thread_func # Deallocate the greenlets; but this won't raise into them + del t + if not deallocate_in_thread: + self.assertEqual(EXIT_COUNT[0], 0) + if deallocate_in_thread: + self.wait_for_pending_cleanups() + + uss_after = self.get_process_uss() + # See if we achieve a non-growth state at some point. Break when we do. + if uss_after <= uss_before and count > 1: + break + + self.wait_for_pending_cleanups() + uss_after = self.get_process_uss() + self.assertLessEqual(uss_after, uss_before, "after attempts %d" % (count,)) + + @ignores_leakcheck + # Because we're just trying to track raw memory, not objects, and running + # the leakcheck makes an already slow test slower. + def test_untracked_memory_doesnt_increase_unfinished_thread_dealloc_in_thread(self): + self._check_untracked_memory_thread(deallocate_in_thread=True) + + @ignores_leakcheck + # Because the main greenlets from the background threads do not exit in a timely fashion, + # we fail the object-based leakchecks. + def test_untracked_memory_doesnt_increase_unfinished_thread_dealloc_in_main(self): + self._check_untracked_memory_thread(deallocate_in_thread=False) + +if __name__ == '__main__': + __import__('unittest').main() diff --git a/psets/9/finance/env/lib/python3.12/site-packages/greenlet/tests/test_stack_saved.py b/psets/9/finance/env/lib/python3.12/site-packages/greenlet/tests/test_stack_saved.py new file mode 100644 index 0000000..b362bf9 --- /dev/null +++ b/psets/9/finance/env/lib/python3.12/site-packages/greenlet/tests/test_stack_saved.py @@ -0,0 +1,19 @@ +import greenlet +from . import TestCase + + +class Test(TestCase): + + def test_stack_saved(self): + main = greenlet.getcurrent() + self.assertEqual(main._stack_saved, 0) + + def func(): + main.switch(main._stack_saved) + + g = greenlet.greenlet(func) + x = g.switch() + self.assertGreater(x, 0) + self.assertGreater(g._stack_saved, 0) + g.switch() + self.assertEqual(g._stack_saved, 0) diff --git a/psets/9/finance/env/lib/python3.12/site-packages/greenlet/tests/test_throw.py b/psets/9/finance/env/lib/python3.12/site-packages/greenlet/tests/test_throw.py new file mode 100644 index 0000000..f4f9a14 --- /dev/null +++ b/psets/9/finance/env/lib/python3.12/site-packages/greenlet/tests/test_throw.py @@ -0,0 +1,128 @@ +import sys + + +from greenlet import greenlet +from . import TestCase + +def switch(*args): + return greenlet.getcurrent().parent.switch(*args) + + +class ThrowTests(TestCase): + def test_class(self): + def f(): + try: + switch("ok") + except RuntimeError: + switch("ok") + return + switch("fail") + g = greenlet(f) + res = g.switch() + self.assertEqual(res, "ok") + res = g.throw(RuntimeError) + self.assertEqual(res, "ok") + + def test_val(self): + def f(): + try: + switch("ok") + except RuntimeError: + val = sys.exc_info()[1] + if str(val) == "ciao": + switch("ok") + return + switch("fail") + + g = greenlet(f) + res = g.switch() + self.assertEqual(res, "ok") + res = g.throw(RuntimeError("ciao")) + self.assertEqual(res, "ok") + + g = greenlet(f) + res = g.switch() + self.assertEqual(res, "ok") + res = g.throw(RuntimeError, "ciao") + self.assertEqual(res, "ok") + + def test_kill(self): + def f(): + switch("ok") + switch("fail") + g = greenlet(f) + res = g.switch() + self.assertEqual(res, "ok") + res = g.throw() + self.assertTrue(isinstance(res, greenlet.GreenletExit)) + self.assertTrue(g.dead) + res = g.throw() # immediately eaten by the already-dead greenlet + self.assertTrue(isinstance(res, greenlet.GreenletExit)) + + def test_throw_goes_to_original_parent(self): + main = greenlet.getcurrent() + + def f1(): + try: + main.switch("f1 ready to catch") + except IndexError: + return "caught" + return "normal exit" + + def f2(): + main.switch("from f2") + + g1 = greenlet(f1) + g2 = greenlet(f2, parent=g1) + with self.assertRaises(IndexError): + g2.throw(IndexError) + self.assertTrue(g2.dead) + self.assertTrue(g1.dead) + + g1 = greenlet(f1) + g2 = greenlet(f2, parent=g1) + res = g1.switch() + self.assertEqual(res, "f1 ready to catch") + res = g2.throw(IndexError) + self.assertEqual(res, "caught") + self.assertTrue(g2.dead) + self.assertTrue(g1.dead) + + g1 = greenlet(f1) + g2 = greenlet(f2, parent=g1) + res = g1.switch() + self.assertEqual(res, "f1 ready to catch") + res = g2.switch() + self.assertEqual(res, "from f2") + res = g2.throw(IndexError) + self.assertEqual(res, "caught") + self.assertTrue(g2.dead) + self.assertTrue(g1.dead) + + def test_non_traceback_param(self): + with self.assertRaises(TypeError) as exc: + greenlet.getcurrent().throw( + Exception, + Exception(), + self + ) + self.assertEqual(str(exc.exception), + "throw() third argument must be a traceback object") + + def test_instance_of_wrong_type(self): + with self.assertRaises(TypeError) as exc: + greenlet.getcurrent().throw( + Exception(), + BaseException() + ) + + self.assertEqual(str(exc.exception), + "instance exception may not have a separate value") + + def test_not_throwable(self): + with self.assertRaises(TypeError) as exc: + greenlet.getcurrent().throw( + "abc" + ) + self.assertEqual(str(exc.exception), + "exceptions must be classes, or instances, not str") diff --git a/psets/9/finance/env/lib/python3.12/site-packages/greenlet/tests/test_tracing.py b/psets/9/finance/env/lib/python3.12/site-packages/greenlet/tests/test_tracing.py new file mode 100644 index 0000000..c044d4b --- /dev/null +++ b/psets/9/finance/env/lib/python3.12/site-packages/greenlet/tests/test_tracing.py @@ -0,0 +1,291 @@ +from __future__ import print_function +import sys +import greenlet +import unittest + +from . import TestCase +from . import PY312 + +# https://discuss.python.org/t/cpython-3-12-greenlet-and-tracing-profiling-how-to-not-crash-and-get-correct-results/33144/2 +DEBUG_BUILD_PY312 = ( + PY312 and hasattr(sys, 'gettotalrefcount'), + "Broken on debug builds of Python 3.12" +) + +class SomeError(Exception): + pass + +class GreenletTracer(object): + oldtrace = None + + def __init__(self, error_on_trace=False): + self.actions = [] + self.error_on_trace = error_on_trace + + def __call__(self, *args): + self.actions.append(args) + if self.error_on_trace: + raise SomeError + + def __enter__(self): + self.oldtrace = greenlet.settrace(self) + return self.actions + + def __exit__(self, *args): + greenlet.settrace(self.oldtrace) + + +class TestGreenletTracing(TestCase): + """ + Tests of ``greenlet.settrace()`` + """ + + def test_a_greenlet_tracing(self): + main = greenlet.getcurrent() + def dummy(): + pass + def dummyexc(): + raise SomeError() + + with GreenletTracer() as actions: + g1 = greenlet.greenlet(dummy) + g1.switch() + g2 = greenlet.greenlet(dummyexc) + self.assertRaises(SomeError, g2.switch) + + self.assertEqual(actions, [ + ('switch', (main, g1)), + ('switch', (g1, main)), + ('switch', (main, g2)), + ('throw', (g2, main)), + ]) + + def test_b_exception_disables_tracing(self): + main = greenlet.getcurrent() + def dummy(): + main.switch() + g = greenlet.greenlet(dummy) + g.switch() + with GreenletTracer(error_on_trace=True) as actions: + self.assertRaises(SomeError, g.switch) + self.assertEqual(greenlet.gettrace(), None) + + self.assertEqual(actions, [ + ('switch', (main, g)), + ]) + + def test_set_same_tracer_twice(self): + # https://github.com/python-greenlet/greenlet/issues/332 + # Our logic in asserting that the tracefunction should + # gain a reference was incorrect if the same tracefunction was set + # twice. + tracer = GreenletTracer() + with tracer: + greenlet.settrace(tracer) + + +class PythonTracer(object): + oldtrace = None + + def __init__(self): + self.actions = [] + + def __call__(self, frame, event, arg): + # Record the co_name so we have an idea what function we're in. + self.actions.append((event, frame.f_code.co_name)) + + def __enter__(self): + self.oldtrace = sys.setprofile(self) + return self.actions + + def __exit__(self, *args): + sys.setprofile(self.oldtrace) + +def tpt_callback(): + return 42 + +class TestPythonTracing(TestCase): + """ + Tests of the interaction of ``sys.settrace()`` + with greenlet facilities. + + NOTE: Most of this is probably CPython specific. + """ + + maxDiff = None + + def test_trace_events_trivial(self): + with PythonTracer() as actions: + tpt_callback() + # If we use the sys.settrace instead of setprofile, we get + # this: + + # self.assertEqual(actions, [ + # ('call', 'tpt_callback'), + # ('call', '__exit__'), + # ]) + + self.assertEqual(actions, [ + ('return', '__enter__'), + ('call', 'tpt_callback'), + ('return', 'tpt_callback'), + ('call', '__exit__'), + ('c_call', '__exit__'), + ]) + + def _trace_switch(self, glet): + with PythonTracer() as actions: + glet.switch() + return actions + + def _check_trace_events_func_already_set(self, glet): + actions = self._trace_switch(glet) + self.assertEqual(actions, [ + ('return', '__enter__'), + ('c_call', '_trace_switch'), + ('call', 'run'), + ('call', 'tpt_callback'), + ('return', 'tpt_callback'), + ('return', 'run'), + ('c_return', '_trace_switch'), + ('call', '__exit__'), + ('c_call', '__exit__'), + ]) + + def test_trace_events_into_greenlet_func_already_set(self): + def run(): + return tpt_callback() + + self._check_trace_events_func_already_set(greenlet.greenlet(run)) + + def test_trace_events_into_greenlet_subclass_already_set(self): + class X(greenlet.greenlet): + def run(self): + return tpt_callback() + self._check_trace_events_func_already_set(X()) + + def _check_trace_events_from_greenlet_sets_profiler(self, g, tracer): + g.switch() + tpt_callback() + tracer.__exit__() + self.assertEqual(tracer.actions, [ + ('return', '__enter__'), + ('call', 'tpt_callback'), + ('return', 'tpt_callback'), + ('return', 'run'), + ('call', 'tpt_callback'), + ('return', 'tpt_callback'), + ('call', '__exit__'), + ('c_call', '__exit__'), + ]) + + + def test_trace_events_from_greenlet_func_sets_profiler(self): + tracer = PythonTracer() + def run(): + tracer.__enter__() + return tpt_callback() + + self._check_trace_events_from_greenlet_sets_profiler(greenlet.greenlet(run), + tracer) + + def test_trace_events_from_greenlet_subclass_sets_profiler(self): + tracer = PythonTracer() + class X(greenlet.greenlet): + def run(self): + tracer.__enter__() + return tpt_callback() + + self._check_trace_events_from_greenlet_sets_profiler(X(), tracer) + + @unittest.skipIf(*DEBUG_BUILD_PY312) + def test_trace_events_multiple_greenlets_switching(self): + tracer = PythonTracer() + + g1 = None + g2 = None + + def g1_run(): + tracer.__enter__() + tpt_callback() + g2.switch() + tpt_callback() + return 42 + + def g2_run(): + tpt_callback() + tracer.__exit__() + tpt_callback() + g1.switch() + + g1 = greenlet.greenlet(g1_run) + g2 = greenlet.greenlet(g2_run) + + x = g1.switch() + self.assertEqual(x, 42) + tpt_callback() # ensure not in the trace + self.assertEqual(tracer.actions, [ + ('return', '__enter__'), + ('call', 'tpt_callback'), + ('return', 'tpt_callback'), + ('c_call', 'g1_run'), + ('call', 'g2_run'), + ('call', 'tpt_callback'), + ('return', 'tpt_callback'), + ('call', '__exit__'), + ('c_call', '__exit__'), + ]) + + @unittest.skipIf(*DEBUG_BUILD_PY312) + def test_trace_events_multiple_greenlets_switching_siblings(self): + # Like the first version, but get both greenlets running first + # as "siblings" and then establish the tracing. + tracer = PythonTracer() + + g1 = None + g2 = None + + def g1_run(): + greenlet.getcurrent().parent.switch() + tracer.__enter__() + tpt_callback() + g2.switch() + tpt_callback() + return 42 + + def g2_run(): + greenlet.getcurrent().parent.switch() + + tpt_callback() + tracer.__exit__() + tpt_callback() + g1.switch() + + g1 = greenlet.greenlet(g1_run) + g2 = greenlet.greenlet(g2_run) + + # Start g1 + g1.switch() + # And it immediately returns control to us. + # Start g2 + g2.switch() + # Which also returns. Now kick of the real part of the + # test. + x = g1.switch() + self.assertEqual(x, 42) + + tpt_callback() # ensure not in the trace + self.assertEqual(tracer.actions, [ + ('return', '__enter__'), + ('call', 'tpt_callback'), + ('return', 'tpt_callback'), + ('c_call', 'g1_run'), + ('call', 'tpt_callback'), + ('return', 'tpt_callback'), + ('call', '__exit__'), + ('c_call', '__exit__'), + ]) + + +if __name__ == '__main__': + unittest.main() diff --git a/psets/9/finance/env/lib/python3.12/site-packages/greenlet/tests/test_version.py b/psets/9/finance/env/lib/python3.12/site-packages/greenlet/tests/test_version.py new file mode 100644 index 0000000..96c17cf --- /dev/null +++ b/psets/9/finance/env/lib/python3.12/site-packages/greenlet/tests/test_version.py @@ -0,0 +1,41 @@ +#! /usr/bin/env python +from __future__ import absolute_import +from __future__ import print_function + +import sys +import os +from unittest import TestCase as NonLeakingTestCase + +import greenlet + +# No reason to run this multiple times under leakchecks, +# it doesn't do anything. +class VersionTests(NonLeakingTestCase): + def test_version(self): + def find_dominating_file(name): + if os.path.exists(name): + return name + + tried = [] + here = os.path.abspath(os.path.dirname(__file__)) + for i in range(10): + up = ['..'] * i + path = [here] + up + [name] + fname = os.path.join(*path) + fname = os.path.abspath(fname) + tried.append(fname) + if os.path.exists(fname): + return fname + raise AssertionError("Could not find file " + name + "; checked " + str(tried)) + + try: + setup_py = find_dominating_file('setup.py') + except AssertionError as e: + self.skipTest("Unable to find setup.py; must be out of tree. " + str(e)) + + + invoke_setup = "%s %s --version" % (sys.executable, setup_py) + with os.popen(invoke_setup) as f: + sversion = f.read().strip() + + self.assertEqual(sversion, greenlet.__version__) diff --git a/psets/9/finance/env/lib/python3.12/site-packages/greenlet/tests/test_weakref.py b/psets/9/finance/env/lib/python3.12/site-packages/greenlet/tests/test_weakref.py new file mode 100644 index 0000000..05a38a7 --- /dev/null +++ b/psets/9/finance/env/lib/python3.12/site-packages/greenlet/tests/test_weakref.py @@ -0,0 +1,35 @@ +import gc +import weakref + + +import greenlet +from . import TestCase + +class WeakRefTests(TestCase): + def test_dead_weakref(self): + def _dead_greenlet(): + g = greenlet.greenlet(lambda: None) + g.switch() + return g + o = weakref.ref(_dead_greenlet()) + gc.collect() + self.assertEqual(o(), None) + + def test_inactive_weakref(self): + o = weakref.ref(greenlet.greenlet()) + gc.collect() + self.assertEqual(o(), None) + + def test_dealloc_weakref(self): + seen = [] + def worker(): + try: + greenlet.getcurrent().parent.switch() + finally: + seen.append(g()) + g = greenlet.greenlet(worker) + g.switch() + g2 = greenlet.greenlet(lambda: None, g) + g = weakref.ref(g2) + g2 = None + self.assertEqual(seen, [None]) diff --git a/psets/9/finance/env/lib/python3.12/site-packages/idna-3.10.dist-info/INSTALLER b/psets/9/finance/env/lib/python3.12/site-packages/idna-3.10.dist-info/INSTALLER new file mode 100644 index 0000000..a1b589e --- /dev/null +++ b/psets/9/finance/env/lib/python3.12/site-packages/idna-3.10.dist-info/INSTALLER @@ -0,0 +1 @@ +pip diff --git a/psets/9/finance/env/lib/python3.12/site-packages/idna-3.10.dist-info/LICENSE.md b/psets/9/finance/env/lib/python3.12/site-packages/idna-3.10.dist-info/LICENSE.md new file mode 100644 index 0000000..19b6b45 --- /dev/null +++ b/psets/9/finance/env/lib/python3.12/site-packages/idna-3.10.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/psets/9/finance/env/lib/python3.12/site-packages/idna-3.10.dist-info/METADATA b/psets/9/finance/env/lib/python3.12/site-packages/idna-3.10.dist-info/METADATA new file mode 100644 index 0000000..c42623e --- /dev/null +++ b/psets/9/finance/env/lib/python3.12/site-packages/idna-3.10.dist-info/METADATA @@ -0,0 +1,250 @@ +Metadata-Version: 2.1 +Name: idna +Version: 3.10 +Summary: Internationalized Domain Names in Applications (IDNA) +Author-email: Kim Davies +Requires-Python: >=3.6 +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.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 :: 3.13 +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 +Requires-Dist: ruff >= 0.6.2 ; extra == "all" +Requires-Dist: mypy >= 1.11.2 ; extra == "all" +Requires-Dist: pytest >= 8.3.2 ; extra == "all" +Requires-Dist: flake8 >= 7.1.1 ; extra == "all" +Project-URL: Changelog, https://github.com/kjd/idna/blob/master/HISTORY.rst +Project-URL: Issue tracker, https://github.com/kjd/idna/issues +Project-URL: Source, https://github.com/kjd/idna +Provides-Extra: all + +Internationalized Domain Names in Applications (IDNA) +===================================================== + +Support for 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. Strings are +preprocessed according to Section 4.4 “Preprocessing for IDNA2008” +prior to the IDNA operations. + +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.6 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. + Use "idna<3" in your requirements file if you need this library for + a Python 2 application. Be advised that these versions are no longer + actively developed. + +* **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/psets/9/finance/env/lib/python3.12/site-packages/idna-3.10.dist-info/RECORD b/psets/9/finance/env/lib/python3.12/site-packages/idna-3.10.dist-info/RECORD new file mode 100644 index 0000000..54f6609 --- /dev/null +++ b/psets/9/finance/env/lib/python3.12/site-packages/idna-3.10.dist-info/RECORD @@ -0,0 +1,22 @@ +idna-3.10.dist-info/INSTALLER,sha256=zuuue4knoyJ-UwPPXg8fezS7VCrXJQrAP7zeNuwvFQg,4 +idna-3.10.dist-info/LICENSE.md,sha256=pZ8LDvNjWHQQmkRhykT_enDVBpboFHZ7-vch1Mmw2w8,1541 +idna-3.10.dist-info/METADATA,sha256=URR5ZyDfQ1PCEGhkYoojqfi2Ra0tau2--lhwG4XSfjI,10158 +idna-3.10.dist-info/RECORD,, +idna-3.10.dist-info/WHEEL,sha256=EZbGkh7Ie4PoZfRQ8I0ZuP9VklN_TvcZ6DSE5Uar4z4,81 +idna/__init__.py,sha256=MPqNDLZbXqGaNdXxAFhiqFPKEQXju2jNQhCey6-5eJM,868 +idna/__pycache__/__init__.cpython-312.pyc,, +idna/__pycache__/codec.cpython-312.pyc,, +idna/__pycache__/compat.cpython-312.pyc,, +idna/__pycache__/core.cpython-312.pyc,, +idna/__pycache__/idnadata.cpython-312.pyc,, +idna/__pycache__/intranges.cpython-312.pyc,, +idna/__pycache__/package_data.cpython-312.pyc,, +idna/__pycache__/uts46data.cpython-312.pyc,, +idna/codec.py,sha256=PEew3ItwzjW4hymbasnty2N2OXvNcgHB-JjrBuxHPYY,3422 +idna/compat.py,sha256=RzLy6QQCdl9784aFhb2EX9EKGCJjg0P3PilGdeXXcx8,316 +idna/core.py,sha256=YJYyAMnwiQEPjVC4-Fqu_p4CJ6yKKuDGmppBNQNQpFs,13239 +idna/idnadata.py,sha256=W30GcIGvtOWYwAjZj4ZjuouUutC6ffgNuyjJy7fZ-lo,78306 +idna/intranges.py,sha256=amUtkdhYcQG8Zr-CoMM_kVRacxkivC1WgxN1b63KKdU,1898 +idna/package_data.py,sha256=q59S3OXsc5VI8j6vSD0sGBMyk6zZ4vWFREE88yCJYKs,21 +idna/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0 +idna/uts46data.py,sha256=rt90K9J40gUSwppDPCrhjgi5AA6pWM65dEGRSf6rIhM,239289 diff --git a/psets/9/finance/env/lib/python3.12/site-packages/idna-3.10.dist-info/WHEEL b/psets/9/finance/env/lib/python3.12/site-packages/idna-3.10.dist-info/WHEEL new file mode 100644 index 0000000..3b5e64b --- /dev/null +++ b/psets/9/finance/env/lib/python3.12/site-packages/idna-3.10.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/psets/9/finance/env/lib/python3.12/site-packages/idna/__init__.py b/psets/9/finance/env/lib/python3.12/site-packages/idna/__init__.py new file mode 100644 index 0000000..cfdc030 --- /dev/null +++ b/psets/9/finance/env/lib/python3.12/site-packages/idna/__init__.py @@ -0,0 +1,45 @@ +from .core import ( + IDNABidiError, + IDNAError, + InvalidCodepoint, + InvalidCodepointContext, + alabel, + check_bidi, + check_hyphen_ok, + check_initial_combiner, + check_label, + check_nfc, + decode, + encode, + ulabel, + uts46_remap, + valid_contextj, + valid_contexto, + valid_label_length, + valid_string_length, +) +from .intranges import intranges_contain +from .package_data import __version__ + +__all__ = [ + "__version__", + "IDNABidiError", + "IDNAError", + "InvalidCodepoint", + "InvalidCodepointContext", + "alabel", + "check_bidi", + "check_hyphen_ok", + "check_initial_combiner", + "check_label", + "check_nfc", + "decode", + "encode", + "intranges_contain", + "ulabel", + "uts46_remap", + "valid_contextj", + "valid_contexto", + "valid_label_length", + "valid_string_length", +] diff --git a/psets/9/finance/env/lib/python3.12/site-packages/idna/__pycache__/__init__.cpython-312.pyc b/psets/9/finance/env/lib/python3.12/site-packages/idna/__pycache__/__init__.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..d833519b6e523e65adc8cdfa6d1a7758b2038032 GIT binary patch literal 883 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 literal 0 HcmV?d00001 diff --git a/psets/9/finance/env/lib/python3.12/site-packages/idna/__pycache__/idnadata.cpython-312.pyc b/psets/9/finance/env/lib/python3.12/site-packages/idna/__pycache__/idnadata.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..9ffd805f386972a625eebc5642de44250d6a8432 GIT binary patch literal 99473 zcmYh^37nO4|NrsRbec2M9;qbld(%GcQ%yDP(>~HB$)#OdrnF2okv)VEk|c>jNRmMk zl8}TXBq4;*?Y4yf=k@)(&;9%V9*_I^et)hxbLQKb%=va*=gjY|GG$7}?Ek)8ICA2# zmc?RUG9>>mRpr;QV`8zpV^M5WEGibIM8%_cR3b`UU1C(R$+0LArQK01N)MI{mI{^* zmI;;(mJ5~-RtTOIJUdu1cuufVuyU{p+SfTZOjU#D1*-+m4^|J>2-XbN3f2zR3DynP z3)T-d2sR8h!iV`vjl=x`E>=Dcf_6+t4_73(5_6_z6_Q&v*a>G0zI50RUI5;>YI5apcm>0Yt zI6Qb^a71uqa8z(~a14g8bWxbc1}_ed3tkc&AG|ae1uqLu2u=)63Qi7A2~G`83to=l zD@_mc6~P(7nZa4X*}?qaoZ#HxmBD$z`N0Ljg~5X0qTpf-Uuj903xi98R|T&QE(=~0 zyf%1U@cQ5l!5f1&1(yeJ4&D;H6~k9r5$4;1w+HVCt_Z0;Jv~7f~$k~ z2iF822(HEOl^zW9y5K{>^}&aO8-kAnHwGUKJ{H^*+#Gy7_(br@;FjQ17{1ceVSXmK zHTZ0BTkyHy_Tclu9l;lZMZp(?F9lzYcG}OISE60!tHIqEzS3)9em&gcjnMam{$}WV zLw_r{FZg!wo#4CSHv5C`1rG$@4<9`k`~bsO`Y_BN1rG&34jvAE5$T%0l&Q*uGEJFI^40CO zC3PRAl%yt%th_~et8TYK^KGQoa=VV*pYX&%Ku6+1D~W|5}D; zV9W3vY#E+~EyMG$Wq2mG49~@u;n~ZFDYME?o_^_+@*X~xtr8lUemGg9B%jhhUPu`8gDB1D&Nw_ z_bK02zN36sxnKF7@__PvF`8c)qve;ThlZ zGu`Ls%A>m77n+Z0{!$rs0rq)eA7B}F0(xA&(QQsBztw$&9f95Ud(9`6KPZ1xhP{E^ zF6<60!~VcB><}!&9>Fr~5-h_$!7}U=EW=(wYY96BI~Mi}mVfGN{G~jj{9E~t^52jt zws)}a_lgwzx1^`<9r$;p&v9i5WvVivOe4cuQtaQI{yDyPNQp{mF0Cx1EUWarLrPR$ za|NaE9a5sRHCI&n-XSIOy+camdxw->4udJ@Dp{%K_ zrL3*2qpZt5(H^IIn(HeYC>tspDI1e|T$<=uhO()$nX#v9+%F_F3PS--#es4-NN7Pl&HJ1hd!R8xu<5|JETOucSwnR?~oGt z-XSIOy+caWU$@UCwUz-oHc&Z8_w9R!lxT=%-#es4!!+mV&vk)vxbi~X&j{s6f@7?la*7HQ%Cp+dxw9Z?~vkq2dyRSAMAVJdxsS59a6M+ zNYUOQMSF)7?Hy9IcSzCRA;tC%{yh!yLId}>!A`^tl)*7AXleW?6Mc}V%O^04v~YJ4k_9@q-gJuqP;_k_6{l9 zJEUmukm7p>ttIRq?EC6_hZOA{Qf%+w-~VvF!9E_&I9UFzR7t6q_UKb^u0rI?H!6o=j(WNWeuh89g0V_G}l(vQPx%Z-l2HpdxzqY?;VOqzIP}dg}sB; z67~=FnEKwKc;tJB;!#uGm+u{lN4|F`9{Jv(c;tJB;*swiibuY8C>~|%^L+16Jo3Fm z@yPcM#UtN46pwuGP&^8I2d$-(J~vC*S=mL|Rhg~qrtGflq0CYCRQ6K#R`yZ$RrXW% zC$*Mb9UGt=s2rpmtQ?{osvM@wQ~KVac;tJB;?adVK0-NCIZ8QNIfm3)F4D2F%8Qlb zl$R*SD=$?>%FC1!loOScl#`WHlv9<{l$VoQ%XA&PLODY@Q#ngHTbZw%qnxX}QaMjK zU%5cJP+6c{q+CpDElYH)P`OljmGWxkGUYYOYn9h2uUFonyis|Ra=G$m%6J<#WpI%IB3klrJcYlrJh@QogL* zseDDbi_}_P)v?{m*Oad--%##RzNy@+d`r1c`L^;M<-5xL%J-B9l<$*T%RwFcK>4Ba zBjq9G$I8RXPn1WLpDI67ey%*K{6cw5`K9tWskMBiV_z%3QJzqKtNc#+z4D~;2j!2- zpOmMRKP!Jx{;E8!{12(M{HA07RsOF0L;0ujFXb8K-^zcK|Avff?-1ACA+Ehc+|E1L z*IW^|tJTKwEY+|NDOn*6*&JUTDz=i|0_uzxey@$;3{ zl{J(#m9><$m35SLmGzYMl?{{)Nv)-kjx|;`QD!KcDw`>rD_baADqAUAD>IdClx>ym zlJ-`FV%9opMJMZ9Y7^)nm%u`;V9Io{9 z4)JJ&WM;bS#{Eu)h~$HD9b8r@TZtUU{i9QeLLN;}etK&*DU;To2T^i4sp9?;l~#$3zUmUt!1%} zEm0OKmnyGPUaefF^z#n!=vvL!DgC@dJi0-TkDqslM>lEqy+b_my+b?-dk3v0>>uoV z<9mmAvBvBv>op!h+4l}{U9*VmnnhgKEaJLm5!W?~xUN~mb?b+^<{M?0bi}&O5|)-XX5@4so4#i0iyV zT<0C)I`0tId53u9dxyBrJH&O~As+eOA#SfTu*XSj3Ht~8+P-&)N4|H6N4|H6N4|H6 z+cgV+Y<=$#k9_YCk9_YCk9_YCk9_YCk9_YCk9_YCk9_YCk9_YCk9_YCkHX$TYYF=Y zTZ``<;*swi;&#o#zqaok;&#o#XWu)-?V5$pzITX6zITY*H48uPdxv=Bdxv=Bdxv=B zdxyBaYQb+8_6}N0*gx1>eD4sq>lS_+-#f%3-#f%3-#f%3-#f(ZnuXua_YU#M_YU#M z_YU#M_YQHLcZln}LtN(_;yUjT_wx=~OV~fyT72&i_v;om``#h0^A2&HcZf&6cZln} zLtN(_;*swi;*swiN@(v;LVJf2+B=lc-l2r{4khgM4)$jXYq3|zg+E^je}&u%`-o=W zJCv~3JMiZ(Vb?4?ODoGL%PPw$%PT7=&r+VPtf)LkS&7tID(hGk<+;kL%JY=fl;RW?&LSGG{LRJKyKR%R;ODBCLA zDch4;O9vh6sO+T7Qg&8$QFc{kE4wMXD|;w&ls%Qbl)aUGlzmC9rJs)VSLP}QCm8kyjFRg@_OYB${Uq8DVHm6CbgDZbnI5;3gvCe+m&}HS1RvR z-le=-xk`DD@?PbA%GJvIm1{_?z4Bq@2IV8ljmk%rk101PH!B}k zKB0V))LORa*i*`Is{BHEjMQ4b)Uo5ruasXazfqo0eyjXW`MvU_@(1OQ z%Ab^{ls_wfQT|G5EvI$tKg!>f|5g63{6qPt@-O8X<=@JGl>dfI)$1Kn^?HX?y;d?+ zuXjkby+d*>skVRMF;2C;gJ(jSX2;UQM@ok8R;qRlsZnXoWt3%=<&@=>6_jTw&sJ7c zo};WphDRpV&N^7PuUtiWuCl7~JY_ZI`O50b8p@i=TFTnWI?B4rddm9B2Bg-~P{$f6 z8!MYAGn7r0&6LfREtD;lt(2{mnaVcGw#s(O_N3O*LB~2OJ1Mi2ot0gbU6t9&Zp!Y; z9?BeLPh~G$_%IV50lrxkwm9vzy zmHEm!%DKubmGhMIl?#*$l?9~MvPj1kE0-t>l}nXZDX&&8Q(mLIR(YNBdgTqu8{jIp-XT?chg9tyQtiBhe|LQEkgC^8rrLQ2 zKkj>nR6FnB^Z)G~QX}6xq(;7XNY(2lQ~mXlwtC+?q}q80|6JcYq}q80pMCF;8u{KK z)y_Nkao;1OW=N(e*yn}xY-#et*c?af%?H%~;CA4=)Xz!5F-XZb-?Hv-@J0!GsNZ5G?zmGI! zy0WCQl(Mw4jIykGDF!^*-Y77*+SV;*-Ggm_Z@(%f0M>!P`9A!^sFMVEbWgm`fEq!&YpKjY<|K%s_ zs)c`7d=HVZs}?@{9wHI>9wK2^E&RCeArkg#NuPZWk%)W`kVXv0-c)shLlS~6j;mh}7fJwzh%Jwzh%Jw!rREfSIMAriW3k%+<`LTd^82wRKqArg`A zAriW3k1+wWP1%F6G_IRmyvm_bTsGu2$YpYAtJY>;dIk<%7y~ z%7>Kel@BX7C?8R7R6eSFOu0$9S^2o~2~ul$QpdI^egBZqRf~kKS|oJUBB84m30<{F z=&D6RS1l5{YLU=Yi-fLPBy`mxp{o`NUA0K~RST_Ur`GU_a+mT|bnHvzaphOaua(~@Pbj}tey99ic~bd<@<-)Q%2UdpmA{Z$%da|iTKOO4Z_58F ze^>sY{8Rat@{ICtqlu#&-{CI{%QS-9wso4{6#x zq-pn%rdLa*>D7{HwtKM0+SXb_SyNd{SzB30Syx$))LQE6SOaB4Wg}%{WfNtFvZ=C} zvbnN_vZb<>(svJO+C8Lc_mJkh2d$-@ZrfhjLD^B+NtvbWtn8xfs?1h)Q+8MOQ06Fm zDtjq=lUhq39qX&?r|hrHRSr-NR1Q)ORt`}PRr=l`E%LoXn)VK9+B>9a?~vwu2d!nK zK6jLIv~rB{BIQ`+#maHYOO)f4mntLWWy%T4iONaJ$)wgYMaQNprztO2PFG%`oS~el zoTZ$t%va7)&Q)HioTr?xTtI3q3w5kOxk$NKxkOp0T&lcEd9`wx@*3r}%IlQZD{oNV zsJw~PT9)hB&B|Mpw<=dCZ&Ti`yhFKCd8hI&<=x6v%6pXeD(_RSCbgFPb!?6D0p(id zgUWTvhm`A;4=Xn)A5m^pKB|07xksY{8Rat@{ICt2W&&QVrUR#sL~o~x{?JWp9odA_o`vWBvzvX-*8vW~JY zskPM8vHHpe%7)5D%Ernj$_!;wWiw@SWea6XWh-TCWu~$XskOA#v3AP#$_~no%1+8G zWoKmO@Go<#Kkip8O6nC4CH<;Jcw9>A%0)?CxhUyZE>@J(Rg03k zYEe>GElS$nf%`0}-|$dUza6Tie#1ja+dKHj{i;Ptz0;zk-f2-%@3bhXcUqM6cUovI zXX|q-D$h|?QdU-0QJ$-;syt6wO?kf3uUeGUd54lw&G7f9q~4`jGODe)4ym=&)vytj3}sVgGi7sS3uQ}XD`jhCCaJZw(XqD5cFOk34$6+oPRcB0XJr>< zS7o-co3gvIhcZXmlhj&z=~!=NA7x)$|cG|tlwcMyJDeqRUQr@Gym(*JB)3Mdc`;}{y z4=C3vA5^YWKBQc)d|0_b`G|6(@=@hu%1xx!vRTI-S3aS9Qn^L>l=5liGs>;XXO-KO z&ndSnpI7cszMw23wU!rk>?P&P%ALwrl)IF#Dt9YiQ@*ZzL%B!!rgE?HE#*Gt+oaa= zj*h*n+^>93c|iHT@}Tkq<%i0Tl!ufbD-SC_Q65o#s{D-9T0YmYqslLo$CO_xk1M}Y zey#jQc|!TE@;l}C%9F|;ls_teBDI!NI`*^j7v-WkY2nWn*O%Wrnh;vYE2EvW2pxvX!zmskLP4SQ}+q zWjkeiWd~(PWhZ5pva_;_va2#%*-hD9*+ZE_YAro=te3L4vX8Q_vY)cQGFLf3IZ!!B zIaoPFIaE1JnWwyf)LMq?*oDdw%8|-Z%F)U(%8Qg^l@}|=DKAluS6-@&l$R+dkXp+` z9h;<_tem2ps+^|0Tsd8Ng>r^+rgD~YwlZHiM>$t{CHZi%Q7QJ{);#;)eEZ)5``^OV z#YYuiQEGlc!$qZHu?49u+caz0tVN@`(~8@#9?v&+mI-y9)q`FaTRq{m(CQhl*H|rI zHr)0)t5v+-WVNQ(o2|C+y3T5Qug9z|_Zo}aS1T9pp~?BN*sAMl;(FfBQJ*xWvnrH`bx zh{Y;qYe=)9T5@P?!?NU%Wy4V$PO`e41B}7?oLJ3b_KiyM1x;UILzM90unjvWYdC&I zO6>ZsrTh+lv0-O&I9k7i-CcSANXK?IR6ECq>g{c~NW;2;C1Qo+G<-3&L~LirN`AAk z(`{&8*}rJ@1@<}PD*H$JpUp4Fuj0d&I;pYj0aap+(!;l7kKHb((n-GK-&@VD9FG3S zYEk9z0Jd9LES5h_%kON%(d5w8hToGzcN=1t>t;P|D4iSz+fc=ZMycUZyW1YZcsD(2 zYi-EyuAyej;<0#k8DC~=8}{UA7-mCu&ocf;D>jR7aJg8cvf=*z;`@`li&)E8>~s%( ze`2ldd(>NZ{;v(${WXkeZGYTc4KtP$i>+Fum9Md3w+-R0Pd6`a-yf~vj132q!@oA1 zwjn%1#ah^cY~5j~V@oYeu6wu*dA9CwZ#{2kr}ddU>yn9=OuyuCTK`M(FPUoX+sAF0-{u*UWA-H`7lRZi4sj>}sgQs)NQaV8 z3Q9v6C=2DFJXC3{~JxtLk*}2wV*cCfx1u+>O%u)2#ugI zG=U6g3eCVC+Sp_s(#iIK#U{6c){qHppe?k6_Rs-3LMO$ALN;`R?$85rpeOW# z-p~j7LOn!#g^OVvTms|aQi$L( zm;e)D5=@3EFctVOcJk#g9j<_@?FZE4WpE8#3)jK*a0A?C|BX++9qxdYa3|aacf%^U z2kwRYU^UziYv2J`3lG9NcnH?R!>|D!fsODeJO-O!GdvDYz>}~Ao`R?08Q2QX!Zvsg zw!`zV173h4coANPS6~!P# za1$(to8cC?6;{A)a68-qE8$MK3+{$ha1Y!I_rYqoAJ)JFuofPKb?^|ZhlgPUJOUfx zQFshC!De_Io`5G|3p@o+!!xiIo`r4j9BhZ@VF$bbMeriL1TVu*cm;OBtFRkhgV*5= z*aL6EUU&=k!Q1c-ybJr`JvadG!w2vod<2K!V>k?-z!CTyj=~pk48DZp@C}@R@8Ekl z2|vJ(@DuzAf592}7s@4!@=yWJg0rC_oCB4hGE{+cp(>mQ)!=-n4mF@A)PmYj2kJsS zs1FUGAvA)<&;&A|DKvxT&;nXQD`*Xw&<5H;Jun9K9;WPLg zj=~pk48DZp@D+Rw-@pm@7QTb;;UxS3Kf+IN3Vw!P;8*w){)S3vMrEi1=fZhV4bF$^ zPy=d0EvOB3pdQqR2G9r^Llek=rjQNYpgZ({9OwzXpf~h^zR(Z)LoN(}fiMUL!w?t> z!ypeXfZ=cS?U1|ER5@F1*%hhRNC3>)AP z*a(lpW3UM}!xQi%Y=NiXX?O;;WPLgj=~r4B^-yZ;A{8> zPQbVD9efWb;RpB;eu7i*GyDR-!fE&q{09Gp-{BAV6aIoT@HhMe|3WO?Cu;Kr#D&?Ke3E zvY;Duhu+W!`a>=ZfFUpgX2Kj;3Rgi9yaK!6RoD%$!5gp#-iBlFCHx70!5R1){(*m? zn4S2WoCS8;#uf?Pp$Fu^0Js2#!+5w9u7aKLHpEIBama!$&=st_GDb1z1X<7xxM4;`Q*^aeXaXFsl?AM}S@7ytv|DcB0n!Zvsgw!`zV173h4*aL6EUU&=k z!Q1c-R4Hei3vHksbby&K3uZ$;%z?RZCCr2QumBc90W5;WPzX!mD!3Y!!L@K5+zhwC zt*`=agWKT_SP6H+U2r$t1NXvxuo~`%HShqeg$H3BJOu0EVb}nVz(#l!9)nG=86Jlx z;7Qm5Pr=jh3~YsGVH-RL+u?cG0WUxiybevv8_l3Ow18I78Zw~`w1sxi0Xjlw=mH~P zB#ecNVI0haSuh*&;VQTWu7#W7ez@ptV=P<@XH_=NhKkS%TEkEn2D4x`Y=vjxIoJ-* z!wz@>ir__f9o~e!@D}WYx8WUl7xu$@Z~)$iPa#poC<&#YG?amIP!noFZKwlvp&rzS z2G9^1L1SnF8PF7(L33yUEuj^(hD>M!ZJ`~shYrvYIzbk6hAz+*vY{JvhaQjvJ)sx$ zhCa|2`ayrl1v^1)KLubA42B^v6ox?_TmZx2LKp!fVHAvpF>n!#g^OVvTms|aQi$L( zm;e)D5=@3EFcqf3k( z+y=M99k3GaguCEwSOxdMy>K6_hWlX+JOFFqL0AV5!FqTYHozmW5gvudpys(oEvO9* zpdqw^4$u)gLFKAO6*v!u!w47&qhK_Qfs0@)jDzuT8BBnQFbO8Z6qpLrU^e8#9GDAN z!aSG{3t%A>z!KO3Pr=jh3~YsGVH-RL+u?cG0WUxiya+GB%dit(fnD$_?1tCib$A2z zz?-la-hzGbHoOC|^NeDU0>vQ{+Cn>M4;`Q*WI=bB3e(_nm=0IK444VCU^W!OQdkEM z!FqTYHo~K@2{yyy@HL!(Z{Y{{2~NS!kWtNO3eBK7w1Ae-3R**3Xb1b@Jvaad;RE;( zK7vE=F&u_Z;0SyQpTXyF6pq1{a2&pZui+aw0YAWL_#OTLE}2e#1$M!!up3^3*WnG= z18>4!cnkKy+wcy&3;W?cH~{a%LHGbZgpc45d<=)-6F35&!e{U~9EC677<>uG;VbwW zzJU|)Eqn*x!%6r7euSUk6#NXoz^`x`{sX_kf8lrd1O9}+;0*i?|G>Xcs-{r}%0fA4 z3{4;dnnE)e2baKjxD+Co0#jicTn^LW3fK?t!2x(54#EfUA$$af;A1!ppTH6L6h4E` z;V66o$KXpi4qw67@C}@RZ{a)m9!|m!@FV;Lr$Wo1!OyUysc{s(fMf6_9EY#qYxo9E zz_;)nd=Dq#2lx?wf>ZD_`~ttiY4{KP2LFZM;Scx|{(>{`H~a(t0vEg|H-QXj3irUh zaK#2=2F!$6kPmZUE?f!oU_LB>g-`&CU=2I~r{HHu*=VFfDX0haAp^3Z8+3;rkOMuT z7xacc&=>kaf5?RaFc1d8U>E{JVHo7W1uz^ggb^?jM!{$p0~f(qxERL4B`_W?g$OQ# z2`~{R!DN^MQ(+oh4%6WZm;p0kmho+F%-U|o*Wf680mtA=I1XRI*YFLTfN$YD_#RHe z5AY-W1gGF<_!sIwYBYd`&Q+dU+4$@Ar}U~Ko|srVF(n$Qn(79fo<>{ zY=`He2wsG*pwVMSV`u^y&=i_MOK1gcpe^)(TquAo@H9LFTj4p_4llvW@CuxSAK*9m zYLjsSet_zK8L@wiVvqvGAr2)V6%vpJ=};0%L1`!hWuY9@gj!G=>Oftn2lb%=G=xUb z7@9x^G=*l+9R7tr{x$xDzu@m;#q6(7iZQpiaV5-y`LFla2&pZui<+*2|vJ(@Dmi4GM2(sa5XH0Yv5YA4z7nA;6}I!mcz|(3)~7T;5K*^ z9)nG=86JlxAXdgG1}RV+;!pxoApvQS4ke)!l!h`;7Ro_+r~qfd*-#PAfl5#rs=&EW z70!cda6VLr8c-8zL2al5b)g>AhX$~ztg#vXhJWB+Xi?5+39X2-57zTMT17^Z3m<{M+ zDKHhL!3>xQvtTylL;H$G2j~c$APYJ}7w8Jzp$FtZFBl8Yz*cw`w!w3-9d^LWuoHH{ ztMK$W#xt-Lo`oWK5nhI!a0EVu)|HG*XajAb9khoI&=ERASICA<@HlLNr{HOL2DZYp z@En|9*{BXRpf=Qjx=;@qKtpH*jiCuNuVS=-me2}XLngF=w$KhbKu73wu8{>@pa&d; z58y-i2oA$1a1@GFHBz8B#GwSFLITnt9ZEuL$b>e~7TQ63=mc5N8M;7k7y?6K805hP zFdRn0C>RYl!cDLoZiZXnR#*YI!R>Gdtb{w^E?5QkK#OWdOK1hHArsm_TWAj*pd)mG zEa(hf;dZzKR>GZd7u*f2;2yXa?t|5EKdgZVU@bfd>);_+4-dlzcmy7UO|TgrhbQ1k z*aA<(Gw>{IgO=wTt)MkzLK|oc9U%)kLs!U#ZqOZiKo0bT-mn60gFE4F__exm8e%n! zV$c@aL3`)`9U&XKLyJtKCA5OpkO^&|EwqF7&;dF^C&+@%&;`0eHuQ!*&=>kaf5?Ra zFc1d8U>E{JVHo7W1#oJL@iY7azrtx~G1X`Zt)MkzLK|ocgRU@cg%xlc+z!X#{vu-y ztc3?*9XtfFca36@0>vQ?B_I_NkOt{c5=ud7COp;I01crLG=?US0ZpL=w1igB8Zw~`w1sxi9y&lr=mc5N z8M;7M$cApv9eO|x^n_k8@jYV_OorKz4|8BHTnY1FJ}iKRPymZyF)V>XSPECcHE=Cl z2iL<5a3kCVkHIF`439(i14a+Xf!JZA7^FaPh(ifTg#@HQI+TP`P#VfWSttkPp#q!* zXG29e2P#2jr~>CgRX7i-!TC@fYCuh>1+}3L)P;Ib9~wYIXatR+31mQ1Xa>!p1+;`# z&>AwK4YY+$kOiHg3v`8S=my=P2joCc=mou@5A=n8&>wPP01SjdFc^lwP#6YzZ~+X5 z3t_1_=2M6GNI0zrWhYkae<&6!Ykxqf z1+}3L)P;Ib9~wYIXatR+31mQ1Xa>!p1+;`#&>AwK4YY-J&>lKKN9Y7u&>6ZwSICBL z&>ea}4)lax&>Q+dU+4$@Ar}U~Ko|srVF(O`VUPzGz;L(_M!-lI1*2gMTm)m`Vi*UP zz<9V6BDf4Dz(kk?lVJ)>g=ug(OouCA2F!$6FdOn=4$OrsVIItf1+WkbU=b{aB@ioS z6oV8f4sj>}sgQs)NQaV83Q9v6C=2DFJXC3{~JxtLk*}2 zwV*cCfx1u+>O%u)2#ugIG=U6g3eBK7w1Ae-3R*)Zw1KwJ4%$Np=m?!43pzs==nC1; z4Z1@Q$bp{F3wlEz=nMUzKjgvy7zl%4FbsjAFbwkG0vHY#!Uz}%qhK_Qfs0@)Tnyvj z5*QDcLIjt=1egeuU@}aBsW1&Lhv{$y%z&9N3uZ$;%z?RZCCr2QumBc90W5;WumlQW zDO?3t!!o!Au7&I1dbj~@gqvVF+zhwCt*`=agWKT_SP6H+U2r$7f_vazxDQst{jdfe zfVJ=-tb>POJv;1SpekHTZH2{yyy@B};wTi_{p8lHiz@GNYD=U_WL4?ExmD1sN^ zC3qQj!Yi-~UWMK88oUl~z#e!L_QG4R58j4%;9b}c@4*3h9}dC?@F9Ezhu~v444=Re z_!K^a&*3P10mtA=I1XRI*YFLTfN$YD_#RHe5AY-WWHfx*-rUAp;$qG0e_OqFw7S#l zLaWP)g&X|WYC-W(WA^UVqh3?2#^d2=+-hmBsa7j`O|x3fYe}nhy_U9`;nhxd$1=Uz zxy@LXS3B7k%kf&#YOYs1KNZXKYUhn&W4utL44gJ91-Hy!N$P)2qE3HjS3COm646c)iPNp4Zh@Bd-rwo#%C()n#7STV3vTgVmK@AGNyH>t?GP zy*^=etJkNj?)3Vs)%{+dvwFy@on46?_qyBaX|Hx_Al5z+{%rQ|@mRLk_pSEv`hnHK zUO%!r!t2LY$9et4>Ljn9S)JkasMP|m$E+^%dfe)AuU}hT>Gg!w)n31|y58$atDC+4 zXmzXCpRE>o{mtq@uYX!S?)8k-lV1O^dfIEueqq5GuPIjJY5o(&YH6>jRx5f~c|FT&j@OD-bG=rwn&-8O)iGYHT8+F`vpUUdb*uSaYg#Sv zTHER}uXU|1_gdfTO0NyAuJ+p4>UyskRyTWXW_7FA7FLVAwz9h0Ye%d5ymq#F%4;{P zXT0{Xn&!WowPEhSz~sGrexHn&owu)#D|@qkh0@l~SSpV0DYvpR8{8 z%G)=6gMAwZQ8!tINC|x4PWx*H%}0Jz;gV*YB*Z_j=Om zX0Jb5-Rkv})grH_t?u*sht;EA|F(M4>o|Lc-B~_7I^(S_s}O2rb-C9GR#$qRWOcRI zDOT5eU>uRgh zysojD?{%%!0T<6etgiIB(dufik6B&sb+gsYUZ1eK)$10kMPAth?e@CW z>OQaAtRD2b-RcpqJFFh}T4eR4*O#oG_PW#R8LzKeO*=b0e6Lw8@AVCdi~I9p4UTG$9O$#HS&7I>NKyPSn~P!dp&J+pV!~49`yRV)gxa2 zw0hj@8LKC~{$usD*O>hdf-_!Iti~&b2Q_ZBwAWOt6}_fet>(3))w*6wTg~uV)@r8L z@>a9Fo@F)1YelQMUMpG6^IFB~7_U{WMqaB~o#wT=)qJlttrmE#ZFQN~x>lEa<=5A& z^xDwsYOjs0uJ@W@b+gxIR=0X>VYSHXD67#q;c>XmYN6K~tk$d)j=p3y$Lmh3XS}{@ zHSWK*=5?#(z3#DEt@5lg_H#UZ?yol6Z?v%=VzKj5?T2ucP_wNTdL3sqer`BA$Le;k z2dy6W`l;2t^TG|jwOZiyl+}%1WA?t-6JGmU&8`-1`?S@}^F#g3YOF@6|5!ckwON`S ztr?Dvq1Fm@s?|cT*IV7`^;WBOYlj;gvpUY}h;;id)Cor;tA+JKondvA*JW0Bd%f9e z#roj}w^_~d`l!`huTNRs==B+^d%W(jddTZ*R!@0-(`vN_;m+Q*n&I`3)iGX=TP^hZ zi`7+L|F(L{>%Ufi_Zly0-++eU&PrLW=(U2?EU%5M=6Y>ub)(nTR`+;qYxSVlj#iI) z?QHdw*B(}X_uAKLwMOBq4YZo!b*R-GuNPUJ;dQRnRbH1_jW-UTc8k@DUT?RW<@Hgk zxn7^Ly3y-at9!ieuzJwz>sC*B-D|a4lW@Q9Sk3VIp4Dux$E_B6J!N&3*H|h0>*+Oa zHJ%afp^VjvUMpD5^4iF1uGf}UH+s#qy2oors|UUIw0g>GU#r!c`U7P(!|MpEd0r!{ z1zu-ZUFCI_)!kl~Sxsve?%^h@6}{eOwY}H7toHGGpVi3g{Z?mqU2Aoo*N3ex_qxgI zTCY2-Zuk1C)!)6oX|+moe^9M9^!lFFY_Er`j`4cR>ME~gO51;hEyAZ&u-e{hBddM9 zcC@kO-_ye_jEYZdP7W~&vw z-e$GE*GH}P@w(OOMz1@p9`yQ})l**Iv|6RLKMqzKdi}_1p4ZQ<=6gMEwb1J+tE;@8 zwz}JE8GfW@`lDmDy;u9aR&VR`jXYtUf-}9YZpH4EvpT^eqc4r>qk~ccs*)$oYzxUS9v{c zb&uE9Wo-@Z!<}`qy5H*{tFaE@=qRh%Ua#i19mCOUtd{qBlhrC-*IRAjb%WKFUZ1hL z+UrYJ_j`TKYOGVZvp1|(@%paSnqCiE&GvfK>O8N-%Gsx7g-HQ(#yRyTU( zowd8Y^48k@UU|Fh39r{!P3scA8gGQH;&qkP!CraCYvh&pxX$y+yIPlf<$bJcz4DIK ztzKWWdcx})R;zRkU!q@md(5&!U1K%7Td03gdxRRRV1K#1_C3pP+b0|yXtiPAP%pHa z?RBKpabCw-o#gcftA$=~vD&a-__U|2W_#Ucb&uDVtseFIiq%;EaNF0drg{CyYE7>d z?Cq=LyjHT>CpX-7G)KLTvzk9399>~GHZauRtQLB`ypsK;9UP7pS}htG>U|s?73%j^ z3%&kfb@%9Sw359!H8v*HHdYI~=5h3*aP)GkgK?DWk2W?o-1eZ=LtYPA z9dmIw`kB=kUca+i=(Vc7`7nE2xWRm@gvXGCE(kaP%*$gS}?h`?Bo!II{n3VYSF>merG92U%@DC){A3)y-b-vwGZXth#;f zmEi^{R^#(Rjax14HPvcGuW44Rc`a$RuGi95GrX3yn(4K?)hw@PS=l{ zR$>mvzqI5xYazbBdm_`I?8I~b&S<% zUdLL^_d3pMf!Fa?mwAn>F84aY>PoMZtgiMt#p-&m)2wdxI^F74uQRL`d7Wi-x7U2D z`@GJzdeG}Ut4F*puzK8Ufz^{<7h65;wb1GruUA=(F9?tCGOMM%UTd|Y*XylT^LnGz zx?Y!C&G34Q)l9D|tY&$=-D-~4l~!}T-fK0_>l&*wysouc;B}qVWnR}?UG8;*)sl0SDdfj5R$m`QqcYEDxb)VO5Ru6jJZuN-Q9afKfEwXyj>q}No zd);aEjMrUO;|s&Xx7%uIudiFJ=yi|PYF_tRt?PB4)eNuiSk3gh-)ffE16Fgq9<-Y4 z^+T(9UJqFvj|r?y?$qPz1Ndg zH+%ij>Q=9(tQL9w#p-Uar>*Yu`kU2*UVpcG#Ot3{k9$31^`zH-te*CoR>K}&ul$q9OW#_A7;Z~El)uK>max1U1t?uzU$LfBsS6V&fb-vZ3 zUKd(D;dPPKQ(m98x^r>3-{-9AmpQ*-Rlm&neXH3^!VL~t)$euw(rTd}Jz;f)*Z*48 z?{ywj%bsgW==bklV?+5=4dXKGE80a!P7ue&+pw&qhKV+;Ob+(Kq1f8wFx7^Q$>DMv zwj_sHHtbFgb8Og`913hWlpL}r z++ss!a#&$QR&u!AhMeTE(uUmRaF-2v$zhcZW0J$YHblu`wGGpf!x|g%lfzmY3X;P* z89kbwkC%yHWVd?r)}7s9Jbo9FF9

Jm<`L4!&f#ePYyrWuq8SCV#D_2aN34_$)SEz`>(@ZBOm_4Hnd@Na%g75 z*5okBhMmdbZX3?D(dRs3Lt$GDPuj3HIXuVbB!`!6IGP;Zup!n?pYyH_HIu_fHe@G< z&uti&9C!^zVRC3;Ls5I(0l#DYf4^|OnGGAW^^wjtoU&n-{o~gEg!kEzsJlM=fDQc0 z@LBe6Gym|ve1g5!AUql^TH5{QXxM2(VK2Ka|D57Fo!{o>x^`JM`McWxu_60x{aX1l z_3a~evOL^Xh7H+vjyw$AZHS+%A;*T&$)T4G6_Z0B8>%ITem2xi4!JgDB!_`EWG08f zHe@A-p*G|shddi{lf!Tu@{+>{8^$DuQ8q-$VT=valEYXV@{_|j8w!%ccpH`_hscKI z$zg&GE0e<{8&)TWDK@N64%2MdoE&D@ur)a>wqbvAD74{Ba=6NdxLs-pkLWTRN+*YF zZK#+WuD79Da=6iky2)X=4H?Pd78^2?!wMU+lEdvbhJ(qWy$wf_Lq{8qCxP9}#gHk?il**2U>4&7~t zpP&4DZA0ng(94F3$)S%8)sjO$8|o&9TpKcy!$2D{lfz&evXaA48*-9Eo(;LlVYm%> z$zg;IW0J!t8=~Ye#)fIhVXO`L$zhxg1<7H&4a<^4WW)00Fu{hE$zhTWtCPbN8`dX> zX*O(54%2PenjB`>P?Q|z+ps%1EVSW7a#&=;spL>-!P?Q|D*>Es9Y`5V^a@b+R@#Iis!^!0E zk`1Sm!%iE{B!^u##B1n5+-*bYO%5O0ke3_|*)S$K z9JV1!4!_%QC^wb%mxE@89>|H;esz{}(wkd*6I^9`Yuy-+PsBXXWthXTd+Xz`a)L z9qsQs_&x#t!r_JChYmk5eDSmH$2R00-f*w5dUx>m9G-}*H8*A6cXU%g!6 z=U#vHmL)IvET}m63|og6hQIIdFAV?0Vf;C6^X6rl;m;lZ(D3r-+);3^=z3r00}h`w zeAFRe__V_d!)p$|ZKyiDVQ?2?KYL+YyZlRsXRmSB|H|R_41amKjp1*V+%os-vG*N( z@XF`6tt%L6+?%@A%c=k5%|GxA# zcM%!*8<&g6-VOdchZlzb<%0JxdG$x!viE}L4u8iGb$I9dnCu;VhTpo}=KW0m8;2K$ zf8_A$2blcU+uhIeLGZf{FFpi*=+O8v@R=WV_x54Xad^YkCHV(i3 z9Q>CKKQ#P(hj;p!{I3o^!(TeQVff`&+`R=@=5zRCL)hViK_)8)pJ97hX7~e#XICuy zZyi1v0{@f4*9`x&!`$$p%SE4ImVM13Zg}0{FAV?oWm%MEzv}R+;oouijN!K&zGe8^ z4hO@(ba=z?mlwpix3~Y8yX!c3pTma@uQ+_m@L7kr;TIf!$M9u`KQw&9;U61<4nHtN z9DX{%*GW2j-jH$d8Lk~}3>}A+VdC)XhPA^RhS=qD*)(@uaqwk8%i+QB4=&5HO#aZ} zr*q)@m)jWr(~r1iMJ9jG;ZF_!#Gz4Q^89jP?llNHe6S2E4nD(wepyyw@((Ylf}i@R zgS%wNd(3^_VP*J+!yAUsWm%17-@IG`+yMXE1#R&1Pr5VS@NNgUU8C;$!wzn5Md70k zZUaH#D-Ld_KjG^Re_{wY{J>Cg@O4@CI}R`Iz#lvOj^Up=^m|PHnZx%CzjC=+xz8l* z@Y4hE8xB6hZ#k@nO#W|&Hw^E(T;n`v@>Pe=7@j-)siETFTd?fc9RASoI}YJ{CjXhk z-!i=XGw!ZeOy2GAs^O~+pErEd;a?cO?e#h|F zFSprnn}6RSZunh?7luD~7k9tdv+R|Rx$pV_zUdG)_#OVjP;u}bS@xeeyzvBn;}h-< z+y~2hCtu)G4j%$HzrbCsG3) zxlL^5?!bKjy!X9**Wp{=2ETp5cfdb&c;P-G-dpz19KPppe|b*ZD}Qm>tIfywe|WFM ztMAq1U6*~@zWm;2_m|h~?>~I`$4Bf|m#yV4`^;TFr2N_C6R)4$yVvEPT|S{&H~yj9 zEA0(;C64zsMwe~S-1Rjcjt*}uz^`5=?#f7S@*565!{2mR8NPVA-2Gec*Rqhq8-}l5 z_A=`;nK=BwuyOdu11A5b!v}}pw;jfY-*fnDhL2q~Ks&JPa}NKW;pK*#Jo|vYgP(MG z)$nnLvEfq=-!pv9;nxkn=J2hzaR*YMR|7t~Ty6L4{=M!WpMA+YtnYu- z{RZ~zCAaCK_u|aob(24NoA<99_hs3g^s>w2AAQuTLwC}({yWme=kZA3`|tFplKJ3uKKlRvTPpe4w}1aV_4=lJzZ}e__4@Z;UbgQC z^VRbE?;Fkr)4{Y?U+w1I<@aA{&pO??ORIW&+*~fZ%fJ2X&)j$R>@Tlhn@m@)1)8hw z^fkB0-Q>0Q@|VB#+I-nvEnoZkYj=ZbbK35{)}3x%8xLBq&3CK*Z2C)I{Doh9Z8=zV zzc6pMN6lV$`P!f}ZF>LcxIGlVINyE$o!^?wI_q)wJNK8Tuial6pDmyNzI(p-M_zjA zC3o%a2R{1ZJ#W7KQ}2JroAH-E`rdcE`K5P%;2m%N_{*=nh9)8-|g_Shj$9^^6+lqJs#dG zywAh?g%5c6pzw-^4+%f!;lsj5Jp8!uQ4c>M{G^A!BK(wxpB8?`!(SCX=HXT0XFYt} z!&{&5@JUTR<>BXqPkZ=`@L3N(FMQ6!=Y=nL_@eNdhc5}g;NcgAU-Ix};g>ypMfj?R zuL)oG@D1Uc9=;`f+rxK+U-963NqYX0$Je1>bgu$jj>|bHUNH@cVHgpkFebXUBYMX) zAtqr;bZ<-arWr8{b7CGA#3C$-?rnRz>%AMQ>UYZ(&_*z^2%OZLtHp;+=Tz ziG8L6aR^7Edpo1|btmE!&P4aNMsK?wl z@fw!J3apAZuqNKZy4ZkCu?5>=2X@6f*c1D3Ai7_HEuo^`>>v z{W{{YDZ1Y$Jhnym8->TN=r(=z*c07v2p$LG5ROFme{OF&5#2_x7oKOLd$*!DU5M_L zP>)N|y=&3qT6Di4c-)Hajf@_5;v?LP2Y3|STOGZ{C(-wI@%h{J_=SEk0E6Nc42fYF z5u-3B#$iHC!jza6&lxexG$-a^K`g?Ocn!;91y;oySQBqyU2MRn*n(}*y+P9ZkJA<1 zn{7 zB>H|--_>*d9`ri&ivbuEuV6?F!-yD#F)7o%F$q&*8fL^S%!zqe z5R0%RUW@0lSYcWfZ(vQlg>|t3n_>&L#SZL>cd#e+;XrhMq4NG~jKndVh*LNd=Wrpq zzvk)qiYvGlH*hOHz@7Lgp7-K`=}~-wC(-w^zR+|1)#Y{Q7u~+F-nS7H-R7`5zG4_g z#3+o3ahMR3FeRp8M$E#T=ysCzzEDAQ+sS$?iEd9>k7dzqEbFl#--g*8@Ec#33Ace9OH+=uIc$6wbssT!`*(@ZRF3=ys;{ zxE9^^v>vyjd$rNyPIMd9dfba{w_1-!(QR3K;rS%Gmo~iV^LJhzzi+(`{bB$HMfbvk zw>TuaR}MTzMEBIc$C&7zl=qkrlQ1Q^r_#M?Ms!b^d(4S>SP zx5ujJp49eO6K`Q%bWdzwrst;EV%iqn)6w2-yP|vA*<(+1PcM5Mi0+wVk0WsmC*l;& zMECr$w|F7CCuck^MfcpU$F=C5kM+0}AK*@WgnQ9F5$i2JitgE0k0;SRvFh=;_iV#k zuZw5D7+@L{-JYJ_;*jVz_VgGLqcA4MVM0v8l$eGYF$;5|+Zoim=Yr_A2lZGI-J6v? zmcZ z4w;U`F`S4~I1}e^A-bnjb$rDYT#N4A;NEmAKER#$2>0Rv9>phk65UGx-d#QSo*;b7 z?Ii2bFS_kyJqE=q7!t!UB1Xk?OpG&4h)I|d(=a1uVNT4$g6Ouf^}dag=-&D5u`E_# zRlI>U@fOy_25gFMZ(Q%L+M;_SxyP<}2YX^44#XiGiDU6R5vNRNqI+Much3vaJzMT^ zDX!pJ+`z5)0C(ae+=~Zz6rbQpbX)m)U+DRJ_4tK;F#v<2+w#|291`8WzaAr^+X2{P zOmy1-drXK)@thLVOfzB@=EOWKh;9pE@2*PXH7tu2SQT$zO?2;L_ikGk8?Y(5eTltk zTkOEDcn5o89}dJJ9EoE%5vOn_x;M^WzR-Cgx)(ycue%gia4l}&R(yav@e%ID13ZdP z@Fcny|t3o1)to+PkZ^=-$`wu`Axep4f*2aR^7^7*50~oQdvb zOz)l-qI-qX<5FCS=e4+Dx)mSbPJD!W@c@tF6FiANUZr{dem#DnUkt#Ycm+dZ7)Hb> zjEQcmYwt%$h;F}Yk0~(?Gh!Cz#5^pBMe$q`ubGxb_b~;v6nS_s$RRwo7pZ*Ww0l#Ru`c6CauGMfXy& zcUMR837$mX2Q+=|y$tu(>(DO-U{Jh*A<=y>f_KjmF$!a1945phOo?fj5#6ULcz2Z( z^ROTmVM)A(Ww9cjtD^e|2JfzF;w`L;4cHW0uq}3ASGhllk@eBQ800zY?7!t!U zBD&9t@a{P##$iHC!jzbX88HiUVjdR6A}on+qjT>ImBk9IiZ`$(y1mdZi_dk@ZHVsO zwkft?TkOEDcn5o89}dJJ9EoE%5vOn_&f!9I*QR*i#!_@!vU^;M8@Lr8;7)vmd+`8| z;uAcHzE||)Klffaf9rMeO}`j`LGcQP#4wDAQ5X~BFd-&kN=(Cyn1wkp4+~-umc(mV z7AvqS-oTo83+rM7HpP~BZi^kJUGWa~#6BE|LpT!0a3W6OOq|1o=-zs#<14P6;Gi0&g@yq_o~reQ|R z!kn0g1+fTA;x#Ob6<8H-U`=$N6ytr}y4ZkCu?5>=2X@6f@!S*pOb6l+j>IvXh*LNd z=Wrpqw@d2yiYvGlH*hOHz@7LA_u>H_#V2?YeLtoz^xV7H<*nDDUkt#Ycm+dZSUg9> zDASl2hY2wWQ(_us#4OB-c~}sOuq0l?vRHvt@dnn!TUZy}hw^y;VVhzLw#5$Yig&Ol z_TfMrisz9yW;zk4a3;>-LUb1w>iCK)xE42XD?Y%T_z3sn0UpICcoKbFzV!UVdi+Aa z7=S_X3WmfmjEGSf6XW7JAtsro#5Bx^S(p>^upky;NxX(-u>z~&4XlZ`ur4-WQ*6Pu z*nwT~4)(-89Ed|W631{NPQ~*~oHJdB?z&MOUvUN3;s$QT2e=a-;a)tzqxb|*qVFR- ze!c6{-g+JS#Q+S7S1=@oVML6=m>7o%F$q&*T0CdOEYqBrhXt_+OX4*wixpTEZ(vQl zg>|t3n_>&L#SZL>cd#e+;XoY1kvN7EaSCVR94tt@r?U;v?LP z2Y3{p;7Rmx#o_ZG*W(xZ#Q+S7S1=@oVML6=m>7o%F$q&*8fL^S%!zsNTo8*)OX4*w zixpTEZ(vQlg>|t3n_>&L#SZL>cd#e+;XoY1kvN7EaSCVR9407TuzZif)@d}2-FpP*%7!%_#Atqr;Ov8+rg*nlE zn4I_H7sMhgiPz$}ELNCS#T!@?Z(&_*z^2%OZLtHp;vMXXeK-(@a3qf5M4ZBzIEM?- zU9qp@E4t6d^SBl_a4SB*o%kr8_u_%+QG9|Y(Z@x?&woOXU+5PDFeqNZkQjy$F$!a1 z945phOo?fj5wkES=3zlB!jgCm%VGsq#T)Tl6K|Q;#RhDOE!Y-2uq)odp4f*2aR^7^ z7*50~oQZR|5bxnqT*0-tfm`tb?!-s97Z30#K8fd(==(_?zur~gZ@muvVgLrkD;N^P zFd{}_OpL>Xn1m@Y4KrdE=EOWKh(%ZuuVGoNz^ZryYvL`eiw*JI6kAN&Vh47`JJ=KZ za3BuhNF2k7=sq9Pdq~d2Ib4YMa4D|fTHL^`_yBj}BixGzcod)DN%V1D|MS11$FF$y zivgxV@d}2-FpP*%7!%_#Atqr;Ov8+rg*h<~3t|zL#A{dtX{o#TIOf z9r4^1@0j+)J{*WcI1But5Em=UuuC+1;6 zEW(m_4a;H$R>d1w6K`Q%Y`~`2f^D$_yW$<}iG4T_hj1j0#q&g*GM$NYxDfB*Qe45c zxPe>o0q(>{xEBxbD7uf?^-h(O==&M*x%XbHw_b;SF#v<&6%2`C7!ji|CdOexOp51} zm}Z(0voI&-VL>dyl6VcvVg**k8(0%>VO?y%rr3gQu>-r}9qfsHI1q<$B#z-koWhwn z7tagvp6OCt!L_)7ThV=(v3JOJ;v?LP2gmn(_w_fA;uAcHKKJgq%k=qQ)#DfX#Q+S7 zS1=@oVML6=m>7o%F$q&*8fL_-c+QD=rUkJGOX4*wixpTEZ(vQlg>|t3n_>&L#SZL> zcd#e+;XoY1kvN7EaSCVR94^FrxD;37c`a_3Zp8<<6CdGTJiw#)1W%&xV;o=a?U8T2 z4*g;P21WOwtKP{F62mYeMqx~h!-SZGDKQN*VixAaJS>Ps@mvzGnU=*0tco|VCf>rj z*nmy31>0f=cEvl`6WwRbdO!X^9Kw+}h7)lLXW|?##Cy0DS8y$E;8uJP&pYvv>0Ug* zqxb|*qR+kI)qDKDs>d(%ivbuEuV6?F!-yD#F)v3m#Q+S7S1=@oVML6=m>7o%F$q&*8fL^S%!zqe5R0%R zUc<6jfmQJa*2G)!To)Tmn_>&L#SZL>cd#e+;XoY1kvN7EaSCVR94^FrxD;1#EpFge ze1JRg5$?qUJc>{7B>Fz?9pCfwkL&n~Z~Dam42oAUB!*!`jKY{0hY2wWQ(_us#4OB- zc~}sOuq0l?vRHvt@dnn!TUZwxuqn30b6e~%?TUA>C-&h$9Kw+}h7)lLXW|?##Cy0D zS8y$E;8uKqJMj_j#REKwPw*uAKEdPn6FR=oF9yVOP`qLq62mYeMqx~h!-SZGDKQN* zVixAaJS>PsSQ4*cS**aScmr$VEv$|t3n_>&L#SZL>cd#e+;XoXU=aD#OIuWOE zCeGnPyoXD11=r#RZp8<<6CdGTJiw#)1W%&xQykw<>G(pw7=S_X3WmfmjEGSf6XW7J zAtsro#5Bx^S(p>^upky;NxX(-u>z~&4XlZ`ur4-WQ*6Pu*nwT~4)(-89Ed|W631{N zPQ~*~oHJdB_i!n$;9A_kt@r?U;v?LP2Y3{p;7RoT9LM+PbbO&-48Wjx1w&#OM#LzL ziE)?^lQ1Qw#dAi?GR=v3SP+Y_BwoX^SbjoU`PzZ zh!}-2F%A=A5~jp7%!pZ-6Z7J^AQqXH#A{dtX{o#TIOf9oQA`U{CDB zfjERCaSSKo6wbssT!{B@DX!pJ+=%C`_`q~0KEl0tfJgBOo_$M>^3zR)iQ zU{Jh*Au$XiVid;2I82C1m=e=4BW7Vv%)^3MgeCDBmcPBKxPohO1GnM>+=-8HFCO4gd=k$m(f9Kl-=Ej< zg?=#rgW?qoiD4KKqcA4MVM0v8l$eGYF$;5I9u~wREQ!~!ELLDuyn!|G7S_dvcy5X< zrfsnUyW$<}iG4T_hj1j0;Y6ImnK*|F@g6S46rVn;l8#XF`wu@4905RSw#oQP966X$Rt-ovH1f@^UDx8eibiH~qE9^g@Yf+x}U zd5-Vrb$p>;48WjxC7wfKm}x|e!k8F`2{8#%Vj5<|EX;{{SP+Y_BwoX^Sb;v6o-d$<%=a4l}&R(yav@e%ID13ZdP z@Fe=a!14WpjxY3!0T>joU`PzZh!_>mF)_|GAtqr;Ov8+rg*h<~3t|zL#A{dtX{o#TIOf9oQA`U{7?Lk?Hj#aR^7^SUgX}DbtxahYQhtl&g1FOK}C);s$QT z2e=a-;a)tzqxb|*qVJ0w-!JO;LcbV*LGcQP#4wDAQ5X~BFd-(zb4pAz&4^i;6Z5bj z7GX)ehGnq=tKto;iMOyWHege1!M50eUGWa~#6BE|LpT!0a3W6OOq`47g?P_&DX!pJ z+`z5)0C(ae+=~Zz6rbQp^u5OMeND#~`o#bYidQfshG9gE!k8F`2{8#%Vj5<|ta#3e zd8P%i2utEMEQ=Lb6>nfoyoGhK0h?kAw#5$Yig&Ol_TfMr!jU+J6LAV>;v6o-d$<%= z;(0A@m~O=fxDy}YUOZg*tM2*@@rmh4^nHor`z0M;=obSpC|<#k7={rs3S(j%Cd4F6 ziD{S-voI&-VL>d4=aP8Mv@BL&RlI>U@fOy_25gEg*cLmmE8fAL*oOmg2uI==PQ)pk ziF3FR@8MEh!L_)7Tk%0W@5D!@d+`8|;uAcHzF*+@{(_D#^os!)6t7@N48w>Rg)uP> z6Jipk#5Bx^S(p>^upky;NxX(-u_B(U;tkW9cnj-d12)ALY>OS(74KkA?8AXLgd=eb zC*l;r7u_i!n$;9A_kt@r?U;v?LP2l0FqpO~IR-!F1}e^JL5`o#bYidQfshG9gE z!k8F`2{8#%Vj5<|EX;{{SP+Y_BwoX^Sb;v6o-d$<%=a4l}&R(yav@e%ID13ZdP@Fed1w6K`Q%Y`~`263=b1!?Y{j zIllM1**AM)9}dJJ9EoE%5vOn_&f!A5hf8q<*Ww0l#Rs?(AK_j+z@zvCPonS3`VpRg zS;rUp#ejGYidRfSVi-omD2$15m=KdNC8l9U%)*?QhXt_+OX4*wixpTEZ(vQlg>|uU z;jd=jY>F+WZLtHp;+=TziG8L6aR^7^7*50~oQZR|5bxnqTwUnCtF^dcx)mSbPJD!W z@c@tF6FiB&U*`D!vW_qGivbuEuV6?Fi|2?KWf~LXFd-&kN=(Cyn1wkp4+~-umc(mV z7AvqS-oTo83+rM7HpLcfiyhb%?_f{t!+|&y&m(cnbRtgSOq|1ocn_E23a-Ts+=>ry zCqBZxcz{Ro37$mXS2(_3(eZ_TF#v<&6%2`C7!jivx|1*_#x*@B#3YMTVj5<|EX;{{ zSP+Y_BwoX^SbjoU`PzZh!}-2F%A=A5~jqoc+QAf zra3VW3t|zL#A{dtX{o#TIOf9oQA`U{CDBfjERCaSSKo6wbssT!{DL zc`2@#uEh=9iVtunKEl0tfJgBOoJeS1^)2es_YvL`eiw)QmTd*y5U{}0@J+Ti5;t-C+F`S4~ zI1}e^A>PBKxPohO1GnM>+=-9kc`qKA9>phk5`Ev$|1_U}L&x_*_csE+7=S_X3Wmfm zjEGSf6XP%;CSgiU!;F}PIWZ3lViA_aYgiU5uqxh&=bCuSv@SMaQ*6Pu*nwT~4)(-8 z9Ed|W631{NPT@?P!-aScm*NVp#SPqw4{#?w!o7HaNAXEKpG4m`dHjA;#~1p=01S#( zFeHXyM2y0i7>5Zl2~%PkX2dMaiFsHMi?AeK!?IX`Rq+Pa#9LSw8{)YswwSiX4(y6| zuqXE6Kpeu6IEE8(3TNURF2sAd6jyL9Zs1mYfIIOK?!^NOT7 z+!gPb_QXCMh(kCM$8aJ};Y^&vg?JB_;tHPsSQ4*cS**aScmr$VEv$NHeo`_SXGjR?V;yql7E4UUna4SB*o%jg%;sGATCwLNl zzrykT6&+vb7XvUTUcrzUh7mCeV`3a8#H4smiD{-8F$;5I9u~wREQ!~!ELLDuyn!|G z7S_cEY>F+|7CW#j-oc*OhXZj4N8%Vx#3`JKbMd?o@0l*e62-gKkRfC(O+w2;o6xb)CEQu)5&9MegrS8IVQgVSm|B<-<`x!& zdkag#%EFqkv9KjPSlAIBE$j&g!ud#evK1$S&u{04wj6)!bqjt%z(SC4Wg$ceTZj;% z7Gi|Bg#;mKAw@`A$Pls?a)i8v0-S7PH5PQCZT1aP3TzY z67DSY2z?6!!qCEqFt#uuOfAd^a|;W?y@e%VWnoR&SlALCEbIu67WRaLg(Km~!inI! zY(ek-{5U@k@aG5NO+O)EAxOBg5F&&vL z!jiDEuqJFQYzYq*c7#U@d&0rOk?>^UMDPXe&yOJIhXp?&KsW~pSGFQV2wR8{q84I= zxP=5EX(2^OTgVWy7IK8Vg#w{yp+va0P$pC?R0%g0YJ^)0bwa~JlhCrzCUh)x33r5Z zkI=Uj1H#b4h%mM=AxtgI2y+Vy!o7thVP#=W*jU&S9xUt#j~4cXgM}mE$-;@?yR!4+ ziu1#QpAfJRBwSet5yFIXgb=kAF+$uzf{?V3BBU*32w4j`Lf%4wP_$4YTw5p;Di*4Q z8w)kUt%W+FVWCNAS!feF7P^Ex3q3;L!hkR&oJWMQt(Xv|7G{LGg$3c>!jiDEuqJFQ zYzYq*c7#U@d&0rOk?>^UMDT^|{0MP=Snv}97J`H;3n4<-LWB^t5F^A1=L8{XD^i5C zg$yBUAxFqtC=iMkN`z|*WkSV5m2hLBM!2<5Cp0WH2`vk4LdQavaA%=M=vx>Nh89MI zv4sg?N;uC5b6c?>+*?=@Ru=a&JPQILcl_h zaAhGx2wR8{q84I=xP=5EX(2^O6V4ez)>h;Qc?$(X(L#xEZJ|u4Sf~nO0SiIGm4y%?Y#~C3 zT8I(i77~P{g%lxeAw$So$Pw}u3WTDC65*O~E)y!YqDr{2P$S%0s1q6%nuL~xHlbso zOSrSpBlIl{2tx}a!q~!uFtsov%q=Vk_ZF6fm4!87V_{2pu&^UM63%&;v``{kTPPDM z7OI3B!nsDcwH0+j!$OnLvd|`UEOZHX7J7ufg#lq`VMG{Pm=LBGW`wzg1>xSplCZL{ zCTuKh2@e)_ghvZ|!ok9k@I*MD2)?+TA92nP3w}btLXdD}Aw&pUh!CO{VuZMb1R-f5 zMMzu75V96>guI0Up=hB*xVBIxR4h~pHx_DyTMKnUgK%yVTDGE1=ve3y?kw~OeG3D^ z(87o?wlE<~EzAgW3k$-%g(YESVNKXr*b*Kr>)gM}U8 z(ZZf^uy7ENlr67IuV33wy%B!jbS~ z;Y9GI?fgh{epv7m0v3XVD+?h)*g}L5wGbo3EhGp@!Z}4q+lmY!YavI-TPP5U7D|L` z3uQvZLX~i1p+>m1P$x7jGzl#WZ9>OFmvCpHN9bD^5QY{;gt3JQVQOJUm=n$m!o96n z5>^)0gpGwQ;laX=@MvLAI9NCmo-CXQzKoq88O{$2enP-PkZ@%oLJV87+M$+#ug@osf8I~Zec;Vx3DCvEUXC|3tPei z;k+X}+KN5lVBtu3vT!2!a&~^?I6o}-2>}a1!j**(A#5Q+h+2pd;uaEwq=ghAZ6QO* zTF4Rd77B!-g%aV~LYYt@oU4QzTTvt2TBs8m7Mg^Xg*KsMp-Z^4&?EFM3!jiDEuqJFQYzYq*c7#U@d&0rO zk?>^UMDP`Kew?2dI6nw)`UwFGLBf@V5Fu7ET0T z$ENlr67IuV33wy%B!jbS~;Y9G2?ffWnepv7m z0v3XVD+?h)*g}L5wGbo3EhGp@3n@aHaLy32wjxK!TPP5U7D|L`3uQvZLX~i1p+>m1 zP$x7jGzl#WZ9>OFmvCpHN9bD^5QY{;gt3JQVQOJUm|Iv7?g{55VPz}UgpGwQ;laX= z@MvLAI9NCmo-CXQzKWe670wR}enP-PkZ@%oL2-k$S$_g*u_ttIorR9e{@Q%0K)?KfB e{H?dW{K`AdlTST;=p%3Y@1MQm_7HgX?EeGsTu{>h literal 0 HcmV?d00001 diff --git a/psets/9/finance/env/lib/python3.12/site-packages/idna/__pycache__/intranges.cpython-312.pyc b/psets/9/finance/env/lib/python3.12/site-packages/idna/__pycache__/intranges.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..0b5e2384c80f060b31e70e298cb2b76f981c1a21 GIT binary patch literal 2630 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⩓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 literal 0 HcmV?d00001 diff --git a/psets/9/finance/env/lib/python3.12/site-packages/idna/codec.py b/psets/9/finance/env/lib/python3.12/site-packages/idna/codec.py new file mode 100644 index 0000000..913abfd --- /dev/null +++ b/psets/9/finance/env/lib/python3.12/site-packages/idna/codec.py @@ -0,0 +1,122 @@ +import codecs +import re +from typing import Any, Optional, Tuple + +from .core import IDNAError, alabel, decode, encode, ulabel + +_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/psets/9/finance/env/lib/python3.12/site-packages/idna/compat.py b/psets/9/finance/env/lib/python3.12/site-packages/idna/compat.py new file mode 100644 index 0000000..1df9f2a --- /dev/null +++ b/psets/9/finance/env/lib/python3.12/site-packages/idna/compat.py @@ -0,0 +1,15 @@ +from typing import Any, Union + +from .core import decode, encode + + +def ToASCII(label: str) -> bytes: + return encode(label) + + +def ToUnicode(label: Union[bytes, bytearray]) -> str: + return decode(label) + + +def nameprep(s: Any) -> None: + raise NotImplementedError("IDNA 2008 does not utilise nameprep protocol") diff --git a/psets/9/finance/env/lib/python3.12/site-packages/idna/core.py b/psets/9/finance/env/lib/python3.12/site-packages/idna/core.py new file mode 100644 index 0000000..9115f12 --- /dev/null +++ b/psets/9/finance/env/lib/python3.12/site-packages/idna/core.py @@ -0,0 +1,437 @@ +import bisect +import re +import unicodedata +from typing import Optional, Union + +from . import idnadata +from .intranges import intranges_contain + +_virama_combining_class = 9 +_alabel_prefix = b"xn--" +_unicode_dots_re = re.compile("[\u002e\u3002\uff0e\uff61]") + + +class IDNAError(UnicodeError): + """Base exception for all IDNA-encoding related problems""" + + pass + + +class IDNABidiError(IDNAError): + """Exception when bidirectional requirements are not satisfied""" + + pass + + +class InvalidCodepoint(IDNAError): + """Exception when a disallowed or unallocated codepoint is used""" + + pass + + +class InvalidCodepointContext(IDNAError): + """Exception when the codepoint is not valid in the context it is used""" + + pass + + +def _combining_class(cp: int) -> int: + v = unicodedata.combining(chr(cp)) + if v == 0: + if not unicodedata.name(chr(cp)): + raise ValueError("Unknown character in unicodedata") + return v + + +def _is_script(cp: str, script: str) -> bool: + return intranges_contain(ord(cp), idnadata.scripts[script]) + + +def _punycode(s: str) -> bytes: + return s.encode("punycode") + + +def _unot(s: int) -> str: + return "U+{:04X}".format(s) + + +def valid_label_length(label: Union[bytes, str]) -> bool: + if len(label) > 63: + return False + return True + + +def valid_string_length(label: Union[bytes, str], trailing_dot: bool) -> bool: + if len(label) > (254 if trailing_dot else 253): + return False + return True + + +def check_bidi(label: str, check_ltr: bool = False) -> bool: + # Bidi rules should only be applied if string contains RTL characters + bidi_label = False + for idx, cp in enumerate(label, 1): + direction = unicodedata.bidirectional(cp) + if direction == "": + # String likely comes from a newer version of Unicode + raise IDNABidiError("Unknown directionality in label {} at position {}".format(repr(label), idx)) + if direction in ["R", "AL", "AN"]: + bidi_label = True + if not bidi_label and not check_ltr: + return True + + # Bidi rule 1 + direction = unicodedata.bidirectional(label[0]) + if direction in ["R", "AL"]: + rtl = True + elif direction == "L": + rtl = False + else: + raise IDNABidiError("First codepoint in label {} must be directionality L, R or AL".format(repr(label))) + + valid_ending = False + number_type: Optional[str] = None + for idx, cp in enumerate(label, 1): + direction = unicodedata.bidirectional(cp) + + if rtl: + # Bidi rule 2 + if direction not in [ + "R", + "AL", + "AN", + "EN", + "ES", + "CS", + "ET", + "ON", + "BN", + "NSM", + ]: + raise IDNABidiError("Invalid direction for codepoint at position {} in a right-to-left label".format(idx)) + # Bidi rule 3 + if direction in ["R", "AL", "EN", "AN"]: + valid_ending = True + elif direction != "NSM": + valid_ending = False + # Bidi rule 4 + if direction in ["AN", "EN"]: + if not number_type: + number_type = direction + else: + if number_type != direction: + raise IDNABidiError("Can not mix numeral types in a right-to-left label") + else: + # Bidi rule 5 + if direction not in ["L", "EN", "ES", "CS", "ET", "ON", "BN", "NSM"]: + raise IDNABidiError("Invalid direction for codepoint at position {} in a left-to-right label".format(idx)) + # Bidi rule 6 + if direction in ["L", "EN"]: + valid_ending = True + elif direction != "NSM": + valid_ending = False + + if not valid_ending: + raise IDNABidiError("Label ends with illegal codepoint directionality") + + return True + + +def check_initial_combiner(label: str) -> bool: + if unicodedata.category(label[0])[0] == "M": + raise IDNAError("Label begins with an illegal combining character") + return True + + +def check_hyphen_ok(label: str) -> bool: + if label[2:4] == "--": + raise IDNAError("Label has disallowed hyphens in 3rd and 4th position") + if label[0] == "-" or label[-1] == "-": + raise IDNAError("Label must not start or end with a hyphen") + return True + + +def check_nfc(label: str) -> None: + if unicodedata.normalize("NFC", label) != label: + raise IDNAError("Label must be in Normalization Form C") + + +def valid_contextj(label: str, pos: int) -> bool: + cp_value = ord(label[pos]) + + if cp_value == 0x200C: + if pos > 0: + if _combining_class(ord(label[pos - 1])) == _virama_combining_class: + return True + + ok = False + for i in range(pos - 1, -1, -1): + joining_type = idnadata.joining_types.get(ord(label[i])) + if joining_type == ord("T"): + continue + elif joining_type in [ord("L"), ord("D")]: + ok = True + break + else: + break + + if not ok: + return False + + ok = False + for i in range(pos + 1, len(label)): + joining_type = idnadata.joining_types.get(ord(label[i])) + if joining_type == ord("T"): + continue + elif joining_type in [ord("R"), ord("D")]: + ok = True + break + else: + break + return ok + + if cp_value == 0x200D: + if pos > 0: + if _combining_class(ord(label[pos - 1])) == _virama_combining_class: + return True + return False + + else: + return False + + +def valid_contexto(label: str, pos: int, exception: bool = False) -> bool: + cp_value = ord(label[pos]) + + if cp_value == 0x00B7: + if 0 < pos < len(label) - 1: + if ord(label[pos - 1]) == 0x006C and ord(label[pos + 1]) == 0x006C: + return True + return False + + elif cp_value == 0x0375: + if pos < len(label) - 1 and len(label) > 1: + return _is_script(label[pos + 1], "Greek") + return False + + elif cp_value == 0x05F3 or cp_value == 0x05F4: + if pos > 0: + return _is_script(label[pos - 1], "Hebrew") + return False + + elif cp_value == 0x30FB: + for cp in label: + if cp == "\u30fb": + continue + if _is_script(cp, "Hiragana") or _is_script(cp, "Katakana") or _is_script(cp, "Han"): + return True + return False + + elif 0x660 <= cp_value <= 0x669: + for cp in label: + if 0x6F0 <= ord(cp) <= 0x06F9: + return False + return True + + elif 0x6F0 <= cp_value <= 0x6F9: + for cp in label: + if 0x660 <= ord(cp) <= 0x0669: + return False + return True + + return False + + +def check_label(label: Union[str, bytes, bytearray]) -> None: + if isinstance(label, (bytes, bytearray)): + label = label.decode("utf-8") + if len(label) == 0: + raise IDNAError("Empty Label") + + check_nfc(label) + check_hyphen_ok(label) + check_initial_combiner(label) + + for pos, cp in enumerate(label): + cp_value = ord(cp) + if intranges_contain(cp_value, idnadata.codepoint_classes["PVALID"]): + continue + elif intranges_contain(cp_value, idnadata.codepoint_classes["CONTEXTJ"]): + try: + if not valid_contextj(label, pos): + raise InvalidCodepointContext( + "Joiner {} not allowed at position {} in {}".format(_unot(cp_value), pos + 1, repr(label)) + ) + except ValueError: + raise IDNAError( + "Unknown codepoint adjacent to joiner {} at position {} in {}".format( + _unot(cp_value), pos + 1, repr(label) + ) + ) + elif intranges_contain(cp_value, idnadata.codepoint_classes["CONTEXTO"]): + if not valid_contexto(label, pos): + raise InvalidCodepointContext( + "Codepoint {} not allowed at position {} in {}".format(_unot(cp_value), pos + 1, repr(label)) + ) + else: + raise InvalidCodepoint( + "Codepoint {} at position {} of {} not allowed".format(_unot(cp_value), pos + 1, repr(label)) + ) + + check_bidi(label) + + +def alabel(label: str) -> bytes: + try: + label_bytes = label.encode("ascii") + ulabel(label_bytes) + if not valid_label_length(label_bytes): + raise IDNAError("Label too long") + return label_bytes + except UnicodeEncodeError: + pass + + check_label(label) + label_bytes = _alabel_prefix + _punycode(label) + + if not valid_label_length(label_bytes): + raise IDNAError("Label too long") + + return label_bytes + + +def ulabel(label: Union[str, bytes, bytearray]) -> str: + if not isinstance(label, (bytes, bytearray)): + try: + label_bytes = label.encode("ascii") + except UnicodeEncodeError: + check_label(label) + return label + else: + label_bytes = label + + label_bytes = label_bytes.lower() + if label_bytes.startswith(_alabel_prefix): + label_bytes = label_bytes[len(_alabel_prefix) :] + if not label_bytes: + raise IDNAError("Malformed A-label, no Punycode eligible content found") + if label_bytes.decode("ascii")[-1] == "-": + raise IDNAError("A-label must not end with a hyphen") + else: + check_label(label_bytes) + return label_bytes.decode("ascii") + + try: + label = label_bytes.decode("punycode") + except UnicodeError: + raise IDNAError("Invalid A-label") + check_label(label) + return label + + +def uts46_remap(domain: str, std3_rules: bool = True, transitional: bool = False) -> str: + """Re-map the characters in the string according to UTS46 processing.""" + from .uts46data import uts46data + + output = "" + + for pos, char in enumerate(domain): + code_point = ord(char) + try: + uts46row = uts46data[code_point if code_point < 256 else bisect.bisect_left(uts46data, (code_point, "Z")) - 1] + status = uts46row[1] + replacement: Optional[str] = None + if len(uts46row) == 3: + replacement = uts46row[2] + if ( + status == "V" + or (status == "D" and not transitional) + or (status == "3" and not std3_rules and replacement is None) + ): + output += char + elif replacement is not None and ( + status == "M" or (status == "3" and not std3_rules) or (status == "D" and transitional) + ): + output += replacement + elif status != "I": + raise IndexError() + except IndexError: + raise InvalidCodepoint( + "Codepoint {} not allowed at position {} in {}".format(_unot(code_point), pos + 1, repr(domain)) + ) + + return unicodedata.normalize("NFC", output) + + +def encode( + s: Union[str, bytes, bytearray], + strict: bool = False, + uts46: bool = False, + std3_rules: bool = False, + transitional: bool = False, +) -> bytes: + if not isinstance(s, str): + try: + s = str(s, "ascii") + except UnicodeDecodeError: + raise IDNAError("should pass a unicode string to the function rather than a byte string.") + if uts46: + s = uts46_remap(s, std3_rules, transitional) + trailing_dot = False + result = [] + if strict: + labels = s.split(".") + else: + labels = _unicode_dots_re.split(s) + if not labels or labels == [""]: + raise IDNAError("Empty domain") + if labels[-1] == "": + del labels[-1] + trailing_dot = True + for label in labels: + s = alabel(label) + if s: + result.append(s) + else: + raise IDNAError("Empty label") + if trailing_dot: + result.append(b"") + s = b".".join(result) + if not valid_string_length(s, trailing_dot): + raise IDNAError("Domain too long") + return s + + +def decode( + s: Union[str, bytes, bytearray], + strict: bool = False, + uts46: bool = False, + std3_rules: bool = False, +) -> str: + try: + if not isinstance(s, str): + s = str(s, "ascii") + except UnicodeDecodeError: + raise IDNAError("Invalid ASCII in A-label") + if uts46: + s = uts46_remap(s, std3_rules, False) + trailing_dot = False + result = [] + if not strict: + labels = _unicode_dots_re.split(s) + else: + labels = s.split(".") + if not labels or labels == [""]: + raise IDNAError("Empty domain") + if not labels[-1]: + del labels[-1] + trailing_dot = True + for label in labels: + s = ulabel(label) + if s: + result.append(s) + else: + raise IDNAError("Empty label") + if trailing_dot: + result.append("") + return ".".join(result) diff --git a/psets/9/finance/env/lib/python3.12/site-packages/idna/idnadata.py b/psets/9/finance/env/lib/python3.12/site-packages/idna/idnadata.py new file mode 100644 index 0000000..4be6004 --- /dev/null +++ b/psets/9/finance/env/lib/python3.12/site-packages/idna/idnadata.py @@ -0,0 +1,4243 @@ +# This file is automatically generated by tools/idna-data + +__version__ = "15.1.0" +scripts = { + "Greek": ( + 0x37000000374, + 0x37500000378, + 0x37A0000037E, + 0x37F00000380, + 0x38400000385, + 0x38600000387, + 0x3880000038B, + 0x38C0000038D, + 0x38E000003A2, + 0x3A3000003E2, + 0x3F000000400, + 0x1D2600001D2B, + 0x1D5D00001D62, + 0x1D6600001D6B, + 0x1DBF00001DC0, + 0x1F0000001F16, + 0x1F1800001F1E, + 0x1F2000001F46, + 0x1F4800001F4E, + 0x1F5000001F58, + 0x1F5900001F5A, + 0x1F5B00001F5C, + 0x1F5D00001F5E, + 0x1F5F00001F7E, + 0x1F8000001FB5, + 0x1FB600001FC5, + 0x1FC600001FD4, + 0x1FD600001FDC, + 0x1FDD00001FF0, + 0x1FF200001FF5, + 0x1FF600001FFF, + 0x212600002127, + 0xAB650000AB66, + 0x101400001018F, + 0x101A0000101A1, + 0x1D2000001D246, + ), + "Han": ( + 0x2E8000002E9A, + 0x2E9B00002EF4, + 0x2F0000002FD6, + 0x300500003006, + 0x300700003008, + 0x30210000302A, + 0x30380000303C, + 0x340000004DC0, + 0x4E000000A000, + 0xF9000000FA6E, + 0xFA700000FADA, + 0x16FE200016FE4, + 0x16FF000016FF2, + 0x200000002A6E0, + 0x2A7000002B73A, + 0x2B7400002B81E, + 0x2B8200002CEA2, + 0x2CEB00002EBE1, + 0x2EBF00002EE5E, + 0x2F8000002FA1E, + 0x300000003134B, + 0x31350000323B0, + ), + "Hebrew": ( + 0x591000005C8, + 0x5D0000005EB, + 0x5EF000005F5, + 0xFB1D0000FB37, + 0xFB380000FB3D, + 0xFB3E0000FB3F, + 0xFB400000FB42, + 0xFB430000FB45, + 0xFB460000FB50, + ), + "Hiragana": ( + 0x304100003097, + 0x309D000030A0, + 0x1B0010001B120, + 0x1B1320001B133, + 0x1B1500001B153, + 0x1F2000001F201, + ), + "Katakana": ( + 0x30A1000030FB, + 0x30FD00003100, + 0x31F000003200, + 0x32D0000032FF, + 0x330000003358, + 0xFF660000FF70, + 0xFF710000FF9E, + 0x1AFF00001AFF4, + 0x1AFF50001AFFC, + 0x1AFFD0001AFFF, + 0x1B0000001B001, + 0x1B1200001B123, + 0x1B1550001B156, + 0x1B1640001B168, + ), +} +joining_types = { + 0xAD: 84, + 0x300: 84, + 0x301: 84, + 0x302: 84, + 0x303: 84, + 0x304: 84, + 0x305: 84, + 0x306: 84, + 0x307: 84, + 0x308: 84, + 0x309: 84, + 0x30A: 84, + 0x30B: 84, + 0x30C: 84, + 0x30D: 84, + 0x30E: 84, + 0x30F: 84, + 0x310: 84, + 0x311: 84, + 0x312: 84, + 0x313: 84, + 0x314: 84, + 0x315: 84, + 0x316: 84, + 0x317: 84, + 0x318: 84, + 0x319: 84, + 0x31A: 84, + 0x31B: 84, + 0x31C: 84, + 0x31D: 84, + 0x31E: 84, + 0x31F: 84, + 0x320: 84, + 0x321: 84, + 0x322: 84, + 0x323: 84, + 0x324: 84, + 0x325: 84, + 0x326: 84, + 0x327: 84, + 0x328: 84, + 0x329: 84, + 0x32A: 84, + 0x32B: 84, + 0x32C: 84, + 0x32D: 84, + 0x32E: 84, + 0x32F: 84, + 0x330: 84, + 0x331: 84, + 0x332: 84, + 0x333: 84, + 0x334: 84, + 0x335: 84, + 0x336: 84, + 0x337: 84, + 0x338: 84, + 0x339: 84, + 0x33A: 84, + 0x33B: 84, + 0x33C: 84, + 0x33D: 84, + 0x33E: 84, + 0x33F: 84, + 0x340: 84, + 0x341: 84, + 0x342: 84, + 0x343: 84, + 0x344: 84, + 0x345: 84, + 0x346: 84, + 0x347: 84, + 0x348: 84, + 0x349: 84, + 0x34A: 84, + 0x34B: 84, + 0x34C: 84, + 0x34D: 84, + 0x34E: 84, + 0x34F: 84, + 0x350: 84, + 0x351: 84, + 0x352: 84, + 0x353: 84, + 0x354: 84, + 0x355: 84, + 0x356: 84, + 0x357: 84, + 0x358: 84, + 0x359: 84, + 0x35A: 84, + 0x35B: 84, + 0x35C: 84, + 0x35D: 84, + 0x35E: 84, + 0x35F: 84, + 0x360: 84, + 0x361: 84, + 0x362: 84, + 0x363: 84, + 0x364: 84, + 0x365: 84, + 0x366: 84, + 0x367: 84, + 0x368: 84, + 0x369: 84, + 0x36A: 84, + 0x36B: 84, + 0x36C: 84, + 0x36D: 84, + 0x36E: 84, + 0x36F: 84, + 0x483: 84, + 0x484: 84, + 0x485: 84, + 0x486: 84, + 0x487: 84, + 0x488: 84, + 0x489: 84, + 0x591: 84, + 0x592: 84, + 0x593: 84, + 0x594: 84, + 0x595: 84, + 0x596: 84, + 0x597: 84, + 0x598: 84, + 0x599: 84, + 0x59A: 84, + 0x59B: 84, + 0x59C: 84, + 0x59D: 84, + 0x59E: 84, + 0x59F: 84, + 0x5A0: 84, + 0x5A1: 84, + 0x5A2: 84, + 0x5A3: 84, + 0x5A4: 84, + 0x5A5: 84, + 0x5A6: 84, + 0x5A7: 84, + 0x5A8: 84, + 0x5A9: 84, + 0x5AA: 84, + 0x5AB: 84, + 0x5AC: 84, + 0x5AD: 84, + 0x5AE: 84, + 0x5AF: 84, + 0x5B0: 84, + 0x5B1: 84, + 0x5B2: 84, + 0x5B3: 84, + 0x5B4: 84, + 0x5B5: 84, + 0x5B6: 84, + 0x5B7: 84, + 0x5B8: 84, + 0x5B9: 84, + 0x5BA: 84, + 0x5BB: 84, + 0x5BC: 84, + 0x5BD: 84, + 0x5BF: 84, + 0x5C1: 84, + 0x5C2: 84, + 0x5C4: 84, + 0x5C5: 84, + 0x5C7: 84, + 0x610: 84, + 0x611: 84, + 0x612: 84, + 0x613: 84, + 0x614: 84, + 0x615: 84, + 0x616: 84, + 0x617: 84, + 0x618: 84, + 0x619: 84, + 0x61A: 84, + 0x61C: 84, + 0x620: 68, + 0x622: 82, + 0x623: 82, + 0x624: 82, + 0x625: 82, + 0x626: 68, + 0x627: 82, + 0x628: 68, + 0x629: 82, + 0x62A: 68, + 0x62B: 68, + 0x62C: 68, + 0x62D: 68, + 0x62E: 68, + 0x62F: 82, + 0x630: 82, + 0x631: 82, + 0x632: 82, + 0x633: 68, + 0x634: 68, + 0x635: 68, + 0x636: 68, + 0x637: 68, + 0x638: 68, + 0x639: 68, + 0x63A: 68, + 0x63B: 68, + 0x63C: 68, + 0x63D: 68, + 0x63E: 68, + 0x63F: 68, + 0x640: 67, + 0x641: 68, + 0x642: 68, + 0x643: 68, + 0x644: 68, + 0x645: 68, + 0x646: 68, + 0x647: 68, + 0x648: 82, + 0x649: 68, + 0x64A: 68, + 0x64B: 84, + 0x64C: 84, + 0x64D: 84, + 0x64E: 84, + 0x64F: 84, + 0x650: 84, + 0x651: 84, + 0x652: 84, + 0x653: 84, + 0x654: 84, + 0x655: 84, + 0x656: 84, + 0x657: 84, + 0x658: 84, + 0x659: 84, + 0x65A: 84, + 0x65B: 84, + 0x65C: 84, + 0x65D: 84, + 0x65E: 84, + 0x65F: 84, + 0x66E: 68, + 0x66F: 68, + 0x670: 84, + 0x671: 82, + 0x672: 82, + 0x673: 82, + 0x675: 82, + 0x676: 82, + 0x677: 82, + 0x678: 68, + 0x679: 68, + 0x67A: 68, + 0x67B: 68, + 0x67C: 68, + 0x67D: 68, + 0x67E: 68, + 0x67F: 68, + 0x680: 68, + 0x681: 68, + 0x682: 68, + 0x683: 68, + 0x684: 68, + 0x685: 68, + 0x686: 68, + 0x687: 68, + 0x688: 82, + 0x689: 82, + 0x68A: 82, + 0x68B: 82, + 0x68C: 82, + 0x68D: 82, + 0x68E: 82, + 0x68F: 82, + 0x690: 82, + 0x691: 82, + 0x692: 82, + 0x693: 82, + 0x694: 82, + 0x695: 82, + 0x696: 82, + 0x697: 82, + 0x698: 82, + 0x699: 82, + 0x69A: 68, + 0x69B: 68, + 0x69C: 68, + 0x69D: 68, + 0x69E: 68, + 0x69F: 68, + 0x6A0: 68, + 0x6A1: 68, + 0x6A2: 68, + 0x6A3: 68, + 0x6A4: 68, + 0x6A5: 68, + 0x6A6: 68, + 0x6A7: 68, + 0x6A8: 68, + 0x6A9: 68, + 0x6AA: 68, + 0x6AB: 68, + 0x6AC: 68, + 0x6AD: 68, + 0x6AE: 68, + 0x6AF: 68, + 0x6B0: 68, + 0x6B1: 68, + 0x6B2: 68, + 0x6B3: 68, + 0x6B4: 68, + 0x6B5: 68, + 0x6B6: 68, + 0x6B7: 68, + 0x6B8: 68, + 0x6B9: 68, + 0x6BA: 68, + 0x6BB: 68, + 0x6BC: 68, + 0x6BD: 68, + 0x6BE: 68, + 0x6BF: 68, + 0x6C0: 82, + 0x6C1: 68, + 0x6C2: 68, + 0x6C3: 82, + 0x6C4: 82, + 0x6C5: 82, + 0x6C6: 82, + 0x6C7: 82, + 0x6C8: 82, + 0x6C9: 82, + 0x6CA: 82, + 0x6CB: 82, + 0x6CC: 68, + 0x6CD: 82, + 0x6CE: 68, + 0x6CF: 82, + 0x6D0: 68, + 0x6D1: 68, + 0x6D2: 82, + 0x6D3: 82, + 0x6D5: 82, + 0x6D6: 84, + 0x6D7: 84, + 0x6D8: 84, + 0x6D9: 84, + 0x6DA: 84, + 0x6DB: 84, + 0x6DC: 84, + 0x6DF: 84, + 0x6E0: 84, + 0x6E1: 84, + 0x6E2: 84, + 0x6E3: 84, + 0x6E4: 84, + 0x6E7: 84, + 0x6E8: 84, + 0x6EA: 84, + 0x6EB: 84, + 0x6EC: 84, + 0x6ED: 84, + 0x6EE: 82, + 0x6EF: 82, + 0x6FA: 68, + 0x6FB: 68, + 0x6FC: 68, + 0x6FF: 68, + 0x70F: 84, + 0x710: 82, + 0x711: 84, + 0x712: 68, + 0x713: 68, + 0x714: 68, + 0x715: 82, + 0x716: 82, + 0x717: 82, + 0x718: 82, + 0x719: 82, + 0x71A: 68, + 0x71B: 68, + 0x71C: 68, + 0x71D: 68, + 0x71E: 82, + 0x71F: 68, + 0x720: 68, + 0x721: 68, + 0x722: 68, + 0x723: 68, + 0x724: 68, + 0x725: 68, + 0x726: 68, + 0x727: 68, + 0x728: 82, + 0x729: 68, + 0x72A: 82, + 0x72B: 68, + 0x72C: 82, + 0x72D: 68, + 0x72E: 68, + 0x72F: 82, + 0x730: 84, + 0x731: 84, + 0x732: 84, + 0x733: 84, + 0x734: 84, + 0x735: 84, + 0x736: 84, + 0x737: 84, + 0x738: 84, + 0x739: 84, + 0x73A: 84, + 0x73B: 84, + 0x73C: 84, + 0x73D: 84, + 0x73E: 84, + 0x73F: 84, + 0x740: 84, + 0x741: 84, + 0x742: 84, + 0x743: 84, + 0x744: 84, + 0x745: 84, + 0x746: 84, + 0x747: 84, + 0x748: 84, + 0x749: 84, + 0x74A: 84, + 0x74D: 82, + 0x74E: 68, + 0x74F: 68, + 0x750: 68, + 0x751: 68, + 0x752: 68, + 0x753: 68, + 0x754: 68, + 0x755: 68, + 0x756: 68, + 0x757: 68, + 0x758: 68, + 0x759: 82, + 0x75A: 82, + 0x75B: 82, + 0x75C: 68, + 0x75D: 68, + 0x75E: 68, + 0x75F: 68, + 0x760: 68, + 0x761: 68, + 0x762: 68, + 0x763: 68, + 0x764: 68, + 0x765: 68, + 0x766: 68, + 0x767: 68, + 0x768: 68, + 0x769: 68, + 0x76A: 68, + 0x76B: 82, + 0x76C: 82, + 0x76D: 68, + 0x76E: 68, + 0x76F: 68, + 0x770: 68, + 0x771: 82, + 0x772: 68, + 0x773: 82, + 0x774: 82, + 0x775: 68, + 0x776: 68, + 0x777: 68, + 0x778: 82, + 0x779: 82, + 0x77A: 68, + 0x77B: 68, + 0x77C: 68, + 0x77D: 68, + 0x77E: 68, + 0x77F: 68, + 0x7A6: 84, + 0x7A7: 84, + 0x7A8: 84, + 0x7A9: 84, + 0x7AA: 84, + 0x7AB: 84, + 0x7AC: 84, + 0x7AD: 84, + 0x7AE: 84, + 0x7AF: 84, + 0x7B0: 84, + 0x7CA: 68, + 0x7CB: 68, + 0x7CC: 68, + 0x7CD: 68, + 0x7CE: 68, + 0x7CF: 68, + 0x7D0: 68, + 0x7D1: 68, + 0x7D2: 68, + 0x7D3: 68, + 0x7D4: 68, + 0x7D5: 68, + 0x7D6: 68, + 0x7D7: 68, + 0x7D8: 68, + 0x7D9: 68, + 0x7DA: 68, + 0x7DB: 68, + 0x7DC: 68, + 0x7DD: 68, + 0x7DE: 68, + 0x7DF: 68, + 0x7E0: 68, + 0x7E1: 68, + 0x7E2: 68, + 0x7E3: 68, + 0x7E4: 68, + 0x7E5: 68, + 0x7E6: 68, + 0x7E7: 68, + 0x7E8: 68, + 0x7E9: 68, + 0x7EA: 68, + 0x7EB: 84, + 0x7EC: 84, + 0x7ED: 84, + 0x7EE: 84, + 0x7EF: 84, + 0x7F0: 84, + 0x7F1: 84, + 0x7F2: 84, + 0x7F3: 84, + 0x7FA: 67, + 0x7FD: 84, + 0x816: 84, + 0x817: 84, + 0x818: 84, + 0x819: 84, + 0x81B: 84, + 0x81C: 84, + 0x81D: 84, + 0x81E: 84, + 0x81F: 84, + 0x820: 84, + 0x821: 84, + 0x822: 84, + 0x823: 84, + 0x825: 84, + 0x826: 84, + 0x827: 84, + 0x829: 84, + 0x82A: 84, + 0x82B: 84, + 0x82C: 84, + 0x82D: 84, + 0x840: 82, + 0x841: 68, + 0x842: 68, + 0x843: 68, + 0x844: 68, + 0x845: 68, + 0x846: 82, + 0x847: 82, + 0x848: 68, + 0x849: 82, + 0x84A: 68, + 0x84B: 68, + 0x84C: 68, + 0x84D: 68, + 0x84E: 68, + 0x84F: 68, + 0x850: 68, + 0x851: 68, + 0x852: 68, + 0x853: 68, + 0x854: 82, + 0x855: 68, + 0x856: 82, + 0x857: 82, + 0x858: 82, + 0x859: 84, + 0x85A: 84, + 0x85B: 84, + 0x860: 68, + 0x862: 68, + 0x863: 68, + 0x864: 68, + 0x865: 68, + 0x867: 82, + 0x868: 68, + 0x869: 82, + 0x86A: 82, + 0x870: 82, + 0x871: 82, + 0x872: 82, + 0x873: 82, + 0x874: 82, + 0x875: 82, + 0x876: 82, + 0x877: 82, + 0x878: 82, + 0x879: 82, + 0x87A: 82, + 0x87B: 82, + 0x87C: 82, + 0x87D: 82, + 0x87E: 82, + 0x87F: 82, + 0x880: 82, + 0x881: 82, + 0x882: 82, + 0x883: 67, + 0x884: 67, + 0x885: 67, + 0x886: 68, + 0x889: 68, + 0x88A: 68, + 0x88B: 68, + 0x88C: 68, + 0x88D: 68, + 0x88E: 82, + 0x898: 84, + 0x899: 84, + 0x89A: 84, + 0x89B: 84, + 0x89C: 84, + 0x89D: 84, + 0x89E: 84, + 0x89F: 84, + 0x8A0: 68, + 0x8A1: 68, + 0x8A2: 68, + 0x8A3: 68, + 0x8A4: 68, + 0x8A5: 68, + 0x8A6: 68, + 0x8A7: 68, + 0x8A8: 68, + 0x8A9: 68, + 0x8AA: 82, + 0x8AB: 82, + 0x8AC: 82, + 0x8AE: 82, + 0x8AF: 68, + 0x8B0: 68, + 0x8B1: 82, + 0x8B2: 82, + 0x8B3: 68, + 0x8B4: 68, + 0x8B5: 68, + 0x8B6: 68, + 0x8B7: 68, + 0x8B8: 68, + 0x8B9: 82, + 0x8BA: 68, + 0x8BB: 68, + 0x8BC: 68, + 0x8BD: 68, + 0x8BE: 68, + 0x8BF: 68, + 0x8C0: 68, + 0x8C1: 68, + 0x8C2: 68, + 0x8C3: 68, + 0x8C4: 68, + 0x8C5: 68, + 0x8C6: 68, + 0x8C7: 68, + 0x8C8: 68, + 0x8CA: 84, + 0x8CB: 84, + 0x8CC: 84, + 0x8CD: 84, + 0x8CE: 84, + 0x8CF: 84, + 0x8D0: 84, + 0x8D1: 84, + 0x8D2: 84, + 0x8D3: 84, + 0x8D4: 84, + 0x8D5: 84, + 0x8D6: 84, + 0x8D7: 84, + 0x8D8: 84, + 0x8D9: 84, + 0x8DA: 84, + 0x8DB: 84, + 0x8DC: 84, + 0x8DD: 84, + 0x8DE: 84, + 0x8DF: 84, + 0x8E0: 84, + 0x8E1: 84, + 0x8E3: 84, + 0x8E4: 84, + 0x8E5: 84, + 0x8E6: 84, + 0x8E7: 84, + 0x8E8: 84, + 0x8E9: 84, + 0x8EA: 84, + 0x8EB: 84, + 0x8EC: 84, + 0x8ED: 84, + 0x8EE: 84, + 0x8EF: 84, + 0x8F0: 84, + 0x8F1: 84, + 0x8F2: 84, + 0x8F3: 84, + 0x8F4: 84, + 0x8F5: 84, + 0x8F6: 84, + 0x8F7: 84, + 0x8F8: 84, + 0x8F9: 84, + 0x8FA: 84, + 0x8FB: 84, + 0x8FC: 84, + 0x8FD: 84, + 0x8FE: 84, + 0x8FF: 84, + 0x900: 84, + 0x901: 84, + 0x902: 84, + 0x93A: 84, + 0x93C: 84, + 0x941: 84, + 0x942: 84, + 0x943: 84, + 0x944: 84, + 0x945: 84, + 0x946: 84, + 0x947: 84, + 0x948: 84, + 0x94D: 84, + 0x951: 84, + 0x952: 84, + 0x953: 84, + 0x954: 84, + 0x955: 84, + 0x956: 84, + 0x957: 84, + 0x962: 84, + 0x963: 84, + 0x981: 84, + 0x9BC: 84, + 0x9C1: 84, + 0x9C2: 84, + 0x9C3: 84, + 0x9C4: 84, + 0x9CD: 84, + 0x9E2: 84, + 0x9E3: 84, + 0x9FE: 84, + 0xA01: 84, + 0xA02: 84, + 0xA3C: 84, + 0xA41: 84, + 0xA42: 84, + 0xA47: 84, + 0xA48: 84, + 0xA4B: 84, + 0xA4C: 84, + 0xA4D: 84, + 0xA51: 84, + 0xA70: 84, + 0xA71: 84, + 0xA75: 84, + 0xA81: 84, + 0xA82: 84, + 0xABC: 84, + 0xAC1: 84, + 0xAC2: 84, + 0xAC3: 84, + 0xAC4: 84, + 0xAC5: 84, + 0xAC7: 84, + 0xAC8: 84, + 0xACD: 84, + 0xAE2: 84, + 0xAE3: 84, + 0xAFA: 84, + 0xAFB: 84, + 0xAFC: 84, + 0xAFD: 84, + 0xAFE: 84, + 0xAFF: 84, + 0xB01: 84, + 0xB3C: 84, + 0xB3F: 84, + 0xB41: 84, + 0xB42: 84, + 0xB43: 84, + 0xB44: 84, + 0xB4D: 84, + 0xB55: 84, + 0xB56: 84, + 0xB62: 84, + 0xB63: 84, + 0xB82: 84, + 0xBC0: 84, + 0xBCD: 84, + 0xC00: 84, + 0xC04: 84, + 0xC3C: 84, + 0xC3E: 84, + 0xC3F: 84, + 0xC40: 84, + 0xC46: 84, + 0xC47: 84, + 0xC48: 84, + 0xC4A: 84, + 0xC4B: 84, + 0xC4C: 84, + 0xC4D: 84, + 0xC55: 84, + 0xC56: 84, + 0xC62: 84, + 0xC63: 84, + 0xC81: 84, + 0xCBC: 84, + 0xCBF: 84, + 0xCC6: 84, + 0xCCC: 84, + 0xCCD: 84, + 0xCE2: 84, + 0xCE3: 84, + 0xD00: 84, + 0xD01: 84, + 0xD3B: 84, + 0xD3C: 84, + 0xD41: 84, + 0xD42: 84, + 0xD43: 84, + 0xD44: 84, + 0xD4D: 84, + 0xD62: 84, + 0xD63: 84, + 0xD81: 84, + 0xDCA: 84, + 0xDD2: 84, + 0xDD3: 84, + 0xDD4: 84, + 0xDD6: 84, + 0xE31: 84, + 0xE34: 84, + 0xE35: 84, + 0xE36: 84, + 0xE37: 84, + 0xE38: 84, + 0xE39: 84, + 0xE3A: 84, + 0xE47: 84, + 0xE48: 84, + 0xE49: 84, + 0xE4A: 84, + 0xE4B: 84, + 0xE4C: 84, + 0xE4D: 84, + 0xE4E: 84, + 0xEB1: 84, + 0xEB4: 84, + 0xEB5: 84, + 0xEB6: 84, + 0xEB7: 84, + 0xEB8: 84, + 0xEB9: 84, + 0xEBA: 84, + 0xEBB: 84, + 0xEBC: 84, + 0xEC8: 84, + 0xEC9: 84, + 0xECA: 84, + 0xECB: 84, + 0xECC: 84, + 0xECD: 84, + 0xECE: 84, + 0xF18: 84, + 0xF19: 84, + 0xF35: 84, + 0xF37: 84, + 0xF39: 84, + 0xF71: 84, + 0xF72: 84, + 0xF73: 84, + 0xF74: 84, + 0xF75: 84, + 0xF76: 84, + 0xF77: 84, + 0xF78: 84, + 0xF79: 84, + 0xF7A: 84, + 0xF7B: 84, + 0xF7C: 84, + 0xF7D: 84, + 0xF7E: 84, + 0xF80: 84, + 0xF81: 84, + 0xF82: 84, + 0xF83: 84, + 0xF84: 84, + 0xF86: 84, + 0xF87: 84, + 0xF8D: 84, + 0xF8E: 84, + 0xF8F: 84, + 0xF90: 84, + 0xF91: 84, + 0xF92: 84, + 0xF93: 84, + 0xF94: 84, + 0xF95: 84, + 0xF96: 84, + 0xF97: 84, + 0xF99: 84, + 0xF9A: 84, + 0xF9B: 84, + 0xF9C: 84, + 0xF9D: 84, + 0xF9E: 84, + 0xF9F: 84, + 0xFA0: 84, + 0xFA1: 84, + 0xFA2: 84, + 0xFA3: 84, + 0xFA4: 84, + 0xFA5: 84, + 0xFA6: 84, + 0xFA7: 84, + 0xFA8: 84, + 0xFA9: 84, + 0xFAA: 84, + 0xFAB: 84, + 0xFAC: 84, + 0xFAD: 84, + 0xFAE: 84, + 0xFAF: 84, + 0xFB0: 84, + 0xFB1: 84, + 0xFB2: 84, + 0xFB3: 84, + 0xFB4: 84, + 0xFB5: 84, + 0xFB6: 84, + 0xFB7: 84, + 0xFB8: 84, + 0xFB9: 84, + 0xFBA: 84, + 0xFBB: 84, + 0xFBC: 84, + 0xFC6: 84, + 0x102D: 84, + 0x102E: 84, + 0x102F: 84, + 0x1030: 84, + 0x1032: 84, + 0x1033: 84, + 0x1034: 84, + 0x1035: 84, + 0x1036: 84, + 0x1037: 84, + 0x1039: 84, + 0x103A: 84, + 0x103D: 84, + 0x103E: 84, + 0x1058: 84, + 0x1059: 84, + 0x105E: 84, + 0x105F: 84, + 0x1060: 84, + 0x1071: 84, + 0x1072: 84, + 0x1073: 84, + 0x1074: 84, + 0x1082: 84, + 0x1085: 84, + 0x1086: 84, + 0x108D: 84, + 0x109D: 84, + 0x135D: 84, + 0x135E: 84, + 0x135F: 84, + 0x1712: 84, + 0x1713: 84, + 0x1714: 84, + 0x1732: 84, + 0x1733: 84, + 0x1752: 84, + 0x1753: 84, + 0x1772: 84, + 0x1773: 84, + 0x17B4: 84, + 0x17B5: 84, + 0x17B7: 84, + 0x17B8: 84, + 0x17B9: 84, + 0x17BA: 84, + 0x17BB: 84, + 0x17BC: 84, + 0x17BD: 84, + 0x17C6: 84, + 0x17C9: 84, + 0x17CA: 84, + 0x17CB: 84, + 0x17CC: 84, + 0x17CD: 84, + 0x17CE: 84, + 0x17CF: 84, + 0x17D0: 84, + 0x17D1: 84, + 0x17D2: 84, + 0x17D3: 84, + 0x17DD: 84, + 0x1807: 68, + 0x180A: 67, + 0x180B: 84, + 0x180C: 84, + 0x180D: 84, + 0x180F: 84, + 0x1820: 68, + 0x1821: 68, + 0x1822: 68, + 0x1823: 68, + 0x1824: 68, + 0x1825: 68, + 0x1826: 68, + 0x1827: 68, + 0x1828: 68, + 0x1829: 68, + 0x182A: 68, + 0x182B: 68, + 0x182C: 68, + 0x182D: 68, + 0x182E: 68, + 0x182F: 68, + 0x1830: 68, + 0x1831: 68, + 0x1832: 68, + 0x1833: 68, + 0x1834: 68, + 0x1835: 68, + 0x1836: 68, + 0x1837: 68, + 0x1838: 68, + 0x1839: 68, + 0x183A: 68, + 0x183B: 68, + 0x183C: 68, + 0x183D: 68, + 0x183E: 68, + 0x183F: 68, + 0x1840: 68, + 0x1841: 68, + 0x1842: 68, + 0x1843: 68, + 0x1844: 68, + 0x1845: 68, + 0x1846: 68, + 0x1847: 68, + 0x1848: 68, + 0x1849: 68, + 0x184A: 68, + 0x184B: 68, + 0x184C: 68, + 0x184D: 68, + 0x184E: 68, + 0x184F: 68, + 0x1850: 68, + 0x1851: 68, + 0x1852: 68, + 0x1853: 68, + 0x1854: 68, + 0x1855: 68, + 0x1856: 68, + 0x1857: 68, + 0x1858: 68, + 0x1859: 68, + 0x185A: 68, + 0x185B: 68, + 0x185C: 68, + 0x185D: 68, + 0x185E: 68, + 0x185F: 68, + 0x1860: 68, + 0x1861: 68, + 0x1862: 68, + 0x1863: 68, + 0x1864: 68, + 0x1865: 68, + 0x1866: 68, + 0x1867: 68, + 0x1868: 68, + 0x1869: 68, + 0x186A: 68, + 0x186B: 68, + 0x186C: 68, + 0x186D: 68, + 0x186E: 68, + 0x186F: 68, + 0x1870: 68, + 0x1871: 68, + 0x1872: 68, + 0x1873: 68, + 0x1874: 68, + 0x1875: 68, + 0x1876: 68, + 0x1877: 68, + 0x1878: 68, + 0x1885: 84, + 0x1886: 84, + 0x1887: 68, + 0x1888: 68, + 0x1889: 68, + 0x188A: 68, + 0x188B: 68, + 0x188C: 68, + 0x188D: 68, + 0x188E: 68, + 0x188F: 68, + 0x1890: 68, + 0x1891: 68, + 0x1892: 68, + 0x1893: 68, + 0x1894: 68, + 0x1895: 68, + 0x1896: 68, + 0x1897: 68, + 0x1898: 68, + 0x1899: 68, + 0x189A: 68, + 0x189B: 68, + 0x189C: 68, + 0x189D: 68, + 0x189E: 68, + 0x189F: 68, + 0x18A0: 68, + 0x18A1: 68, + 0x18A2: 68, + 0x18A3: 68, + 0x18A4: 68, + 0x18A5: 68, + 0x18A6: 68, + 0x18A7: 68, + 0x18A8: 68, + 0x18A9: 84, + 0x18AA: 68, + 0x1920: 84, + 0x1921: 84, + 0x1922: 84, + 0x1927: 84, + 0x1928: 84, + 0x1932: 84, + 0x1939: 84, + 0x193A: 84, + 0x193B: 84, + 0x1A17: 84, + 0x1A18: 84, + 0x1A1B: 84, + 0x1A56: 84, + 0x1A58: 84, + 0x1A59: 84, + 0x1A5A: 84, + 0x1A5B: 84, + 0x1A5C: 84, + 0x1A5D: 84, + 0x1A5E: 84, + 0x1A60: 84, + 0x1A62: 84, + 0x1A65: 84, + 0x1A66: 84, + 0x1A67: 84, + 0x1A68: 84, + 0x1A69: 84, + 0x1A6A: 84, + 0x1A6B: 84, + 0x1A6C: 84, + 0x1A73: 84, + 0x1A74: 84, + 0x1A75: 84, + 0x1A76: 84, + 0x1A77: 84, + 0x1A78: 84, + 0x1A79: 84, + 0x1A7A: 84, + 0x1A7B: 84, + 0x1A7C: 84, + 0x1A7F: 84, + 0x1AB0: 84, + 0x1AB1: 84, + 0x1AB2: 84, + 0x1AB3: 84, + 0x1AB4: 84, + 0x1AB5: 84, + 0x1AB6: 84, + 0x1AB7: 84, + 0x1AB8: 84, + 0x1AB9: 84, + 0x1ABA: 84, + 0x1ABB: 84, + 0x1ABC: 84, + 0x1ABD: 84, + 0x1ABE: 84, + 0x1ABF: 84, + 0x1AC0: 84, + 0x1AC1: 84, + 0x1AC2: 84, + 0x1AC3: 84, + 0x1AC4: 84, + 0x1AC5: 84, + 0x1AC6: 84, + 0x1AC7: 84, + 0x1AC8: 84, + 0x1AC9: 84, + 0x1ACA: 84, + 0x1ACB: 84, + 0x1ACC: 84, + 0x1ACD: 84, + 0x1ACE: 84, + 0x1B00: 84, + 0x1B01: 84, + 0x1B02: 84, + 0x1B03: 84, + 0x1B34: 84, + 0x1B36: 84, + 0x1B37: 84, + 0x1B38: 84, + 0x1B39: 84, + 0x1B3A: 84, + 0x1B3C: 84, + 0x1B42: 84, + 0x1B6B: 84, + 0x1B6C: 84, + 0x1B6D: 84, + 0x1B6E: 84, + 0x1B6F: 84, + 0x1B70: 84, + 0x1B71: 84, + 0x1B72: 84, + 0x1B73: 84, + 0x1B80: 84, + 0x1B81: 84, + 0x1BA2: 84, + 0x1BA3: 84, + 0x1BA4: 84, + 0x1BA5: 84, + 0x1BA8: 84, + 0x1BA9: 84, + 0x1BAB: 84, + 0x1BAC: 84, + 0x1BAD: 84, + 0x1BE6: 84, + 0x1BE8: 84, + 0x1BE9: 84, + 0x1BED: 84, + 0x1BEF: 84, + 0x1BF0: 84, + 0x1BF1: 84, + 0x1C2C: 84, + 0x1C2D: 84, + 0x1C2E: 84, + 0x1C2F: 84, + 0x1C30: 84, + 0x1C31: 84, + 0x1C32: 84, + 0x1C33: 84, + 0x1C36: 84, + 0x1C37: 84, + 0x1CD0: 84, + 0x1CD1: 84, + 0x1CD2: 84, + 0x1CD4: 84, + 0x1CD5: 84, + 0x1CD6: 84, + 0x1CD7: 84, + 0x1CD8: 84, + 0x1CD9: 84, + 0x1CDA: 84, + 0x1CDB: 84, + 0x1CDC: 84, + 0x1CDD: 84, + 0x1CDE: 84, + 0x1CDF: 84, + 0x1CE0: 84, + 0x1CE2: 84, + 0x1CE3: 84, + 0x1CE4: 84, + 0x1CE5: 84, + 0x1CE6: 84, + 0x1CE7: 84, + 0x1CE8: 84, + 0x1CED: 84, + 0x1CF4: 84, + 0x1CF8: 84, + 0x1CF9: 84, + 0x1DC0: 84, + 0x1DC1: 84, + 0x1DC2: 84, + 0x1DC3: 84, + 0x1DC4: 84, + 0x1DC5: 84, + 0x1DC6: 84, + 0x1DC7: 84, + 0x1DC8: 84, + 0x1DC9: 84, + 0x1DCA: 84, + 0x1DCB: 84, + 0x1DCC: 84, + 0x1DCD: 84, + 0x1DCE: 84, + 0x1DCF: 84, + 0x1DD0: 84, + 0x1DD1: 84, + 0x1DD2: 84, + 0x1DD3: 84, + 0x1DD4: 84, + 0x1DD5: 84, + 0x1DD6: 84, + 0x1DD7: 84, + 0x1DD8: 84, + 0x1DD9: 84, + 0x1DDA: 84, + 0x1DDB: 84, + 0x1DDC: 84, + 0x1DDD: 84, + 0x1DDE: 84, + 0x1DDF: 84, + 0x1DE0: 84, + 0x1DE1: 84, + 0x1DE2: 84, + 0x1DE3: 84, + 0x1DE4: 84, + 0x1DE5: 84, + 0x1DE6: 84, + 0x1DE7: 84, + 0x1DE8: 84, + 0x1DE9: 84, + 0x1DEA: 84, + 0x1DEB: 84, + 0x1DEC: 84, + 0x1DED: 84, + 0x1DEE: 84, + 0x1DEF: 84, + 0x1DF0: 84, + 0x1DF1: 84, + 0x1DF2: 84, + 0x1DF3: 84, + 0x1DF4: 84, + 0x1DF5: 84, + 0x1DF6: 84, + 0x1DF7: 84, + 0x1DF8: 84, + 0x1DF9: 84, + 0x1DFA: 84, + 0x1DFB: 84, + 0x1DFC: 84, + 0x1DFD: 84, + 0x1DFE: 84, + 0x1DFF: 84, + 0x200B: 84, + 0x200D: 67, + 0x200E: 84, + 0x200F: 84, + 0x202A: 84, + 0x202B: 84, + 0x202C: 84, + 0x202D: 84, + 0x202E: 84, + 0x2060: 84, + 0x2061: 84, + 0x2062: 84, + 0x2063: 84, + 0x2064: 84, + 0x206A: 84, + 0x206B: 84, + 0x206C: 84, + 0x206D: 84, + 0x206E: 84, + 0x206F: 84, + 0x20D0: 84, + 0x20D1: 84, + 0x20D2: 84, + 0x20D3: 84, + 0x20D4: 84, + 0x20D5: 84, + 0x20D6: 84, + 0x20D7: 84, + 0x20D8: 84, + 0x20D9: 84, + 0x20DA: 84, + 0x20DB: 84, + 0x20DC: 84, + 0x20DD: 84, + 0x20DE: 84, + 0x20DF: 84, + 0x20E0: 84, + 0x20E1: 84, + 0x20E2: 84, + 0x20E3: 84, + 0x20E4: 84, + 0x20E5: 84, + 0x20E6: 84, + 0x20E7: 84, + 0x20E8: 84, + 0x20E9: 84, + 0x20EA: 84, + 0x20EB: 84, + 0x20EC: 84, + 0x20ED: 84, + 0x20EE: 84, + 0x20EF: 84, + 0x20F0: 84, + 0x2CEF: 84, + 0x2CF0: 84, + 0x2CF1: 84, + 0x2D7F: 84, + 0x2DE0: 84, + 0x2DE1: 84, + 0x2DE2: 84, + 0x2DE3: 84, + 0x2DE4: 84, + 0x2DE5: 84, + 0x2DE6: 84, + 0x2DE7: 84, + 0x2DE8: 84, + 0x2DE9: 84, + 0x2DEA: 84, + 0x2DEB: 84, + 0x2DEC: 84, + 0x2DED: 84, + 0x2DEE: 84, + 0x2DEF: 84, + 0x2DF0: 84, + 0x2DF1: 84, + 0x2DF2: 84, + 0x2DF3: 84, + 0x2DF4: 84, + 0x2DF5: 84, + 0x2DF6: 84, + 0x2DF7: 84, + 0x2DF8: 84, + 0x2DF9: 84, + 0x2DFA: 84, + 0x2DFB: 84, + 0x2DFC: 84, + 0x2DFD: 84, + 0x2DFE: 84, + 0x2DFF: 84, + 0x302A: 84, + 0x302B: 84, + 0x302C: 84, + 0x302D: 84, + 0x3099: 84, + 0x309A: 84, + 0xA66F: 84, + 0xA670: 84, + 0xA671: 84, + 0xA672: 84, + 0xA674: 84, + 0xA675: 84, + 0xA676: 84, + 0xA677: 84, + 0xA678: 84, + 0xA679: 84, + 0xA67A: 84, + 0xA67B: 84, + 0xA67C: 84, + 0xA67D: 84, + 0xA69E: 84, + 0xA69F: 84, + 0xA6F0: 84, + 0xA6F1: 84, + 0xA802: 84, + 0xA806: 84, + 0xA80B: 84, + 0xA825: 84, + 0xA826: 84, + 0xA82C: 84, + 0xA840: 68, + 0xA841: 68, + 0xA842: 68, + 0xA843: 68, + 0xA844: 68, + 0xA845: 68, + 0xA846: 68, + 0xA847: 68, + 0xA848: 68, + 0xA849: 68, + 0xA84A: 68, + 0xA84B: 68, + 0xA84C: 68, + 0xA84D: 68, + 0xA84E: 68, + 0xA84F: 68, + 0xA850: 68, + 0xA851: 68, + 0xA852: 68, + 0xA853: 68, + 0xA854: 68, + 0xA855: 68, + 0xA856: 68, + 0xA857: 68, + 0xA858: 68, + 0xA859: 68, + 0xA85A: 68, + 0xA85B: 68, + 0xA85C: 68, + 0xA85D: 68, + 0xA85E: 68, + 0xA85F: 68, + 0xA860: 68, + 0xA861: 68, + 0xA862: 68, + 0xA863: 68, + 0xA864: 68, + 0xA865: 68, + 0xA866: 68, + 0xA867: 68, + 0xA868: 68, + 0xA869: 68, + 0xA86A: 68, + 0xA86B: 68, + 0xA86C: 68, + 0xA86D: 68, + 0xA86E: 68, + 0xA86F: 68, + 0xA870: 68, + 0xA871: 68, + 0xA872: 76, + 0xA8C4: 84, + 0xA8C5: 84, + 0xA8E0: 84, + 0xA8E1: 84, + 0xA8E2: 84, + 0xA8E3: 84, + 0xA8E4: 84, + 0xA8E5: 84, + 0xA8E6: 84, + 0xA8E7: 84, + 0xA8E8: 84, + 0xA8E9: 84, + 0xA8EA: 84, + 0xA8EB: 84, + 0xA8EC: 84, + 0xA8ED: 84, + 0xA8EE: 84, + 0xA8EF: 84, + 0xA8F0: 84, + 0xA8F1: 84, + 0xA8FF: 84, + 0xA926: 84, + 0xA927: 84, + 0xA928: 84, + 0xA929: 84, + 0xA92A: 84, + 0xA92B: 84, + 0xA92C: 84, + 0xA92D: 84, + 0xA947: 84, + 0xA948: 84, + 0xA949: 84, + 0xA94A: 84, + 0xA94B: 84, + 0xA94C: 84, + 0xA94D: 84, + 0xA94E: 84, + 0xA94F: 84, + 0xA950: 84, + 0xA951: 84, + 0xA980: 84, + 0xA981: 84, + 0xA982: 84, + 0xA9B3: 84, + 0xA9B6: 84, + 0xA9B7: 84, + 0xA9B8: 84, + 0xA9B9: 84, + 0xA9BC: 84, + 0xA9BD: 84, + 0xA9E5: 84, + 0xAA29: 84, + 0xAA2A: 84, + 0xAA2B: 84, + 0xAA2C: 84, + 0xAA2D: 84, + 0xAA2E: 84, + 0xAA31: 84, + 0xAA32: 84, + 0xAA35: 84, + 0xAA36: 84, + 0xAA43: 84, + 0xAA4C: 84, + 0xAA7C: 84, + 0xAAB0: 84, + 0xAAB2: 84, + 0xAAB3: 84, + 0xAAB4: 84, + 0xAAB7: 84, + 0xAAB8: 84, + 0xAABE: 84, + 0xAABF: 84, + 0xAAC1: 84, + 0xAAEC: 84, + 0xAAED: 84, + 0xAAF6: 84, + 0xABE5: 84, + 0xABE8: 84, + 0xABED: 84, + 0xFB1E: 84, + 0xFE00: 84, + 0xFE01: 84, + 0xFE02: 84, + 0xFE03: 84, + 0xFE04: 84, + 0xFE05: 84, + 0xFE06: 84, + 0xFE07: 84, + 0xFE08: 84, + 0xFE09: 84, + 0xFE0A: 84, + 0xFE0B: 84, + 0xFE0C: 84, + 0xFE0D: 84, + 0xFE0E: 84, + 0xFE0F: 84, + 0xFE20: 84, + 0xFE21: 84, + 0xFE22: 84, + 0xFE23: 84, + 0xFE24: 84, + 0xFE25: 84, + 0xFE26: 84, + 0xFE27: 84, + 0xFE28: 84, + 0xFE29: 84, + 0xFE2A: 84, + 0xFE2B: 84, + 0xFE2C: 84, + 0xFE2D: 84, + 0xFE2E: 84, + 0xFE2F: 84, + 0xFEFF: 84, + 0xFFF9: 84, + 0xFFFA: 84, + 0xFFFB: 84, + 0x101FD: 84, + 0x102E0: 84, + 0x10376: 84, + 0x10377: 84, + 0x10378: 84, + 0x10379: 84, + 0x1037A: 84, + 0x10A01: 84, + 0x10A02: 84, + 0x10A03: 84, + 0x10A05: 84, + 0x10A06: 84, + 0x10A0C: 84, + 0x10A0D: 84, + 0x10A0E: 84, + 0x10A0F: 84, + 0x10A38: 84, + 0x10A39: 84, + 0x10A3A: 84, + 0x10A3F: 84, + 0x10AC0: 68, + 0x10AC1: 68, + 0x10AC2: 68, + 0x10AC3: 68, + 0x10AC4: 68, + 0x10AC5: 82, + 0x10AC7: 82, + 0x10AC9: 82, + 0x10ACA: 82, + 0x10ACD: 76, + 0x10ACE: 82, + 0x10ACF: 82, + 0x10AD0: 82, + 0x10AD1: 82, + 0x10AD2: 82, + 0x10AD3: 68, + 0x10AD4: 68, + 0x10AD5: 68, + 0x10AD6: 68, + 0x10AD7: 76, + 0x10AD8: 68, + 0x10AD9: 68, + 0x10ADA: 68, + 0x10ADB: 68, + 0x10ADC: 68, + 0x10ADD: 82, + 0x10ADE: 68, + 0x10ADF: 68, + 0x10AE0: 68, + 0x10AE1: 82, + 0x10AE4: 82, + 0x10AE5: 84, + 0x10AE6: 84, + 0x10AEB: 68, + 0x10AEC: 68, + 0x10AED: 68, + 0x10AEE: 68, + 0x10AEF: 82, + 0x10B80: 68, + 0x10B81: 82, + 0x10B82: 68, + 0x10B83: 82, + 0x10B84: 82, + 0x10B85: 82, + 0x10B86: 68, + 0x10B87: 68, + 0x10B88: 68, + 0x10B89: 82, + 0x10B8A: 68, + 0x10B8B: 68, + 0x10B8C: 82, + 0x10B8D: 68, + 0x10B8E: 82, + 0x10B8F: 82, + 0x10B90: 68, + 0x10B91: 82, + 0x10BA9: 82, + 0x10BAA: 82, + 0x10BAB: 82, + 0x10BAC: 82, + 0x10BAD: 68, + 0x10BAE: 68, + 0x10D00: 76, + 0x10D01: 68, + 0x10D02: 68, + 0x10D03: 68, + 0x10D04: 68, + 0x10D05: 68, + 0x10D06: 68, + 0x10D07: 68, + 0x10D08: 68, + 0x10D09: 68, + 0x10D0A: 68, + 0x10D0B: 68, + 0x10D0C: 68, + 0x10D0D: 68, + 0x10D0E: 68, + 0x10D0F: 68, + 0x10D10: 68, + 0x10D11: 68, + 0x10D12: 68, + 0x10D13: 68, + 0x10D14: 68, + 0x10D15: 68, + 0x10D16: 68, + 0x10D17: 68, + 0x10D18: 68, + 0x10D19: 68, + 0x10D1A: 68, + 0x10D1B: 68, + 0x10D1C: 68, + 0x10D1D: 68, + 0x10D1E: 68, + 0x10D1F: 68, + 0x10D20: 68, + 0x10D21: 68, + 0x10D22: 82, + 0x10D23: 68, + 0x10D24: 84, + 0x10D25: 84, + 0x10D26: 84, + 0x10D27: 84, + 0x10EAB: 84, + 0x10EAC: 84, + 0x10EFD: 84, + 0x10EFE: 84, + 0x10EFF: 84, + 0x10F30: 68, + 0x10F31: 68, + 0x10F32: 68, + 0x10F33: 82, + 0x10F34: 68, + 0x10F35: 68, + 0x10F36: 68, + 0x10F37: 68, + 0x10F38: 68, + 0x10F39: 68, + 0x10F3A: 68, + 0x10F3B: 68, + 0x10F3C: 68, + 0x10F3D: 68, + 0x10F3E: 68, + 0x10F3F: 68, + 0x10F40: 68, + 0x10F41: 68, + 0x10F42: 68, + 0x10F43: 68, + 0x10F44: 68, + 0x10F46: 84, + 0x10F47: 84, + 0x10F48: 84, + 0x10F49: 84, + 0x10F4A: 84, + 0x10F4B: 84, + 0x10F4C: 84, + 0x10F4D: 84, + 0x10F4E: 84, + 0x10F4F: 84, + 0x10F50: 84, + 0x10F51: 68, + 0x10F52: 68, + 0x10F53: 68, + 0x10F54: 82, + 0x10F70: 68, + 0x10F71: 68, + 0x10F72: 68, + 0x10F73: 68, + 0x10F74: 82, + 0x10F75: 82, + 0x10F76: 68, + 0x10F77: 68, + 0x10F78: 68, + 0x10F79: 68, + 0x10F7A: 68, + 0x10F7B: 68, + 0x10F7C: 68, + 0x10F7D: 68, + 0x10F7E: 68, + 0x10F7F: 68, + 0x10F80: 68, + 0x10F81: 68, + 0x10F82: 84, + 0x10F83: 84, + 0x10F84: 84, + 0x10F85: 84, + 0x10FB0: 68, + 0x10FB2: 68, + 0x10FB3: 68, + 0x10FB4: 82, + 0x10FB5: 82, + 0x10FB6: 82, + 0x10FB8: 68, + 0x10FB9: 82, + 0x10FBA: 82, + 0x10FBB: 68, + 0x10FBC: 68, + 0x10FBD: 82, + 0x10FBE: 68, + 0x10FBF: 68, + 0x10FC1: 68, + 0x10FC2: 82, + 0x10FC3: 82, + 0x10FC4: 68, + 0x10FC9: 82, + 0x10FCA: 68, + 0x10FCB: 76, + 0x11001: 84, + 0x11038: 84, + 0x11039: 84, + 0x1103A: 84, + 0x1103B: 84, + 0x1103C: 84, + 0x1103D: 84, + 0x1103E: 84, + 0x1103F: 84, + 0x11040: 84, + 0x11041: 84, + 0x11042: 84, + 0x11043: 84, + 0x11044: 84, + 0x11045: 84, + 0x11046: 84, + 0x11070: 84, + 0x11073: 84, + 0x11074: 84, + 0x1107F: 84, + 0x11080: 84, + 0x11081: 84, + 0x110B3: 84, + 0x110B4: 84, + 0x110B5: 84, + 0x110B6: 84, + 0x110B9: 84, + 0x110BA: 84, + 0x110C2: 84, + 0x11100: 84, + 0x11101: 84, + 0x11102: 84, + 0x11127: 84, + 0x11128: 84, + 0x11129: 84, + 0x1112A: 84, + 0x1112B: 84, + 0x1112D: 84, + 0x1112E: 84, + 0x1112F: 84, + 0x11130: 84, + 0x11131: 84, + 0x11132: 84, + 0x11133: 84, + 0x11134: 84, + 0x11173: 84, + 0x11180: 84, + 0x11181: 84, + 0x111B6: 84, + 0x111B7: 84, + 0x111B8: 84, + 0x111B9: 84, + 0x111BA: 84, + 0x111BB: 84, + 0x111BC: 84, + 0x111BD: 84, + 0x111BE: 84, + 0x111C9: 84, + 0x111CA: 84, + 0x111CB: 84, + 0x111CC: 84, + 0x111CF: 84, + 0x1122F: 84, + 0x11230: 84, + 0x11231: 84, + 0x11234: 84, + 0x11236: 84, + 0x11237: 84, + 0x1123E: 84, + 0x11241: 84, + 0x112DF: 84, + 0x112E3: 84, + 0x112E4: 84, + 0x112E5: 84, + 0x112E6: 84, + 0x112E7: 84, + 0x112E8: 84, + 0x112E9: 84, + 0x112EA: 84, + 0x11300: 84, + 0x11301: 84, + 0x1133B: 84, + 0x1133C: 84, + 0x11340: 84, + 0x11366: 84, + 0x11367: 84, + 0x11368: 84, + 0x11369: 84, + 0x1136A: 84, + 0x1136B: 84, + 0x1136C: 84, + 0x11370: 84, + 0x11371: 84, + 0x11372: 84, + 0x11373: 84, + 0x11374: 84, + 0x11438: 84, + 0x11439: 84, + 0x1143A: 84, + 0x1143B: 84, + 0x1143C: 84, + 0x1143D: 84, + 0x1143E: 84, + 0x1143F: 84, + 0x11442: 84, + 0x11443: 84, + 0x11444: 84, + 0x11446: 84, + 0x1145E: 84, + 0x114B3: 84, + 0x114B4: 84, + 0x114B5: 84, + 0x114B6: 84, + 0x114B7: 84, + 0x114B8: 84, + 0x114BA: 84, + 0x114BF: 84, + 0x114C0: 84, + 0x114C2: 84, + 0x114C3: 84, + 0x115B2: 84, + 0x115B3: 84, + 0x115B4: 84, + 0x115B5: 84, + 0x115BC: 84, + 0x115BD: 84, + 0x115BF: 84, + 0x115C0: 84, + 0x115DC: 84, + 0x115DD: 84, + 0x11633: 84, + 0x11634: 84, + 0x11635: 84, + 0x11636: 84, + 0x11637: 84, + 0x11638: 84, + 0x11639: 84, + 0x1163A: 84, + 0x1163D: 84, + 0x1163F: 84, + 0x11640: 84, + 0x116AB: 84, + 0x116AD: 84, + 0x116B0: 84, + 0x116B1: 84, + 0x116B2: 84, + 0x116B3: 84, + 0x116B4: 84, + 0x116B5: 84, + 0x116B7: 84, + 0x1171D: 84, + 0x1171E: 84, + 0x1171F: 84, + 0x11722: 84, + 0x11723: 84, + 0x11724: 84, + 0x11725: 84, + 0x11727: 84, + 0x11728: 84, + 0x11729: 84, + 0x1172A: 84, + 0x1172B: 84, + 0x1182F: 84, + 0x11830: 84, + 0x11831: 84, + 0x11832: 84, + 0x11833: 84, + 0x11834: 84, + 0x11835: 84, + 0x11836: 84, + 0x11837: 84, + 0x11839: 84, + 0x1183A: 84, + 0x1193B: 84, + 0x1193C: 84, + 0x1193E: 84, + 0x11943: 84, + 0x119D4: 84, + 0x119D5: 84, + 0x119D6: 84, + 0x119D7: 84, + 0x119DA: 84, + 0x119DB: 84, + 0x119E0: 84, + 0x11A01: 84, + 0x11A02: 84, + 0x11A03: 84, + 0x11A04: 84, + 0x11A05: 84, + 0x11A06: 84, + 0x11A07: 84, + 0x11A08: 84, + 0x11A09: 84, + 0x11A0A: 84, + 0x11A33: 84, + 0x11A34: 84, + 0x11A35: 84, + 0x11A36: 84, + 0x11A37: 84, + 0x11A38: 84, + 0x11A3B: 84, + 0x11A3C: 84, + 0x11A3D: 84, + 0x11A3E: 84, + 0x11A47: 84, + 0x11A51: 84, + 0x11A52: 84, + 0x11A53: 84, + 0x11A54: 84, + 0x11A55: 84, + 0x11A56: 84, + 0x11A59: 84, + 0x11A5A: 84, + 0x11A5B: 84, + 0x11A8A: 84, + 0x11A8B: 84, + 0x11A8C: 84, + 0x11A8D: 84, + 0x11A8E: 84, + 0x11A8F: 84, + 0x11A90: 84, + 0x11A91: 84, + 0x11A92: 84, + 0x11A93: 84, + 0x11A94: 84, + 0x11A95: 84, + 0x11A96: 84, + 0x11A98: 84, + 0x11A99: 84, + 0x11C30: 84, + 0x11C31: 84, + 0x11C32: 84, + 0x11C33: 84, + 0x11C34: 84, + 0x11C35: 84, + 0x11C36: 84, + 0x11C38: 84, + 0x11C39: 84, + 0x11C3A: 84, + 0x11C3B: 84, + 0x11C3C: 84, + 0x11C3D: 84, + 0x11C3F: 84, + 0x11C92: 84, + 0x11C93: 84, + 0x11C94: 84, + 0x11C95: 84, + 0x11C96: 84, + 0x11C97: 84, + 0x11C98: 84, + 0x11C99: 84, + 0x11C9A: 84, + 0x11C9B: 84, + 0x11C9C: 84, + 0x11C9D: 84, + 0x11C9E: 84, + 0x11C9F: 84, + 0x11CA0: 84, + 0x11CA1: 84, + 0x11CA2: 84, + 0x11CA3: 84, + 0x11CA4: 84, + 0x11CA5: 84, + 0x11CA6: 84, + 0x11CA7: 84, + 0x11CAA: 84, + 0x11CAB: 84, + 0x11CAC: 84, + 0x11CAD: 84, + 0x11CAE: 84, + 0x11CAF: 84, + 0x11CB0: 84, + 0x11CB2: 84, + 0x11CB3: 84, + 0x11CB5: 84, + 0x11CB6: 84, + 0x11D31: 84, + 0x11D32: 84, + 0x11D33: 84, + 0x11D34: 84, + 0x11D35: 84, + 0x11D36: 84, + 0x11D3A: 84, + 0x11D3C: 84, + 0x11D3D: 84, + 0x11D3F: 84, + 0x11D40: 84, + 0x11D41: 84, + 0x11D42: 84, + 0x11D43: 84, + 0x11D44: 84, + 0x11D45: 84, + 0x11D47: 84, + 0x11D90: 84, + 0x11D91: 84, + 0x11D95: 84, + 0x11D97: 84, + 0x11EF3: 84, + 0x11EF4: 84, + 0x11F00: 84, + 0x11F01: 84, + 0x11F36: 84, + 0x11F37: 84, + 0x11F38: 84, + 0x11F39: 84, + 0x11F3A: 84, + 0x11F40: 84, + 0x11F42: 84, + 0x13430: 84, + 0x13431: 84, + 0x13432: 84, + 0x13433: 84, + 0x13434: 84, + 0x13435: 84, + 0x13436: 84, + 0x13437: 84, + 0x13438: 84, + 0x13439: 84, + 0x1343A: 84, + 0x1343B: 84, + 0x1343C: 84, + 0x1343D: 84, + 0x1343E: 84, + 0x1343F: 84, + 0x13440: 84, + 0x13447: 84, + 0x13448: 84, + 0x13449: 84, + 0x1344A: 84, + 0x1344B: 84, + 0x1344C: 84, + 0x1344D: 84, + 0x1344E: 84, + 0x1344F: 84, + 0x13450: 84, + 0x13451: 84, + 0x13452: 84, + 0x13453: 84, + 0x13454: 84, + 0x13455: 84, + 0x16AF0: 84, + 0x16AF1: 84, + 0x16AF2: 84, + 0x16AF3: 84, + 0x16AF4: 84, + 0x16B30: 84, + 0x16B31: 84, + 0x16B32: 84, + 0x16B33: 84, + 0x16B34: 84, + 0x16B35: 84, + 0x16B36: 84, + 0x16F4F: 84, + 0x16F8F: 84, + 0x16F90: 84, + 0x16F91: 84, + 0x16F92: 84, + 0x16FE4: 84, + 0x1BC9D: 84, + 0x1BC9E: 84, + 0x1BCA0: 84, + 0x1BCA1: 84, + 0x1BCA2: 84, + 0x1BCA3: 84, + 0x1CF00: 84, + 0x1CF01: 84, + 0x1CF02: 84, + 0x1CF03: 84, + 0x1CF04: 84, + 0x1CF05: 84, + 0x1CF06: 84, + 0x1CF07: 84, + 0x1CF08: 84, + 0x1CF09: 84, + 0x1CF0A: 84, + 0x1CF0B: 84, + 0x1CF0C: 84, + 0x1CF0D: 84, + 0x1CF0E: 84, + 0x1CF0F: 84, + 0x1CF10: 84, + 0x1CF11: 84, + 0x1CF12: 84, + 0x1CF13: 84, + 0x1CF14: 84, + 0x1CF15: 84, + 0x1CF16: 84, + 0x1CF17: 84, + 0x1CF18: 84, + 0x1CF19: 84, + 0x1CF1A: 84, + 0x1CF1B: 84, + 0x1CF1C: 84, + 0x1CF1D: 84, + 0x1CF1E: 84, + 0x1CF1F: 84, + 0x1CF20: 84, + 0x1CF21: 84, + 0x1CF22: 84, + 0x1CF23: 84, + 0x1CF24: 84, + 0x1CF25: 84, + 0x1CF26: 84, + 0x1CF27: 84, + 0x1CF28: 84, + 0x1CF29: 84, + 0x1CF2A: 84, + 0x1CF2B: 84, + 0x1CF2C: 84, + 0x1CF2D: 84, + 0x1CF30: 84, + 0x1CF31: 84, + 0x1CF32: 84, + 0x1CF33: 84, + 0x1CF34: 84, + 0x1CF35: 84, + 0x1CF36: 84, + 0x1CF37: 84, + 0x1CF38: 84, + 0x1CF39: 84, + 0x1CF3A: 84, + 0x1CF3B: 84, + 0x1CF3C: 84, + 0x1CF3D: 84, + 0x1CF3E: 84, + 0x1CF3F: 84, + 0x1CF40: 84, + 0x1CF41: 84, + 0x1CF42: 84, + 0x1CF43: 84, + 0x1CF44: 84, + 0x1CF45: 84, + 0x1CF46: 84, + 0x1D167: 84, + 0x1D168: 84, + 0x1D169: 84, + 0x1D173: 84, + 0x1D174: 84, + 0x1D175: 84, + 0x1D176: 84, + 0x1D177: 84, + 0x1D178: 84, + 0x1D179: 84, + 0x1D17A: 84, + 0x1D17B: 84, + 0x1D17C: 84, + 0x1D17D: 84, + 0x1D17E: 84, + 0x1D17F: 84, + 0x1D180: 84, + 0x1D181: 84, + 0x1D182: 84, + 0x1D185: 84, + 0x1D186: 84, + 0x1D187: 84, + 0x1D188: 84, + 0x1D189: 84, + 0x1D18A: 84, + 0x1D18B: 84, + 0x1D1AA: 84, + 0x1D1AB: 84, + 0x1D1AC: 84, + 0x1D1AD: 84, + 0x1D242: 84, + 0x1D243: 84, + 0x1D244: 84, + 0x1DA00: 84, + 0x1DA01: 84, + 0x1DA02: 84, + 0x1DA03: 84, + 0x1DA04: 84, + 0x1DA05: 84, + 0x1DA06: 84, + 0x1DA07: 84, + 0x1DA08: 84, + 0x1DA09: 84, + 0x1DA0A: 84, + 0x1DA0B: 84, + 0x1DA0C: 84, + 0x1DA0D: 84, + 0x1DA0E: 84, + 0x1DA0F: 84, + 0x1DA10: 84, + 0x1DA11: 84, + 0x1DA12: 84, + 0x1DA13: 84, + 0x1DA14: 84, + 0x1DA15: 84, + 0x1DA16: 84, + 0x1DA17: 84, + 0x1DA18: 84, + 0x1DA19: 84, + 0x1DA1A: 84, + 0x1DA1B: 84, + 0x1DA1C: 84, + 0x1DA1D: 84, + 0x1DA1E: 84, + 0x1DA1F: 84, + 0x1DA20: 84, + 0x1DA21: 84, + 0x1DA22: 84, + 0x1DA23: 84, + 0x1DA24: 84, + 0x1DA25: 84, + 0x1DA26: 84, + 0x1DA27: 84, + 0x1DA28: 84, + 0x1DA29: 84, + 0x1DA2A: 84, + 0x1DA2B: 84, + 0x1DA2C: 84, + 0x1DA2D: 84, + 0x1DA2E: 84, + 0x1DA2F: 84, + 0x1DA30: 84, + 0x1DA31: 84, + 0x1DA32: 84, + 0x1DA33: 84, + 0x1DA34: 84, + 0x1DA35: 84, + 0x1DA36: 84, + 0x1DA3B: 84, + 0x1DA3C: 84, + 0x1DA3D: 84, + 0x1DA3E: 84, + 0x1DA3F: 84, + 0x1DA40: 84, + 0x1DA41: 84, + 0x1DA42: 84, + 0x1DA43: 84, + 0x1DA44: 84, + 0x1DA45: 84, + 0x1DA46: 84, + 0x1DA47: 84, + 0x1DA48: 84, + 0x1DA49: 84, + 0x1DA4A: 84, + 0x1DA4B: 84, + 0x1DA4C: 84, + 0x1DA4D: 84, + 0x1DA4E: 84, + 0x1DA4F: 84, + 0x1DA50: 84, + 0x1DA51: 84, + 0x1DA52: 84, + 0x1DA53: 84, + 0x1DA54: 84, + 0x1DA55: 84, + 0x1DA56: 84, + 0x1DA57: 84, + 0x1DA58: 84, + 0x1DA59: 84, + 0x1DA5A: 84, + 0x1DA5B: 84, + 0x1DA5C: 84, + 0x1DA5D: 84, + 0x1DA5E: 84, + 0x1DA5F: 84, + 0x1DA60: 84, + 0x1DA61: 84, + 0x1DA62: 84, + 0x1DA63: 84, + 0x1DA64: 84, + 0x1DA65: 84, + 0x1DA66: 84, + 0x1DA67: 84, + 0x1DA68: 84, + 0x1DA69: 84, + 0x1DA6A: 84, + 0x1DA6B: 84, + 0x1DA6C: 84, + 0x1DA75: 84, + 0x1DA84: 84, + 0x1DA9B: 84, + 0x1DA9C: 84, + 0x1DA9D: 84, + 0x1DA9E: 84, + 0x1DA9F: 84, + 0x1DAA1: 84, + 0x1DAA2: 84, + 0x1DAA3: 84, + 0x1DAA4: 84, + 0x1DAA5: 84, + 0x1DAA6: 84, + 0x1DAA7: 84, + 0x1DAA8: 84, + 0x1DAA9: 84, + 0x1DAAA: 84, + 0x1DAAB: 84, + 0x1DAAC: 84, + 0x1DAAD: 84, + 0x1DAAE: 84, + 0x1DAAF: 84, + 0x1E000: 84, + 0x1E001: 84, + 0x1E002: 84, + 0x1E003: 84, + 0x1E004: 84, + 0x1E005: 84, + 0x1E006: 84, + 0x1E008: 84, + 0x1E009: 84, + 0x1E00A: 84, + 0x1E00B: 84, + 0x1E00C: 84, + 0x1E00D: 84, + 0x1E00E: 84, + 0x1E00F: 84, + 0x1E010: 84, + 0x1E011: 84, + 0x1E012: 84, + 0x1E013: 84, + 0x1E014: 84, + 0x1E015: 84, + 0x1E016: 84, + 0x1E017: 84, + 0x1E018: 84, + 0x1E01B: 84, + 0x1E01C: 84, + 0x1E01D: 84, + 0x1E01E: 84, + 0x1E01F: 84, + 0x1E020: 84, + 0x1E021: 84, + 0x1E023: 84, + 0x1E024: 84, + 0x1E026: 84, + 0x1E027: 84, + 0x1E028: 84, + 0x1E029: 84, + 0x1E02A: 84, + 0x1E08F: 84, + 0x1E130: 84, + 0x1E131: 84, + 0x1E132: 84, + 0x1E133: 84, + 0x1E134: 84, + 0x1E135: 84, + 0x1E136: 84, + 0x1E2AE: 84, + 0x1E2EC: 84, + 0x1E2ED: 84, + 0x1E2EE: 84, + 0x1E2EF: 84, + 0x1E4EC: 84, + 0x1E4ED: 84, + 0x1E4EE: 84, + 0x1E4EF: 84, + 0x1E8D0: 84, + 0x1E8D1: 84, + 0x1E8D2: 84, + 0x1E8D3: 84, + 0x1E8D4: 84, + 0x1E8D5: 84, + 0x1E8D6: 84, + 0x1E900: 68, + 0x1E901: 68, + 0x1E902: 68, + 0x1E903: 68, + 0x1E904: 68, + 0x1E905: 68, + 0x1E906: 68, + 0x1E907: 68, + 0x1E908: 68, + 0x1E909: 68, + 0x1E90A: 68, + 0x1E90B: 68, + 0x1E90C: 68, + 0x1E90D: 68, + 0x1E90E: 68, + 0x1E90F: 68, + 0x1E910: 68, + 0x1E911: 68, + 0x1E912: 68, + 0x1E913: 68, + 0x1E914: 68, + 0x1E915: 68, + 0x1E916: 68, + 0x1E917: 68, + 0x1E918: 68, + 0x1E919: 68, + 0x1E91A: 68, + 0x1E91B: 68, + 0x1E91C: 68, + 0x1E91D: 68, + 0x1E91E: 68, + 0x1E91F: 68, + 0x1E920: 68, + 0x1E921: 68, + 0x1E922: 68, + 0x1E923: 68, + 0x1E924: 68, + 0x1E925: 68, + 0x1E926: 68, + 0x1E927: 68, + 0x1E928: 68, + 0x1E929: 68, + 0x1E92A: 68, + 0x1E92B: 68, + 0x1E92C: 68, + 0x1E92D: 68, + 0x1E92E: 68, + 0x1E92F: 68, + 0x1E930: 68, + 0x1E931: 68, + 0x1E932: 68, + 0x1E933: 68, + 0x1E934: 68, + 0x1E935: 68, + 0x1E936: 68, + 0x1E937: 68, + 0x1E938: 68, + 0x1E939: 68, + 0x1E93A: 68, + 0x1E93B: 68, + 0x1E93C: 68, + 0x1E93D: 68, + 0x1E93E: 68, + 0x1E93F: 68, + 0x1E940: 68, + 0x1E941: 68, + 0x1E942: 68, + 0x1E943: 68, + 0x1E944: 84, + 0x1E945: 84, + 0x1E946: 84, + 0x1E947: 84, + 0x1E948: 84, + 0x1E949: 84, + 0x1E94A: 84, + 0x1E94B: 84, + 0xE0001: 84, + 0xE0020: 84, + 0xE0021: 84, + 0xE0022: 84, + 0xE0023: 84, + 0xE0024: 84, + 0xE0025: 84, + 0xE0026: 84, + 0xE0027: 84, + 0xE0028: 84, + 0xE0029: 84, + 0xE002A: 84, + 0xE002B: 84, + 0xE002C: 84, + 0xE002D: 84, + 0xE002E: 84, + 0xE002F: 84, + 0xE0030: 84, + 0xE0031: 84, + 0xE0032: 84, + 0xE0033: 84, + 0xE0034: 84, + 0xE0035: 84, + 0xE0036: 84, + 0xE0037: 84, + 0xE0038: 84, + 0xE0039: 84, + 0xE003A: 84, + 0xE003B: 84, + 0xE003C: 84, + 0xE003D: 84, + 0xE003E: 84, + 0xE003F: 84, + 0xE0040: 84, + 0xE0041: 84, + 0xE0042: 84, + 0xE0043: 84, + 0xE0044: 84, + 0xE0045: 84, + 0xE0046: 84, + 0xE0047: 84, + 0xE0048: 84, + 0xE0049: 84, + 0xE004A: 84, + 0xE004B: 84, + 0xE004C: 84, + 0xE004D: 84, + 0xE004E: 84, + 0xE004F: 84, + 0xE0050: 84, + 0xE0051: 84, + 0xE0052: 84, + 0xE0053: 84, + 0xE0054: 84, + 0xE0055: 84, + 0xE0056: 84, + 0xE0057: 84, + 0xE0058: 84, + 0xE0059: 84, + 0xE005A: 84, + 0xE005B: 84, + 0xE005C: 84, + 0xE005D: 84, + 0xE005E: 84, + 0xE005F: 84, + 0xE0060: 84, + 0xE0061: 84, + 0xE0062: 84, + 0xE0063: 84, + 0xE0064: 84, + 0xE0065: 84, + 0xE0066: 84, + 0xE0067: 84, + 0xE0068: 84, + 0xE0069: 84, + 0xE006A: 84, + 0xE006B: 84, + 0xE006C: 84, + 0xE006D: 84, + 0xE006E: 84, + 0xE006F: 84, + 0xE0070: 84, + 0xE0071: 84, + 0xE0072: 84, + 0xE0073: 84, + 0xE0074: 84, + 0xE0075: 84, + 0xE0076: 84, + 0xE0077: 84, + 0xE0078: 84, + 0xE0079: 84, + 0xE007A: 84, + 0xE007B: 84, + 0xE007C: 84, + 0xE007D: 84, + 0xE007E: 84, + 0xE007F: 84, + 0xE0100: 84, + 0xE0101: 84, + 0xE0102: 84, + 0xE0103: 84, + 0xE0104: 84, + 0xE0105: 84, + 0xE0106: 84, + 0xE0107: 84, + 0xE0108: 84, + 0xE0109: 84, + 0xE010A: 84, + 0xE010B: 84, + 0xE010C: 84, + 0xE010D: 84, + 0xE010E: 84, + 0xE010F: 84, + 0xE0110: 84, + 0xE0111: 84, + 0xE0112: 84, + 0xE0113: 84, + 0xE0114: 84, + 0xE0115: 84, + 0xE0116: 84, + 0xE0117: 84, + 0xE0118: 84, + 0xE0119: 84, + 0xE011A: 84, + 0xE011B: 84, + 0xE011C: 84, + 0xE011D: 84, + 0xE011E: 84, + 0xE011F: 84, + 0xE0120: 84, + 0xE0121: 84, + 0xE0122: 84, + 0xE0123: 84, + 0xE0124: 84, + 0xE0125: 84, + 0xE0126: 84, + 0xE0127: 84, + 0xE0128: 84, + 0xE0129: 84, + 0xE012A: 84, + 0xE012B: 84, + 0xE012C: 84, + 0xE012D: 84, + 0xE012E: 84, + 0xE012F: 84, + 0xE0130: 84, + 0xE0131: 84, + 0xE0132: 84, + 0xE0133: 84, + 0xE0134: 84, + 0xE0135: 84, + 0xE0136: 84, + 0xE0137: 84, + 0xE0138: 84, + 0xE0139: 84, + 0xE013A: 84, + 0xE013B: 84, + 0xE013C: 84, + 0xE013D: 84, + 0xE013E: 84, + 0xE013F: 84, + 0xE0140: 84, + 0xE0141: 84, + 0xE0142: 84, + 0xE0143: 84, + 0xE0144: 84, + 0xE0145: 84, + 0xE0146: 84, + 0xE0147: 84, + 0xE0148: 84, + 0xE0149: 84, + 0xE014A: 84, + 0xE014B: 84, + 0xE014C: 84, + 0xE014D: 84, + 0xE014E: 84, + 0xE014F: 84, + 0xE0150: 84, + 0xE0151: 84, + 0xE0152: 84, + 0xE0153: 84, + 0xE0154: 84, + 0xE0155: 84, + 0xE0156: 84, + 0xE0157: 84, + 0xE0158: 84, + 0xE0159: 84, + 0xE015A: 84, + 0xE015B: 84, + 0xE015C: 84, + 0xE015D: 84, + 0xE015E: 84, + 0xE015F: 84, + 0xE0160: 84, + 0xE0161: 84, + 0xE0162: 84, + 0xE0163: 84, + 0xE0164: 84, + 0xE0165: 84, + 0xE0166: 84, + 0xE0167: 84, + 0xE0168: 84, + 0xE0169: 84, + 0xE016A: 84, + 0xE016B: 84, + 0xE016C: 84, + 0xE016D: 84, + 0xE016E: 84, + 0xE016F: 84, + 0xE0170: 84, + 0xE0171: 84, + 0xE0172: 84, + 0xE0173: 84, + 0xE0174: 84, + 0xE0175: 84, + 0xE0176: 84, + 0xE0177: 84, + 0xE0178: 84, + 0xE0179: 84, + 0xE017A: 84, + 0xE017B: 84, + 0xE017C: 84, + 0xE017D: 84, + 0xE017E: 84, + 0xE017F: 84, + 0xE0180: 84, + 0xE0181: 84, + 0xE0182: 84, + 0xE0183: 84, + 0xE0184: 84, + 0xE0185: 84, + 0xE0186: 84, + 0xE0187: 84, + 0xE0188: 84, + 0xE0189: 84, + 0xE018A: 84, + 0xE018B: 84, + 0xE018C: 84, + 0xE018D: 84, + 0xE018E: 84, + 0xE018F: 84, + 0xE0190: 84, + 0xE0191: 84, + 0xE0192: 84, + 0xE0193: 84, + 0xE0194: 84, + 0xE0195: 84, + 0xE0196: 84, + 0xE0197: 84, + 0xE0198: 84, + 0xE0199: 84, + 0xE019A: 84, + 0xE019B: 84, + 0xE019C: 84, + 0xE019D: 84, + 0xE019E: 84, + 0xE019F: 84, + 0xE01A0: 84, + 0xE01A1: 84, + 0xE01A2: 84, + 0xE01A3: 84, + 0xE01A4: 84, + 0xE01A5: 84, + 0xE01A6: 84, + 0xE01A7: 84, + 0xE01A8: 84, + 0xE01A9: 84, + 0xE01AA: 84, + 0xE01AB: 84, + 0xE01AC: 84, + 0xE01AD: 84, + 0xE01AE: 84, + 0xE01AF: 84, + 0xE01B0: 84, + 0xE01B1: 84, + 0xE01B2: 84, + 0xE01B3: 84, + 0xE01B4: 84, + 0xE01B5: 84, + 0xE01B6: 84, + 0xE01B7: 84, + 0xE01B8: 84, + 0xE01B9: 84, + 0xE01BA: 84, + 0xE01BB: 84, + 0xE01BC: 84, + 0xE01BD: 84, + 0xE01BE: 84, + 0xE01BF: 84, + 0xE01C0: 84, + 0xE01C1: 84, + 0xE01C2: 84, + 0xE01C3: 84, + 0xE01C4: 84, + 0xE01C5: 84, + 0xE01C6: 84, + 0xE01C7: 84, + 0xE01C8: 84, + 0xE01C9: 84, + 0xE01CA: 84, + 0xE01CB: 84, + 0xE01CC: 84, + 0xE01CD: 84, + 0xE01CE: 84, + 0xE01CF: 84, + 0xE01D0: 84, + 0xE01D1: 84, + 0xE01D2: 84, + 0xE01D3: 84, + 0xE01D4: 84, + 0xE01D5: 84, + 0xE01D6: 84, + 0xE01D7: 84, + 0xE01D8: 84, + 0xE01D9: 84, + 0xE01DA: 84, + 0xE01DB: 84, + 0xE01DC: 84, + 0xE01DD: 84, + 0xE01DE: 84, + 0xE01DF: 84, + 0xE01E0: 84, + 0xE01E1: 84, + 0xE01E2: 84, + 0xE01E3: 84, + 0xE01E4: 84, + 0xE01E5: 84, + 0xE01E6: 84, + 0xE01E7: 84, + 0xE01E8: 84, + 0xE01E9: 84, + 0xE01EA: 84, + 0xE01EB: 84, + 0xE01EC: 84, + 0xE01ED: 84, + 0xE01EE: 84, + 0xE01EF: 84, +} +codepoint_classes = { + "PVALID": ( + 0x2D0000002E, + 0x300000003A, + 0x610000007B, + 0xDF000000F7, + 0xF800000100, + 0x10100000102, + 0x10300000104, + 0x10500000106, + 0x10700000108, + 0x1090000010A, + 0x10B0000010C, + 0x10D0000010E, + 0x10F00000110, + 0x11100000112, + 0x11300000114, + 0x11500000116, + 0x11700000118, + 0x1190000011A, + 0x11B0000011C, + 0x11D0000011E, + 0x11F00000120, + 0x12100000122, + 0x12300000124, + 0x12500000126, + 0x12700000128, + 0x1290000012A, + 0x12B0000012C, + 0x12D0000012E, + 0x12F00000130, + 0x13100000132, + 0x13500000136, + 0x13700000139, + 0x13A0000013B, + 0x13C0000013D, + 0x13E0000013F, + 0x14200000143, + 0x14400000145, + 0x14600000147, + 0x14800000149, + 0x14B0000014C, + 0x14D0000014E, + 0x14F00000150, + 0x15100000152, + 0x15300000154, + 0x15500000156, + 0x15700000158, + 0x1590000015A, + 0x15B0000015C, + 0x15D0000015E, + 0x15F00000160, + 0x16100000162, + 0x16300000164, + 0x16500000166, + 0x16700000168, + 0x1690000016A, + 0x16B0000016C, + 0x16D0000016E, + 0x16F00000170, + 0x17100000172, + 0x17300000174, + 0x17500000176, + 0x17700000178, + 0x17A0000017B, + 0x17C0000017D, + 0x17E0000017F, + 0x18000000181, + 0x18300000184, + 0x18500000186, + 0x18800000189, + 0x18C0000018E, + 0x19200000193, + 0x19500000196, + 0x1990000019C, + 0x19E0000019F, + 0x1A1000001A2, + 0x1A3000001A4, + 0x1A5000001A6, + 0x1A8000001A9, + 0x1AA000001AC, + 0x1AD000001AE, + 0x1B0000001B1, + 0x1B4000001B5, + 0x1B6000001B7, + 0x1B9000001BC, + 0x1BD000001C4, + 0x1CE000001CF, + 0x1D0000001D1, + 0x1D2000001D3, + 0x1D4000001D5, + 0x1D6000001D7, + 0x1D8000001D9, + 0x1DA000001DB, + 0x1DC000001DE, + 0x1DF000001E0, + 0x1E1000001E2, + 0x1E3000001E4, + 0x1E5000001E6, + 0x1E7000001E8, + 0x1E9000001EA, + 0x1EB000001EC, + 0x1ED000001EE, + 0x1EF000001F1, + 0x1F5000001F6, + 0x1F9000001FA, + 0x1FB000001FC, + 0x1FD000001FE, + 0x1FF00000200, + 0x20100000202, + 0x20300000204, + 0x20500000206, + 0x20700000208, + 0x2090000020A, + 0x20B0000020C, + 0x20D0000020E, + 0x20F00000210, + 0x21100000212, + 0x21300000214, + 0x21500000216, + 0x21700000218, + 0x2190000021A, + 0x21B0000021C, + 0x21D0000021E, + 0x21F00000220, + 0x22100000222, + 0x22300000224, + 0x22500000226, + 0x22700000228, + 0x2290000022A, + 0x22B0000022C, + 0x22D0000022E, + 0x22F00000230, + 0x23100000232, + 0x2330000023A, + 0x23C0000023D, + 0x23F00000241, + 0x24200000243, + 0x24700000248, + 0x2490000024A, + 0x24B0000024C, + 0x24D0000024E, + 0x24F000002B0, + 0x2B9000002C2, + 0x2C6000002D2, + 0x2EC000002ED, + 0x2EE000002EF, + 0x30000000340, + 0x34200000343, + 0x3460000034F, + 0x35000000370, + 0x37100000372, + 0x37300000374, + 0x37700000378, + 0x37B0000037E, + 0x39000000391, + 0x3AC000003CF, + 0x3D7000003D8, + 0x3D9000003DA, + 0x3DB000003DC, + 0x3DD000003DE, + 0x3DF000003E0, + 0x3E1000003E2, + 0x3E3000003E4, + 0x3E5000003E6, + 0x3E7000003E8, + 0x3E9000003EA, + 0x3EB000003EC, + 0x3ED000003EE, + 0x3EF000003F0, + 0x3F3000003F4, + 0x3F8000003F9, + 0x3FB000003FD, + 0x43000000460, + 0x46100000462, + 0x46300000464, + 0x46500000466, + 0x46700000468, + 0x4690000046A, + 0x46B0000046C, + 0x46D0000046E, + 0x46F00000470, + 0x47100000472, + 0x47300000474, + 0x47500000476, + 0x47700000478, + 0x4790000047A, + 0x47B0000047C, + 0x47D0000047E, + 0x47F00000480, + 0x48100000482, + 0x48300000488, + 0x48B0000048C, + 0x48D0000048E, + 0x48F00000490, + 0x49100000492, + 0x49300000494, + 0x49500000496, + 0x49700000498, + 0x4990000049A, + 0x49B0000049C, + 0x49D0000049E, + 0x49F000004A0, + 0x4A1000004A2, + 0x4A3000004A4, + 0x4A5000004A6, + 0x4A7000004A8, + 0x4A9000004AA, + 0x4AB000004AC, + 0x4AD000004AE, + 0x4AF000004B0, + 0x4B1000004B2, + 0x4B3000004B4, + 0x4B5000004B6, + 0x4B7000004B8, + 0x4B9000004BA, + 0x4BB000004BC, + 0x4BD000004BE, + 0x4BF000004C0, + 0x4C2000004C3, + 0x4C4000004C5, + 0x4C6000004C7, + 0x4C8000004C9, + 0x4CA000004CB, + 0x4CC000004CD, + 0x4CE000004D0, + 0x4D1000004D2, + 0x4D3000004D4, + 0x4D5000004D6, + 0x4D7000004D8, + 0x4D9000004DA, + 0x4DB000004DC, + 0x4DD000004DE, + 0x4DF000004E0, + 0x4E1000004E2, + 0x4E3000004E4, + 0x4E5000004E6, + 0x4E7000004E8, + 0x4E9000004EA, + 0x4EB000004EC, + 0x4ED000004EE, + 0x4EF000004F0, + 0x4F1000004F2, + 0x4F3000004F4, + 0x4F5000004F6, + 0x4F7000004F8, + 0x4F9000004FA, + 0x4FB000004FC, + 0x4FD000004FE, + 0x4FF00000500, + 0x50100000502, + 0x50300000504, + 0x50500000506, + 0x50700000508, + 0x5090000050A, + 0x50B0000050C, + 0x50D0000050E, + 0x50F00000510, + 0x51100000512, + 0x51300000514, + 0x51500000516, + 0x51700000518, + 0x5190000051A, + 0x51B0000051C, + 0x51D0000051E, + 0x51F00000520, + 0x52100000522, + 0x52300000524, + 0x52500000526, + 0x52700000528, + 0x5290000052A, + 0x52B0000052C, + 0x52D0000052E, + 0x52F00000530, + 0x5590000055A, + 0x56000000587, + 0x58800000589, + 0x591000005BE, + 0x5BF000005C0, + 0x5C1000005C3, + 0x5C4000005C6, + 0x5C7000005C8, + 0x5D0000005EB, + 0x5EF000005F3, + 0x6100000061B, + 0x62000000640, + 0x64100000660, + 0x66E00000675, + 0x679000006D4, + 0x6D5000006DD, + 0x6DF000006E9, + 0x6EA000006F0, + 0x6FA00000700, + 0x7100000074B, + 0x74D000007B2, + 0x7C0000007F6, + 0x7FD000007FE, + 0x8000000082E, + 0x8400000085C, + 0x8600000086B, + 0x87000000888, + 0x8890000088F, + 0x898000008E2, + 0x8E300000958, + 0x96000000964, + 0x96600000970, + 0x97100000984, + 0x9850000098D, + 0x98F00000991, + 0x993000009A9, + 0x9AA000009B1, + 0x9B2000009B3, + 0x9B6000009BA, + 0x9BC000009C5, + 0x9C7000009C9, + 0x9CB000009CF, + 0x9D7000009D8, + 0x9E0000009E4, + 0x9E6000009F2, + 0x9FC000009FD, + 0x9FE000009FF, + 0xA0100000A04, + 0xA0500000A0B, + 0xA0F00000A11, + 0xA1300000A29, + 0xA2A00000A31, + 0xA3200000A33, + 0xA3500000A36, + 0xA3800000A3A, + 0xA3C00000A3D, + 0xA3E00000A43, + 0xA4700000A49, + 0xA4B00000A4E, + 0xA5100000A52, + 0xA5C00000A5D, + 0xA6600000A76, + 0xA8100000A84, + 0xA8500000A8E, + 0xA8F00000A92, + 0xA9300000AA9, + 0xAAA00000AB1, + 0xAB200000AB4, + 0xAB500000ABA, + 0xABC00000AC6, + 0xAC700000ACA, + 0xACB00000ACE, + 0xAD000000AD1, + 0xAE000000AE4, + 0xAE600000AF0, + 0xAF900000B00, + 0xB0100000B04, + 0xB0500000B0D, + 0xB0F00000B11, + 0xB1300000B29, + 0xB2A00000B31, + 0xB3200000B34, + 0xB3500000B3A, + 0xB3C00000B45, + 0xB4700000B49, + 0xB4B00000B4E, + 0xB5500000B58, + 0xB5F00000B64, + 0xB6600000B70, + 0xB7100000B72, + 0xB8200000B84, + 0xB8500000B8B, + 0xB8E00000B91, + 0xB9200000B96, + 0xB9900000B9B, + 0xB9C00000B9D, + 0xB9E00000BA0, + 0xBA300000BA5, + 0xBA800000BAB, + 0xBAE00000BBA, + 0xBBE00000BC3, + 0xBC600000BC9, + 0xBCA00000BCE, + 0xBD000000BD1, + 0xBD700000BD8, + 0xBE600000BF0, + 0xC0000000C0D, + 0xC0E00000C11, + 0xC1200000C29, + 0xC2A00000C3A, + 0xC3C00000C45, + 0xC4600000C49, + 0xC4A00000C4E, + 0xC5500000C57, + 0xC5800000C5B, + 0xC5D00000C5E, + 0xC6000000C64, + 0xC6600000C70, + 0xC8000000C84, + 0xC8500000C8D, + 0xC8E00000C91, + 0xC9200000CA9, + 0xCAA00000CB4, + 0xCB500000CBA, + 0xCBC00000CC5, + 0xCC600000CC9, + 0xCCA00000CCE, + 0xCD500000CD7, + 0xCDD00000CDF, + 0xCE000000CE4, + 0xCE600000CF0, + 0xCF100000CF4, + 0xD0000000D0D, + 0xD0E00000D11, + 0xD1200000D45, + 0xD4600000D49, + 0xD4A00000D4F, + 0xD5400000D58, + 0xD5F00000D64, + 0xD6600000D70, + 0xD7A00000D80, + 0xD8100000D84, + 0xD8500000D97, + 0xD9A00000DB2, + 0xDB300000DBC, + 0xDBD00000DBE, + 0xDC000000DC7, + 0xDCA00000DCB, + 0xDCF00000DD5, + 0xDD600000DD7, + 0xDD800000DE0, + 0xDE600000DF0, + 0xDF200000DF4, + 0xE0100000E33, + 0xE3400000E3B, + 0xE4000000E4F, + 0xE5000000E5A, + 0xE8100000E83, + 0xE8400000E85, + 0xE8600000E8B, + 0xE8C00000EA4, + 0xEA500000EA6, + 0xEA700000EB3, + 0xEB400000EBE, + 0xEC000000EC5, + 0xEC600000EC7, + 0xEC800000ECF, + 0xED000000EDA, + 0xEDE00000EE0, + 0xF0000000F01, + 0xF0B00000F0C, + 0xF1800000F1A, + 0xF2000000F2A, + 0xF3500000F36, + 0xF3700000F38, + 0xF3900000F3A, + 0xF3E00000F43, + 0xF4400000F48, + 0xF4900000F4D, + 0xF4E00000F52, + 0xF5300000F57, + 0xF5800000F5C, + 0xF5D00000F69, + 0xF6A00000F6D, + 0xF7100000F73, + 0xF7400000F75, + 0xF7A00000F81, + 0xF8200000F85, + 0xF8600000F93, + 0xF9400000F98, + 0xF9900000F9D, + 0xF9E00000FA2, + 0xFA300000FA7, + 0xFA800000FAC, + 0xFAD00000FB9, + 0xFBA00000FBD, + 0xFC600000FC7, + 0x10000000104A, + 0x10500000109E, + 0x10D0000010FB, + 0x10FD00001100, + 0x120000001249, + 0x124A0000124E, + 0x125000001257, + 0x125800001259, + 0x125A0000125E, + 0x126000001289, + 0x128A0000128E, + 0x1290000012B1, + 0x12B2000012B6, + 0x12B8000012BF, + 0x12C0000012C1, + 0x12C2000012C6, + 0x12C8000012D7, + 0x12D800001311, + 0x131200001316, + 0x13180000135B, + 0x135D00001360, + 0x138000001390, + 0x13A0000013F6, + 0x14010000166D, + 0x166F00001680, + 0x16810000169B, + 0x16A0000016EB, + 0x16F1000016F9, + 0x170000001716, + 0x171F00001735, + 0x174000001754, + 0x17600000176D, + 0x176E00001771, + 0x177200001774, + 0x1780000017B4, + 0x17B6000017D4, + 0x17D7000017D8, + 0x17DC000017DE, + 0x17E0000017EA, + 0x18100000181A, + 0x182000001879, + 0x1880000018AB, + 0x18B0000018F6, + 0x19000000191F, + 0x19200000192C, + 0x19300000193C, + 0x19460000196E, + 0x197000001975, + 0x1980000019AC, + 0x19B0000019CA, + 0x19D0000019DA, + 0x1A0000001A1C, + 0x1A2000001A5F, + 0x1A6000001A7D, + 0x1A7F00001A8A, + 0x1A9000001A9A, + 0x1AA700001AA8, + 0x1AB000001ABE, + 0x1ABF00001ACF, + 0x1B0000001B4D, + 0x1B5000001B5A, + 0x1B6B00001B74, + 0x1B8000001BF4, + 0x1C0000001C38, + 0x1C4000001C4A, + 0x1C4D00001C7E, + 0x1CD000001CD3, + 0x1CD400001CFB, + 0x1D0000001D2C, + 0x1D2F00001D30, + 0x1D3B00001D3C, + 0x1D4E00001D4F, + 0x1D6B00001D78, + 0x1D7900001D9B, + 0x1DC000001E00, + 0x1E0100001E02, + 0x1E0300001E04, + 0x1E0500001E06, + 0x1E0700001E08, + 0x1E0900001E0A, + 0x1E0B00001E0C, + 0x1E0D00001E0E, + 0x1E0F00001E10, + 0x1E1100001E12, + 0x1E1300001E14, + 0x1E1500001E16, + 0x1E1700001E18, + 0x1E1900001E1A, + 0x1E1B00001E1C, + 0x1E1D00001E1E, + 0x1E1F00001E20, + 0x1E2100001E22, + 0x1E2300001E24, + 0x1E2500001E26, + 0x1E2700001E28, + 0x1E2900001E2A, + 0x1E2B00001E2C, + 0x1E2D00001E2E, + 0x1E2F00001E30, + 0x1E3100001E32, + 0x1E3300001E34, + 0x1E3500001E36, + 0x1E3700001E38, + 0x1E3900001E3A, + 0x1E3B00001E3C, + 0x1E3D00001E3E, + 0x1E3F00001E40, + 0x1E4100001E42, + 0x1E4300001E44, + 0x1E4500001E46, + 0x1E4700001E48, + 0x1E4900001E4A, + 0x1E4B00001E4C, + 0x1E4D00001E4E, + 0x1E4F00001E50, + 0x1E5100001E52, + 0x1E5300001E54, + 0x1E5500001E56, + 0x1E5700001E58, + 0x1E5900001E5A, + 0x1E5B00001E5C, + 0x1E5D00001E5E, + 0x1E5F00001E60, + 0x1E6100001E62, + 0x1E6300001E64, + 0x1E6500001E66, + 0x1E6700001E68, + 0x1E6900001E6A, + 0x1E6B00001E6C, + 0x1E6D00001E6E, + 0x1E6F00001E70, + 0x1E7100001E72, + 0x1E7300001E74, + 0x1E7500001E76, + 0x1E7700001E78, + 0x1E7900001E7A, + 0x1E7B00001E7C, + 0x1E7D00001E7E, + 0x1E7F00001E80, + 0x1E8100001E82, + 0x1E8300001E84, + 0x1E8500001E86, + 0x1E8700001E88, + 0x1E8900001E8A, + 0x1E8B00001E8C, + 0x1E8D00001E8E, + 0x1E8F00001E90, + 0x1E9100001E92, + 0x1E9300001E94, + 0x1E9500001E9A, + 0x1E9C00001E9E, + 0x1E9F00001EA0, + 0x1EA100001EA2, + 0x1EA300001EA4, + 0x1EA500001EA6, + 0x1EA700001EA8, + 0x1EA900001EAA, + 0x1EAB00001EAC, + 0x1EAD00001EAE, + 0x1EAF00001EB0, + 0x1EB100001EB2, + 0x1EB300001EB4, + 0x1EB500001EB6, + 0x1EB700001EB8, + 0x1EB900001EBA, + 0x1EBB00001EBC, + 0x1EBD00001EBE, + 0x1EBF00001EC0, + 0x1EC100001EC2, + 0x1EC300001EC4, + 0x1EC500001EC6, + 0x1EC700001EC8, + 0x1EC900001ECA, + 0x1ECB00001ECC, + 0x1ECD00001ECE, + 0x1ECF00001ED0, + 0x1ED100001ED2, + 0x1ED300001ED4, + 0x1ED500001ED6, + 0x1ED700001ED8, + 0x1ED900001EDA, + 0x1EDB00001EDC, + 0x1EDD00001EDE, + 0x1EDF00001EE0, + 0x1EE100001EE2, + 0x1EE300001EE4, + 0x1EE500001EE6, + 0x1EE700001EE8, + 0x1EE900001EEA, + 0x1EEB00001EEC, + 0x1EED00001EEE, + 0x1EEF00001EF0, + 0x1EF100001EF2, + 0x1EF300001EF4, + 0x1EF500001EF6, + 0x1EF700001EF8, + 0x1EF900001EFA, + 0x1EFB00001EFC, + 0x1EFD00001EFE, + 0x1EFF00001F08, + 0x1F1000001F16, + 0x1F2000001F28, + 0x1F3000001F38, + 0x1F4000001F46, + 0x1F5000001F58, + 0x1F6000001F68, + 0x1F7000001F71, + 0x1F7200001F73, + 0x1F7400001F75, + 0x1F7600001F77, + 0x1F7800001F79, + 0x1F7A00001F7B, + 0x1F7C00001F7D, + 0x1FB000001FB2, + 0x1FB600001FB7, + 0x1FC600001FC7, + 0x1FD000001FD3, + 0x1FD600001FD8, + 0x1FE000001FE3, + 0x1FE400001FE8, + 0x1FF600001FF7, + 0x214E0000214F, + 0x218400002185, + 0x2C3000002C60, + 0x2C6100002C62, + 0x2C6500002C67, + 0x2C6800002C69, + 0x2C6A00002C6B, + 0x2C6C00002C6D, + 0x2C7100002C72, + 0x2C7300002C75, + 0x2C7600002C7C, + 0x2C8100002C82, + 0x2C8300002C84, + 0x2C8500002C86, + 0x2C8700002C88, + 0x2C8900002C8A, + 0x2C8B00002C8C, + 0x2C8D00002C8E, + 0x2C8F00002C90, + 0x2C9100002C92, + 0x2C9300002C94, + 0x2C9500002C96, + 0x2C9700002C98, + 0x2C9900002C9A, + 0x2C9B00002C9C, + 0x2C9D00002C9E, + 0x2C9F00002CA0, + 0x2CA100002CA2, + 0x2CA300002CA4, + 0x2CA500002CA6, + 0x2CA700002CA8, + 0x2CA900002CAA, + 0x2CAB00002CAC, + 0x2CAD00002CAE, + 0x2CAF00002CB0, + 0x2CB100002CB2, + 0x2CB300002CB4, + 0x2CB500002CB6, + 0x2CB700002CB8, + 0x2CB900002CBA, + 0x2CBB00002CBC, + 0x2CBD00002CBE, + 0x2CBF00002CC0, + 0x2CC100002CC2, + 0x2CC300002CC4, + 0x2CC500002CC6, + 0x2CC700002CC8, + 0x2CC900002CCA, + 0x2CCB00002CCC, + 0x2CCD00002CCE, + 0x2CCF00002CD0, + 0x2CD100002CD2, + 0x2CD300002CD4, + 0x2CD500002CD6, + 0x2CD700002CD8, + 0x2CD900002CDA, + 0x2CDB00002CDC, + 0x2CDD00002CDE, + 0x2CDF00002CE0, + 0x2CE100002CE2, + 0x2CE300002CE5, + 0x2CEC00002CED, + 0x2CEE00002CF2, + 0x2CF300002CF4, + 0x2D0000002D26, + 0x2D2700002D28, + 0x2D2D00002D2E, + 0x2D3000002D68, + 0x2D7F00002D97, + 0x2DA000002DA7, + 0x2DA800002DAF, + 0x2DB000002DB7, + 0x2DB800002DBF, + 0x2DC000002DC7, + 0x2DC800002DCF, + 0x2DD000002DD7, + 0x2DD800002DDF, + 0x2DE000002E00, + 0x2E2F00002E30, + 0x300500003008, + 0x302A0000302E, + 0x303C0000303D, + 0x304100003097, + 0x30990000309B, + 0x309D0000309F, + 0x30A1000030FB, + 0x30FC000030FF, + 0x310500003130, + 0x31A0000031C0, + 0x31F000003200, + 0x340000004DC0, + 0x4E000000A48D, + 0xA4D00000A4FE, + 0xA5000000A60D, + 0xA6100000A62C, + 0xA6410000A642, + 0xA6430000A644, + 0xA6450000A646, + 0xA6470000A648, + 0xA6490000A64A, + 0xA64B0000A64C, + 0xA64D0000A64E, + 0xA64F0000A650, + 0xA6510000A652, + 0xA6530000A654, + 0xA6550000A656, + 0xA6570000A658, + 0xA6590000A65A, + 0xA65B0000A65C, + 0xA65D0000A65E, + 0xA65F0000A660, + 0xA6610000A662, + 0xA6630000A664, + 0xA6650000A666, + 0xA6670000A668, + 0xA6690000A66A, + 0xA66B0000A66C, + 0xA66D0000A670, + 0xA6740000A67E, + 0xA67F0000A680, + 0xA6810000A682, + 0xA6830000A684, + 0xA6850000A686, + 0xA6870000A688, + 0xA6890000A68A, + 0xA68B0000A68C, + 0xA68D0000A68E, + 0xA68F0000A690, + 0xA6910000A692, + 0xA6930000A694, + 0xA6950000A696, + 0xA6970000A698, + 0xA6990000A69A, + 0xA69B0000A69C, + 0xA69E0000A6E6, + 0xA6F00000A6F2, + 0xA7170000A720, + 0xA7230000A724, + 0xA7250000A726, + 0xA7270000A728, + 0xA7290000A72A, + 0xA72B0000A72C, + 0xA72D0000A72E, + 0xA72F0000A732, + 0xA7330000A734, + 0xA7350000A736, + 0xA7370000A738, + 0xA7390000A73A, + 0xA73B0000A73C, + 0xA73D0000A73E, + 0xA73F0000A740, + 0xA7410000A742, + 0xA7430000A744, + 0xA7450000A746, + 0xA7470000A748, + 0xA7490000A74A, + 0xA74B0000A74C, + 0xA74D0000A74E, + 0xA74F0000A750, + 0xA7510000A752, + 0xA7530000A754, + 0xA7550000A756, + 0xA7570000A758, + 0xA7590000A75A, + 0xA75B0000A75C, + 0xA75D0000A75E, + 0xA75F0000A760, + 0xA7610000A762, + 0xA7630000A764, + 0xA7650000A766, + 0xA7670000A768, + 0xA7690000A76A, + 0xA76B0000A76C, + 0xA76D0000A76E, + 0xA76F0000A770, + 0xA7710000A779, + 0xA77A0000A77B, + 0xA77C0000A77D, + 0xA77F0000A780, + 0xA7810000A782, + 0xA7830000A784, + 0xA7850000A786, + 0xA7870000A789, + 0xA78C0000A78D, + 0xA78E0000A790, + 0xA7910000A792, + 0xA7930000A796, + 0xA7970000A798, + 0xA7990000A79A, + 0xA79B0000A79C, + 0xA79D0000A79E, + 0xA79F0000A7A0, + 0xA7A10000A7A2, + 0xA7A30000A7A4, + 0xA7A50000A7A6, + 0xA7A70000A7A8, + 0xA7A90000A7AA, + 0xA7AF0000A7B0, + 0xA7B50000A7B6, + 0xA7B70000A7B8, + 0xA7B90000A7BA, + 0xA7BB0000A7BC, + 0xA7BD0000A7BE, + 0xA7BF0000A7C0, + 0xA7C10000A7C2, + 0xA7C30000A7C4, + 0xA7C80000A7C9, + 0xA7CA0000A7CB, + 0xA7D10000A7D2, + 0xA7D30000A7D4, + 0xA7D50000A7D6, + 0xA7D70000A7D8, + 0xA7D90000A7DA, + 0xA7F60000A7F8, + 0xA7FA0000A828, + 0xA82C0000A82D, + 0xA8400000A874, + 0xA8800000A8C6, + 0xA8D00000A8DA, + 0xA8E00000A8F8, + 0xA8FB0000A8FC, + 0xA8FD0000A92E, + 0xA9300000A954, + 0xA9800000A9C1, + 0xA9CF0000A9DA, + 0xA9E00000A9FF, + 0xAA000000AA37, + 0xAA400000AA4E, + 0xAA500000AA5A, + 0xAA600000AA77, + 0xAA7A0000AAC3, + 0xAADB0000AADE, + 0xAAE00000AAF0, + 0xAAF20000AAF7, + 0xAB010000AB07, + 0xAB090000AB0F, + 0xAB110000AB17, + 0xAB200000AB27, + 0xAB280000AB2F, + 0xAB300000AB5B, + 0xAB600000AB69, + 0xABC00000ABEB, + 0xABEC0000ABEE, + 0xABF00000ABFA, + 0xAC000000D7A4, + 0xFA0E0000FA10, + 0xFA110000FA12, + 0xFA130000FA15, + 0xFA1F0000FA20, + 0xFA210000FA22, + 0xFA230000FA25, + 0xFA270000FA2A, + 0xFB1E0000FB1F, + 0xFE200000FE30, + 0xFE730000FE74, + 0x100000001000C, + 0x1000D00010027, + 0x100280001003B, + 0x1003C0001003E, + 0x1003F0001004E, + 0x100500001005E, + 0x10080000100FB, + 0x101FD000101FE, + 0x102800001029D, + 0x102A0000102D1, + 0x102E0000102E1, + 0x1030000010320, + 0x1032D00010341, + 0x103420001034A, + 0x103500001037B, + 0x103800001039E, + 0x103A0000103C4, + 0x103C8000103D0, + 0x104280001049E, + 0x104A0000104AA, + 0x104D8000104FC, + 0x1050000010528, + 0x1053000010564, + 0x10597000105A2, + 0x105A3000105B2, + 0x105B3000105BA, + 0x105BB000105BD, + 0x1060000010737, + 0x1074000010756, + 0x1076000010768, + 0x1078000010781, + 0x1080000010806, + 0x1080800010809, + 0x1080A00010836, + 0x1083700010839, + 0x1083C0001083D, + 0x1083F00010856, + 0x1086000010877, + 0x108800001089F, + 0x108E0000108F3, + 0x108F4000108F6, + 0x1090000010916, + 0x109200001093A, + 0x10980000109B8, + 0x109BE000109C0, + 0x10A0000010A04, + 0x10A0500010A07, + 0x10A0C00010A14, + 0x10A1500010A18, + 0x10A1900010A36, + 0x10A3800010A3B, + 0x10A3F00010A40, + 0x10A6000010A7D, + 0x10A8000010A9D, + 0x10AC000010AC8, + 0x10AC900010AE7, + 0x10B0000010B36, + 0x10B4000010B56, + 0x10B6000010B73, + 0x10B8000010B92, + 0x10C0000010C49, + 0x10CC000010CF3, + 0x10D0000010D28, + 0x10D3000010D3A, + 0x10E8000010EAA, + 0x10EAB00010EAD, + 0x10EB000010EB2, + 0x10EFD00010F1D, + 0x10F2700010F28, + 0x10F3000010F51, + 0x10F7000010F86, + 0x10FB000010FC5, + 0x10FE000010FF7, + 0x1100000011047, + 0x1106600011076, + 0x1107F000110BB, + 0x110C2000110C3, + 0x110D0000110E9, + 0x110F0000110FA, + 0x1110000011135, + 0x1113600011140, + 0x1114400011148, + 0x1115000011174, + 0x1117600011177, + 0x11180000111C5, + 0x111C9000111CD, + 0x111CE000111DB, + 0x111DC000111DD, + 0x1120000011212, + 0x1121300011238, + 0x1123E00011242, + 0x1128000011287, + 0x1128800011289, + 0x1128A0001128E, + 0x1128F0001129E, + 0x1129F000112A9, + 0x112B0000112EB, + 0x112F0000112FA, + 0x1130000011304, + 0x113050001130D, + 0x1130F00011311, + 0x1131300011329, + 0x1132A00011331, + 0x1133200011334, + 0x113350001133A, + 0x1133B00011345, + 0x1134700011349, + 0x1134B0001134E, + 0x1135000011351, + 0x1135700011358, + 0x1135D00011364, + 0x113660001136D, + 0x1137000011375, + 0x114000001144B, + 0x114500001145A, + 0x1145E00011462, + 0x11480000114C6, + 0x114C7000114C8, + 0x114D0000114DA, + 0x11580000115B6, + 0x115B8000115C1, + 0x115D8000115DE, + 0x1160000011641, + 0x1164400011645, + 0x116500001165A, + 0x11680000116B9, + 0x116C0000116CA, + 0x117000001171B, + 0x1171D0001172C, + 0x117300001173A, + 0x1174000011747, + 0x118000001183B, + 0x118C0000118EA, + 0x118FF00011907, + 0x119090001190A, + 0x1190C00011914, + 0x1191500011917, + 0x1191800011936, + 0x1193700011939, + 0x1193B00011944, + 0x119500001195A, + 0x119A0000119A8, + 0x119AA000119D8, + 0x119DA000119E2, + 0x119E3000119E5, + 0x11A0000011A3F, + 0x11A4700011A48, + 0x11A5000011A9A, + 0x11A9D00011A9E, + 0x11AB000011AF9, + 0x11C0000011C09, + 0x11C0A00011C37, + 0x11C3800011C41, + 0x11C5000011C5A, + 0x11C7200011C90, + 0x11C9200011CA8, + 0x11CA900011CB7, + 0x11D0000011D07, + 0x11D0800011D0A, + 0x11D0B00011D37, + 0x11D3A00011D3B, + 0x11D3C00011D3E, + 0x11D3F00011D48, + 0x11D5000011D5A, + 0x11D6000011D66, + 0x11D6700011D69, + 0x11D6A00011D8F, + 0x11D9000011D92, + 0x11D9300011D99, + 0x11DA000011DAA, + 0x11EE000011EF7, + 0x11F0000011F11, + 0x11F1200011F3B, + 0x11F3E00011F43, + 0x11F5000011F5A, + 0x11FB000011FB1, + 0x120000001239A, + 0x1248000012544, + 0x12F9000012FF1, + 0x1300000013430, + 0x1344000013456, + 0x1440000014647, + 0x1680000016A39, + 0x16A4000016A5F, + 0x16A6000016A6A, + 0x16A7000016ABF, + 0x16AC000016ACA, + 0x16AD000016AEE, + 0x16AF000016AF5, + 0x16B0000016B37, + 0x16B4000016B44, + 0x16B5000016B5A, + 0x16B6300016B78, + 0x16B7D00016B90, + 0x16E6000016E80, + 0x16F0000016F4B, + 0x16F4F00016F88, + 0x16F8F00016FA0, + 0x16FE000016FE2, + 0x16FE300016FE5, + 0x16FF000016FF2, + 0x17000000187F8, + 0x1880000018CD6, + 0x18D0000018D09, + 0x1AFF00001AFF4, + 0x1AFF50001AFFC, + 0x1AFFD0001AFFF, + 0x1B0000001B123, + 0x1B1320001B133, + 0x1B1500001B153, + 0x1B1550001B156, + 0x1B1640001B168, + 0x1B1700001B2FC, + 0x1BC000001BC6B, + 0x1BC700001BC7D, + 0x1BC800001BC89, + 0x1BC900001BC9A, + 0x1BC9D0001BC9F, + 0x1CF000001CF2E, + 0x1CF300001CF47, + 0x1DA000001DA37, + 0x1DA3B0001DA6D, + 0x1DA750001DA76, + 0x1DA840001DA85, + 0x1DA9B0001DAA0, + 0x1DAA10001DAB0, + 0x1DF000001DF1F, + 0x1DF250001DF2B, + 0x1E0000001E007, + 0x1E0080001E019, + 0x1E01B0001E022, + 0x1E0230001E025, + 0x1E0260001E02B, + 0x1E08F0001E090, + 0x1E1000001E12D, + 0x1E1300001E13E, + 0x1E1400001E14A, + 0x1E14E0001E14F, + 0x1E2900001E2AF, + 0x1E2C00001E2FA, + 0x1E4D00001E4FA, + 0x1E7E00001E7E7, + 0x1E7E80001E7EC, + 0x1E7ED0001E7EF, + 0x1E7F00001E7FF, + 0x1E8000001E8C5, + 0x1E8D00001E8D7, + 0x1E9220001E94C, + 0x1E9500001E95A, + 0x200000002A6E0, + 0x2A7000002B73A, + 0x2B7400002B81E, + 0x2B8200002CEA2, + 0x2CEB00002EBE1, + 0x2EBF00002EE5E, + 0x300000003134B, + 0x31350000323B0, + ), + "CONTEXTJ": (0x200C0000200E,), + "CONTEXTO": ( + 0xB7000000B8, + 0x37500000376, + 0x5F3000005F5, + 0x6600000066A, + 0x6F0000006FA, + 0x30FB000030FC, + ), +} diff --git a/psets/9/finance/env/lib/python3.12/site-packages/idna/intranges.py b/psets/9/finance/env/lib/python3.12/site-packages/idna/intranges.py new file mode 100644 index 0000000..7bfaa8d --- /dev/null +++ b/psets/9/finance/env/lib/python3.12/site-packages/idna/intranges.py @@ -0,0 +1,57 @@ +""" +Given a list of integers, made up of (hopefully) a small number of long runs +of consecutive integers, compute a representation of the form +((start1, end1), (start2, end2) ...). Then answer the question "was x present +in the original list?" in time O(log(# runs)). +""" + +import bisect +from typing import List, Tuple + + +def intranges_from_list(list_: List[int]) -> Tuple[int, ...]: + """Represent a list of integers as a sequence of ranges: + ((start_0, end_0), (start_1, end_1), ...), such that the original + integers are exactly those x such that start_i <= x < end_i for some i. + + Ranges are encoded as single integers (start << 32 | end), not as tuples. + """ + + sorted_list = sorted(list_) + ranges = [] + last_write = -1 + for i in range(len(sorted_list)): + if i + 1 < len(sorted_list): + if sorted_list[i] == sorted_list[i + 1] - 1: + continue + current_range = sorted_list[last_write + 1 : i + 1] + ranges.append(_encode_range(current_range[0], current_range[-1] + 1)) + last_write = i + + return tuple(ranges) + + +def _encode_range(start: int, end: int) -> int: + return (start << 32) | end + + +def _decode_range(r: int) -> Tuple[int, int]: + return (r >> 32), (r & ((1 << 32) - 1)) + + +def intranges_contain(int_: int, ranges: Tuple[int, ...]) -> bool: + """Determine if `int_` falls into one of the ranges in `ranges`.""" + tuple_ = _encode_range(int_, 0) + pos = bisect.bisect_left(ranges, tuple_) + # we could be immediately ahead of a tuple (start, end) + # with start < int_ <= end + if pos > 0: + left, right = _decode_range(ranges[pos - 1]) + if left <= int_ < right: + return True + # or we could be immediately behind a tuple (int_, end) + if pos < len(ranges): + left, _ = _decode_range(ranges[pos]) + if left == int_: + return True + return False diff --git a/psets/9/finance/env/lib/python3.12/site-packages/idna/package_data.py b/psets/9/finance/env/lib/python3.12/site-packages/idna/package_data.py new file mode 100644 index 0000000..514ff7e --- /dev/null +++ b/psets/9/finance/env/lib/python3.12/site-packages/idna/package_data.py @@ -0,0 +1 @@ +__version__ = "3.10" diff --git a/psets/9/finance/env/lib/python3.12/site-packages/idna/py.typed b/psets/9/finance/env/lib/python3.12/site-packages/idna/py.typed new file mode 100644 index 0000000..e69de29 diff --git a/psets/9/finance/env/lib/python3.12/site-packages/idna/uts46data.py b/psets/9/finance/env/lib/python3.12/site-packages/idna/uts46data.py new file mode 100644 index 0000000..eb89432 --- /dev/null +++ b/psets/9/finance/env/lib/python3.12/site-packages/idna/uts46data.py @@ -0,0 +1,8681 @@ +# This file is automatically generated by tools/idna-data +# vim: set fileencoding=utf-8 : + +from typing import List, Tuple, Union + +"""IDNA Mapping Table from UTS46.""" + + +__version__ = "15.1.0" + + +def _seg_0() -> List[Union[Tuple[int, str], Tuple[int, str, str]]]: + return [ + (0x0, "3"), + (0x1, "3"), + (0x2, "3"), + (0x3, "3"), + (0x4, "3"), + (0x5, "3"), + (0x6, "3"), + (0x7, "3"), + (0x8, "3"), + (0x9, "3"), + (0xA, "3"), + (0xB, "3"), + (0xC, "3"), + (0xD, "3"), + (0xE, "3"), + (0xF, "3"), + (0x10, "3"), + (0x11, "3"), + (0x12, "3"), + (0x13, "3"), + (0x14, "3"), + (0x15, "3"), + (0x16, "3"), + (0x17, "3"), + (0x18, "3"), + (0x19, "3"), + (0x1A, "3"), + (0x1B, "3"), + (0x1C, "3"), + (0x1D, "3"), + (0x1E, "3"), + (0x1F, "3"), + (0x20, "3"), + (0x21, "3"), + (0x22, "3"), + (0x23, "3"), + (0x24, "3"), + (0x25, "3"), + (0x26, "3"), + (0x27, "3"), + (0x28, "3"), + (0x29, "3"), + (0x2A, "3"), + (0x2B, "3"), + (0x2C, "3"), + (0x2D, "V"), + (0x2E, "V"), + (0x2F, "3"), + (0x30, "V"), + (0x31, "V"), + (0x32, "V"), + (0x33, "V"), + (0x34, "V"), + (0x35, "V"), + (0x36, "V"), + (0x37, "V"), + (0x38, "V"), + (0x39, "V"), + (0x3A, "3"), + (0x3B, "3"), + (0x3C, "3"), + (0x3D, "3"), + (0x3E, "3"), + (0x3F, "3"), + (0x40, "3"), + (0x41, "M", "a"), + (0x42, "M", "b"), + (0x43, "M", "c"), + (0x44, "M", "d"), + (0x45, "M", "e"), + (0x46, "M", "f"), + (0x47, "M", "g"), + (0x48, "M", "h"), + (0x49, "M", "i"), + (0x4A, "M", "j"), + (0x4B, "M", "k"), + (0x4C, "M", "l"), + (0x4D, "M", "m"), + (0x4E, "M", "n"), + (0x4F, "M", "o"), + (0x50, "M", "p"), + (0x51, "M", "q"), + (0x52, "M", "r"), + (0x53, "M", "s"), + (0x54, "M", "t"), + (0x55, "M", "u"), + (0x56, "M", "v"), + (0x57, "M", "w"), + (0x58, "M", "x"), + (0x59, "M", "y"), + (0x5A, "M", "z"), + (0x5B, "3"), + (0x5C, "3"), + (0x5D, "3"), + (0x5E, "3"), + (0x5F, "3"), + (0x60, "3"), + (0x61, "V"), + (0x62, "V"), + (0x63, "V"), + ] + + +def _seg_1() -> List[Union[Tuple[int, str], Tuple[int, str, str]]]: + return [ + (0x64, "V"), + (0x65, "V"), + (0x66, "V"), + (0x67, "V"), + (0x68, "V"), + (0x69, "V"), + (0x6A, "V"), + (0x6B, "V"), + (0x6C, "V"), + (0x6D, "V"), + (0x6E, "V"), + (0x6F, "V"), + (0x70, "V"), + (0x71, "V"), + (0x72, "V"), + (0x73, "V"), + (0x74, "V"), + (0x75, "V"), + (0x76, "V"), + (0x77, "V"), + (0x78, "V"), + (0x79, "V"), + (0x7A, "V"), + (0x7B, "3"), + (0x7C, "3"), + (0x7D, "3"), + (0x7E, "3"), + (0x7F, "3"), + (0x80, "X"), + (0x81, "X"), + (0x82, "X"), + (0x83, "X"), + (0x84, "X"), + (0x85, "X"), + (0x86, "X"), + (0x87, "X"), + (0x88, "X"), + (0x89, "X"), + (0x8A, "X"), + (0x8B, "X"), + (0x8C, "X"), + (0x8D, "X"), + (0x8E, "X"), + (0x8F, "X"), + (0x90, "X"), + (0x91, "X"), + (0x92, "X"), + (0x93, "X"), + (0x94, "X"), + (0x95, "X"), + (0x96, "X"), + (0x97, "X"), + (0x98, "X"), + (0x99, "X"), + (0x9A, "X"), + (0x9B, "X"), + (0x9C, "X"), + (0x9D, "X"), + (0x9E, "X"), + (0x9F, "X"), + (0xA0, "3", " "), + (0xA1, "V"), + (0xA2, "V"), + (0xA3, "V"), + (0xA4, "V"), + (0xA5, "V"), + (0xA6, "V"), + (0xA7, "V"), + (0xA8, "3", " ̈"), + (0xA9, "V"), + (0xAA, "M", "a"), + (0xAB, "V"), + (0xAC, "V"), + (0xAD, "I"), + (0xAE, "V"), + (0xAF, "3", " ̄"), + (0xB0, "V"), + (0xB1, "V"), + (0xB2, "M", "2"), + (0xB3, "M", "3"), + (0xB4, "3", " ́"), + (0xB5, "M", "μ"), + (0xB6, "V"), + (0xB7, "V"), + (0xB8, "3", " ̧"), + (0xB9, "M", "1"), + (0xBA, "M", "o"), + (0xBB, "V"), + (0xBC, "M", "1⁄4"), + (0xBD, "M", "1⁄2"), + (0xBE, "M", "3⁄4"), + (0xBF, "V"), + (0xC0, "M", "à"), + (0xC1, "M", "á"), + (0xC2, "M", "â"), + (0xC3, "M", "ã"), + (0xC4, "M", "ä"), + (0xC5, "M", "å"), + (0xC6, "M", "æ"), + (0xC7, "M", "ç"), + ] + + +def _seg_2() -> List[Union[Tuple[int, str], Tuple[int, str, str]]]: + return [ + (0xC8, "M", "è"), + (0xC9, "M", "é"), + (0xCA, "M", "ê"), + (0xCB, "M", "ë"), + (0xCC, "M", "ì"), + (0xCD, "M", "í"), + (0xCE, "M", "î"), + (0xCF, "M", "ï"), + (0xD0, "M", "ð"), + (0xD1, "M", "ñ"), + (0xD2, "M", "ò"), + (0xD3, "M", "ó"), + (0xD4, "M", "ô"), + (0xD5, "M", "õ"), + (0xD6, "M", "ö"), + (0xD7, "V"), + (0xD8, "M", "ø"), + (0xD9, "M", "ù"), + (0xDA, "M", "ú"), + (0xDB, "M", "û"), + (0xDC, "M", "ü"), + (0xDD, "M", "ý"), + (0xDE, "M", "þ"), + (0xDF, "D", "ss"), + (0xE0, "V"), + (0xE1, "V"), + (0xE2, "V"), + (0xE3, "V"), + (0xE4, "V"), + (0xE5, "V"), + (0xE6, "V"), + (0xE7, "V"), + (0xE8, "V"), + (0xE9, "V"), + (0xEA, "V"), + (0xEB, "V"), + (0xEC, "V"), + (0xED, "V"), + (0xEE, "V"), + (0xEF, "V"), + (0xF0, "V"), + (0xF1, "V"), + (0xF2, "V"), + (0xF3, "V"), + (0xF4, "V"), + (0xF5, "V"), + (0xF6, "V"), + (0xF7, "V"), + (0xF8, "V"), + (0xF9, "V"), + (0xFA, "V"), + (0xFB, "V"), + (0xFC, "V"), + (0xFD, "V"), + (0xFE, "V"), + (0xFF, "V"), + (0x100, "M", "ā"), + (0x101, "V"), + (0x102, "M", "ă"), + (0x103, "V"), + (0x104, "M", "ą"), + (0x105, "V"), + (0x106, "M", "ć"), + (0x107, "V"), + (0x108, "M", "ĉ"), + (0x109, "V"), + (0x10A, "M", "ċ"), + (0x10B, "V"), + (0x10C, "M", "č"), + (0x10D, "V"), + (0x10E, "M", "ď"), + (0x10F, "V"), + (0x110, "M", "đ"), + (0x111, "V"), + (0x112, "M", "ē"), + (0x113, "V"), + (0x114, "M", "ĕ"), + (0x115, "V"), + (0x116, "M", "ė"), + (0x117, "V"), + (0x118, "M", "ę"), + (0x119, "V"), + (0x11A, "M", "ě"), + (0x11B, "V"), + (0x11C, "M", "ĝ"), + (0x11D, "V"), + (0x11E, "M", "ğ"), + (0x11F, "V"), + (0x120, "M", "ġ"), + (0x121, "V"), + (0x122, "M", "ģ"), + (0x123, "V"), + (0x124, "M", "ĥ"), + (0x125, "V"), + (0x126, "M", "ħ"), + (0x127, "V"), + (0x128, "M", "ĩ"), + (0x129, "V"), + (0x12A, "M", "ī"), + (0x12B, "V"), + ] + + +def _seg_3() -> List[Union[Tuple[int, str], Tuple[int, str, str]]]: + return [ + (0x12C, "M", "ĭ"), + (0x12D, "V"), + (0x12E, "M", "į"), + (0x12F, "V"), + (0x130, "M", "i̇"), + (0x131, "V"), + (0x132, "M", "ij"), + (0x134, "M", "ĵ"), + (0x135, "V"), + (0x136, "M", "ķ"), + (0x137, "V"), + (0x139, "M", "ĺ"), + (0x13A, "V"), + (0x13B, "M", "ļ"), + (0x13C, "V"), + (0x13D, "M", "ľ"), + (0x13E, "V"), + (0x13F, "M", "l·"), + (0x141, "M", "ł"), + (0x142, "V"), + (0x143, "M", "ń"), + (0x144, "V"), + (0x145, "M", "ņ"), + (0x146, "V"), + (0x147, "M", "ň"), + (0x148, "V"), + (0x149, "M", "ʼn"), + (0x14A, "M", "ŋ"), + (0x14B, "V"), + (0x14C, "M", "ō"), + (0x14D, "V"), + (0x14E, "M", "ŏ"), + (0x14F, "V"), + (0x150, "M", "ő"), + (0x151, "V"), + (0x152, "M", "œ"), + (0x153, "V"), + (0x154, "M", "ŕ"), + (0x155, "V"), + (0x156, "M", "ŗ"), + (0x157, "V"), + (0x158, "M", "ř"), + (0x159, "V"), + (0x15A, "M", "ś"), + (0x15B, "V"), + (0x15C, "M", "ŝ"), + (0x15D, "V"), + (0x15E, "M", "ş"), + (0x15F, "V"), + (0x160, "M", "š"), + (0x161, "V"), + (0x162, "M", "ţ"), + (0x163, "V"), + (0x164, "M", "ť"), + (0x165, "V"), + (0x166, "M", "ŧ"), + (0x167, "V"), + (0x168, "M", "ũ"), + (0x169, "V"), + (0x16A, "M", "ū"), + (0x16B, "V"), + (0x16C, "M", "ŭ"), + (0x16D, "V"), + (0x16E, "M", "ů"), + (0x16F, "V"), + (0x170, "M", "ű"), + (0x171, "V"), + (0x172, "M", "ų"), + (0x173, "V"), + (0x174, "M", "ŵ"), + (0x175, "V"), + (0x176, "M", "ŷ"), + (0x177, "V"), + (0x178, "M", "ÿ"), + (0x179, "M", "ź"), + (0x17A, "V"), + (0x17B, "M", "ż"), + (0x17C, "V"), + (0x17D, "M", "ž"), + (0x17E, "V"), + (0x17F, "M", "s"), + (0x180, "V"), + (0x181, "M", "ɓ"), + (0x182, "M", "ƃ"), + (0x183, "V"), + (0x184, "M", "ƅ"), + (0x185, "V"), + (0x186, "M", "ɔ"), + (0x187, "M", "ƈ"), + (0x188, "V"), + (0x189, "M", "ɖ"), + (0x18A, "M", "ɗ"), + (0x18B, "M", "ƌ"), + (0x18C, "V"), + (0x18E, "M", "ǝ"), + (0x18F, "M", "ə"), + (0x190, "M", "ɛ"), + (0x191, "M", "ƒ"), + (0x192, "V"), + (0x193, "M", "ɠ"), + ] + + +def _seg_4() -> List[Union[Tuple[int, str], Tuple[int, str, str]]]: + return [ + (0x194, "M", "ɣ"), + (0x195, "V"), + (0x196, "M", "ɩ"), + (0x197, "M", "ɨ"), + (0x198, "M", "ƙ"), + (0x199, "V"), + (0x19C, "M", "ɯ"), + (0x19D, "M", "ɲ"), + (0x19E, "V"), + (0x19F, "M", "ɵ"), + (0x1A0, "M", "ơ"), + (0x1A1, "V"), + (0x1A2, "M", "ƣ"), + (0x1A3, "V"), + (0x1A4, "M", "ƥ"), + (0x1A5, "V"), + (0x1A6, "M", "ʀ"), + (0x1A7, "M", "ƨ"), + (0x1A8, "V"), + (0x1A9, "M", "ʃ"), + (0x1AA, "V"), + (0x1AC, "M", "ƭ"), + (0x1AD, "V"), + (0x1AE, "M", "ʈ"), + (0x1AF, "M", "ư"), + (0x1B0, "V"), + (0x1B1, "M", "ʊ"), + (0x1B2, "M", "ʋ"), + (0x1B3, "M", "ƴ"), + (0x1B4, "V"), + (0x1B5, "M", "ƶ"), + (0x1B6, "V"), + (0x1B7, "M", "ʒ"), + (0x1B8, "M", "ƹ"), + (0x1B9, "V"), + (0x1BC, "M", "ƽ"), + (0x1BD, "V"), + (0x1C4, "M", "dž"), + (0x1C7, "M", "lj"), + (0x1CA, "M", "nj"), + (0x1CD, "M", "ǎ"), + (0x1CE, "V"), + (0x1CF, "M", "ǐ"), + (0x1D0, "V"), + (0x1D1, "M", "ǒ"), + (0x1D2, "V"), + (0x1D3, "M", "ǔ"), + (0x1D4, "V"), + (0x1D5, "M", "ǖ"), + (0x1D6, "V"), + (0x1D7, "M", "ǘ"), + (0x1D8, "V"), + (0x1D9, "M", "ǚ"), + (0x1DA, "V"), + (0x1DB, "M", "ǜ"), + (0x1DC, "V"), + (0x1DE, "M", "ǟ"), + (0x1DF, "V"), + (0x1E0, "M", "ǡ"), + (0x1E1, "V"), + (0x1E2, "M", "ǣ"), + (0x1E3, "V"), + (0x1E4, "M", "ǥ"), + (0x1E5, "V"), + (0x1E6, "M", "ǧ"), + (0x1E7, "V"), + (0x1E8, "M", "ǩ"), + (0x1E9, "V"), + (0x1EA, "M", "ǫ"), + (0x1EB, "V"), + (0x1EC, "M", "ǭ"), + (0x1ED, "V"), + (0x1EE, "M", "ǯ"), + (0x1EF, "V"), + (0x1F1, "M", "dz"), + (0x1F4, "M", "ǵ"), + (0x1F5, "V"), + (0x1F6, "M", "ƕ"), + (0x1F7, "M", "ƿ"), + (0x1F8, "M", "ǹ"), + (0x1F9, "V"), + (0x1FA, "M", "ǻ"), + (0x1FB, "V"), + (0x1FC, "M", "ǽ"), + (0x1FD, "V"), + (0x1FE, "M", "ǿ"), + (0x1FF, "V"), + (0x200, "M", "ȁ"), + (0x201, "V"), + (0x202, "M", "ȃ"), + (0x203, "V"), + (0x204, "M", "ȅ"), + (0x205, "V"), + (0x206, "M", "ȇ"), + (0x207, "V"), + (0x208, "M", "ȉ"), + (0x209, "V"), + (0x20A, "M", "ȋ"), + (0x20B, "V"), + (0x20C, "M", "ȍ"), + ] + + +def _seg_5() -> List[Union[Tuple[int, str], Tuple[int, str, str]]]: + return [ + (0x20D, "V"), + (0x20E, "M", "ȏ"), + (0x20F, "V"), + (0x210, "M", "ȑ"), + (0x211, "V"), + (0x212, "M", "ȓ"), + (0x213, "V"), + (0x214, "M", "ȕ"), + (0x215, "V"), + (0x216, "M", "ȗ"), + (0x217, "V"), + (0x218, "M", "ș"), + (0x219, "V"), + (0x21A, "M", "ț"), + (0x21B, "V"), + (0x21C, "M", "ȝ"), + (0x21D, "V"), + (0x21E, "M", "ȟ"), + (0x21F, "V"), + (0x220, "M", "ƞ"), + (0x221, "V"), + (0x222, "M", "ȣ"), + (0x223, "V"), + (0x224, "M", "ȥ"), + (0x225, "V"), + (0x226, "M", "ȧ"), + (0x227, "V"), + (0x228, "M", "ȩ"), + (0x229, "V"), + (0x22A, "M", "ȫ"), + (0x22B, "V"), + (0x22C, "M", "ȭ"), + (0x22D, "V"), + (0x22E, "M", "ȯ"), + (0x22F, "V"), + (0x230, "M", "ȱ"), + (0x231, "V"), + (0x232, "M", "ȳ"), + (0x233, "V"), + (0x23A, "M", "ⱥ"), + (0x23B, "M", "ȼ"), + (0x23C, "V"), + (0x23D, "M", "ƚ"), + (0x23E, "M", "ⱦ"), + (0x23F, "V"), + (0x241, "M", "ɂ"), + (0x242, "V"), + (0x243, "M", "ƀ"), + (0x244, "M", "ʉ"), + (0x245, "M", "ʌ"), + (0x246, "M", "ɇ"), + (0x247, "V"), + (0x248, "M", "ɉ"), + (0x249, "V"), + (0x24A, "M", "ɋ"), + (0x24B, "V"), + (0x24C, "M", "ɍ"), + (0x24D, "V"), + (0x24E, "M", "ɏ"), + (0x24F, "V"), + (0x2B0, "M", "h"), + (0x2B1, "M", "ɦ"), + (0x2B2, "M", "j"), + (0x2B3, "M", "r"), + (0x2B4, "M", "ɹ"), + (0x2B5, "M", "ɻ"), + (0x2B6, "M", "ʁ"), + (0x2B7, "M", "w"), + (0x2B8, "M", "y"), + (0x2B9, "V"), + (0x2D8, "3", " ̆"), + (0x2D9, "3", " ̇"), + (0x2DA, "3", " ̊"), + (0x2DB, "3", " ̨"), + (0x2DC, "3", " ̃"), + (0x2DD, "3", " ̋"), + (0x2DE, "V"), + (0x2E0, "M", "ɣ"), + (0x2E1, "M", "l"), + (0x2E2, "M", "s"), + (0x2E3, "M", "x"), + (0x2E4, "M", "ʕ"), + (0x2E5, "V"), + (0x340, "M", "̀"), + (0x341, "M", "́"), + (0x342, "V"), + (0x343, "M", "̓"), + (0x344, "M", "̈́"), + (0x345, "M", "ι"), + (0x346, "V"), + (0x34F, "I"), + (0x350, "V"), + (0x370, "M", "ͱ"), + (0x371, "V"), + (0x372, "M", "ͳ"), + (0x373, "V"), + (0x374, "M", "ʹ"), + (0x375, "V"), + (0x376, "M", "ͷ"), + (0x377, "V"), + ] + + +def _seg_6() -> List[Union[Tuple[int, str], Tuple[int, str, str]]]: + return [ + (0x378, "X"), + (0x37A, "3", " ι"), + (0x37B, "V"), + (0x37E, "3", ";"), + (0x37F, "M", "ϳ"), + (0x380, "X"), + (0x384, "3", " ́"), + (0x385, "3", " ̈́"), + (0x386, "M", "ά"), + (0x387, "M", "·"), + (0x388, "M", "έ"), + (0x389, "M", "ή"), + (0x38A, "M", "ί"), + (0x38B, "X"), + (0x38C, "M", "ό"), + (0x38D, "X"), + (0x38E, "M", "ύ"), + (0x38F, "M", "ώ"), + (0x390, "V"), + (0x391, "M", "α"), + (0x392, "M", "β"), + (0x393, "M", "γ"), + (0x394, "M", "δ"), + (0x395, "M", "ε"), + (0x396, "M", "ζ"), + (0x397, "M", "η"), + (0x398, "M", "θ"), + (0x399, "M", "ι"), + (0x39A, "M", "κ"), + (0x39B, "M", "λ"), + (0x39C, "M", "μ"), + (0x39D, "M", "ν"), + (0x39E, "M", "ξ"), + (0x39F, "M", "ο"), + (0x3A0, "M", "π"), + (0x3A1, "M", "ρ"), + (0x3A2, "X"), + (0x3A3, "M", "σ"), + (0x3A4, "M", "τ"), + (0x3A5, "M", "υ"), + (0x3A6, "M", "φ"), + (0x3A7, "M", "χ"), + (0x3A8, "M", "ψ"), + (0x3A9, "M", "ω"), + (0x3AA, "M", "ϊ"), + (0x3AB, "M", "ϋ"), + (0x3AC, "V"), + (0x3C2, "D", "σ"), + (0x3C3, "V"), + (0x3CF, "M", "ϗ"), + (0x3D0, "M", "β"), + (0x3D1, "M", "θ"), + (0x3D2, "M", "υ"), + (0x3D3, "M", "ύ"), + (0x3D4, "M", "ϋ"), + (0x3D5, "M", "φ"), + (0x3D6, "M", "π"), + (0x3D7, "V"), + (0x3D8, "M", "ϙ"), + (0x3D9, "V"), + (0x3DA, "M", "ϛ"), + (0x3DB, "V"), + (0x3DC, "M", "ϝ"), + (0x3DD, "V"), + (0x3DE, "M", "ϟ"), + (0x3DF, "V"), + (0x3E0, "M", "ϡ"), + (0x3E1, "V"), + (0x3E2, "M", "ϣ"), + (0x3E3, "V"), + (0x3E4, "M", "ϥ"), + (0x3E5, "V"), + (0x3E6, "M", "ϧ"), + (0x3E7, "V"), + (0x3E8, "M", "ϩ"), + (0x3E9, "V"), + (0x3EA, "M", "ϫ"), + (0x3EB, "V"), + (0x3EC, "M", "ϭ"), + (0x3ED, "V"), + (0x3EE, "M", "ϯ"), + (0x3EF, "V"), + (0x3F0, "M", "κ"), + (0x3F1, "M", "ρ"), + (0x3F2, "M", "σ"), + (0x3F3, "V"), + (0x3F4, "M", "θ"), + (0x3F5, "M", "ε"), + (0x3F6, "V"), + (0x3F7, "M", "ϸ"), + (0x3F8, "V"), + (0x3F9, "M", "σ"), + (0x3FA, "M", "ϻ"), + (0x3FB, "V"), + (0x3FD, "M", "ͻ"), + (0x3FE, "M", "ͼ"), + (0x3FF, "M", "ͽ"), + (0x400, "M", "ѐ"), + (0x401, "M", "ё"), + (0x402, "M", "ђ"), + ] + + +def _seg_7() -> List[Union[Tuple[int, str], Tuple[int, str, str]]]: + return [ + (0x403, "M", "ѓ"), + (0x404, "M", "є"), + (0x405, "M", "ѕ"), + (0x406, "M", "і"), + (0x407, "M", "ї"), + (0x408, "M", "ј"), + (0x409, "M", "љ"), + (0x40A, "M", "њ"), + (0x40B, "M", "ћ"), + (0x40C, "M", "ќ"), + (0x40D, "M", "ѝ"), + (0x40E, "M", "ў"), + (0x40F, "M", "џ"), + (0x410, "M", "а"), + (0x411, "M", "б"), + (0x412, "M", "в"), + (0x413, "M", "г"), + (0x414, "M", "д"), + (0x415, "M", "е"), + (0x416, "M", "ж"), + (0x417, "M", "з"), + (0x418, "M", "и"), + (0x419, "M", "й"), + (0x41A, "M", "к"), + (0x41B, "M", "л"), + (0x41C, "M", "м"), + (0x41D, "M", "н"), + (0x41E, "M", "о"), + (0x41F, "M", "п"), + (0x420, "M", "р"), + (0x421, "M", "с"), + (0x422, "M", "т"), + (0x423, "M", "у"), + (0x424, "M", "ф"), + (0x425, "M", "х"), + (0x426, "M", "ц"), + (0x427, "M", "ч"), + (0x428, "M", "ш"), + (0x429, "M", "щ"), + (0x42A, "M", "ъ"), + (0x42B, "M", "ы"), + (0x42C, "M", "ь"), + (0x42D, "M", "э"), + (0x42E, "M", "ю"), + (0x42F, "M", "я"), + (0x430, "V"), + (0x460, "M", "ѡ"), + (0x461, "V"), + (0x462, "M", "ѣ"), + (0x463, "V"), + (0x464, "M", "ѥ"), + (0x465, "V"), + (0x466, "M", "ѧ"), + (0x467, "V"), + (0x468, "M", "ѩ"), + (0x469, "V"), + (0x46A, "M", "ѫ"), + (0x46B, "V"), + (0x46C, "M", "ѭ"), + (0x46D, "V"), + (0x46E, "M", "ѯ"), + (0x46F, "V"), + (0x470, "M", "ѱ"), + (0x471, "V"), + (0x472, "M", "ѳ"), + (0x473, "V"), + (0x474, "M", "ѵ"), + (0x475, "V"), + (0x476, "M", "ѷ"), + (0x477, "V"), + (0x478, "M", "ѹ"), + (0x479, "V"), + (0x47A, "M", "ѻ"), + (0x47B, "V"), + (0x47C, "M", "ѽ"), + (0x47D, "V"), + (0x47E, "M", "ѿ"), + (0x47F, "V"), + (0x480, "M", "ҁ"), + (0x481, "V"), + (0x48A, "M", "ҋ"), + (0x48B, "V"), + (0x48C, "M", "ҍ"), + (0x48D, "V"), + (0x48E, "M", "ҏ"), + (0x48F, "V"), + (0x490, "M", "ґ"), + (0x491, "V"), + (0x492, "M", "ғ"), + (0x493, "V"), + (0x494, "M", "ҕ"), + (0x495, "V"), + (0x496, "M", "җ"), + (0x497, "V"), + (0x498, "M", "ҙ"), + (0x499, "V"), + (0x49A, "M", "қ"), + (0x49B, "V"), + (0x49C, "M", "ҝ"), + (0x49D, "V"), + ] + + +def _seg_8() -> List[Union[Tuple[int, str], Tuple[int, str, str]]]: + return [ + (0x49E, "M", "ҟ"), + (0x49F, "V"), + (0x4A0, "M", "ҡ"), + (0x4A1, "V"), + (0x4A2, "M", "ң"), + (0x4A3, "V"), + (0x4A4, "M", "ҥ"), + (0x4A5, "V"), + (0x4A6, "M", "ҧ"), + (0x4A7, "V"), + (0x4A8, "M", "ҩ"), + (0x4A9, "V"), + (0x4AA, "M", "ҫ"), + (0x4AB, "V"), + (0x4AC, "M", "ҭ"), + (0x4AD, "V"), + (0x4AE, "M", "ү"), + (0x4AF, "V"), + (0x4B0, "M", "ұ"), + (0x4B1, "V"), + (0x4B2, "M", "ҳ"), + (0x4B3, "V"), + (0x4B4, "M", "ҵ"), + (0x4B5, "V"), + (0x4B6, "M", "ҷ"), + (0x4B7, "V"), + (0x4B8, "M", "ҹ"), + (0x4B9, "V"), + (0x4BA, "M", "һ"), + (0x4BB, "V"), + (0x4BC, "M", "ҽ"), + (0x4BD, "V"), + (0x4BE, "M", "ҿ"), + (0x4BF, "V"), + (0x4C0, "X"), + (0x4C1, "M", "ӂ"), + (0x4C2, "V"), + (0x4C3, "M", "ӄ"), + (0x4C4, "V"), + (0x4C5, "M", "ӆ"), + (0x4C6, "V"), + (0x4C7, "M", "ӈ"), + (0x4C8, "V"), + (0x4C9, "M", "ӊ"), + (0x4CA, "V"), + (0x4CB, "M", "ӌ"), + (0x4CC, "V"), + (0x4CD, "M", "ӎ"), + (0x4CE, "V"), + (0x4D0, "M", "ӑ"), + (0x4D1, "V"), + (0x4D2, "M", "ӓ"), + (0x4D3, "V"), + (0x4D4, "M", "ӕ"), + (0x4D5, "V"), + (0x4D6, "M", "ӗ"), + (0x4D7, "V"), + (0x4D8, "M", "ә"), + (0x4D9, "V"), + (0x4DA, "M", "ӛ"), + (0x4DB, "V"), + (0x4DC, "M", "ӝ"), + (0x4DD, "V"), + (0x4DE, "M", "ӟ"), + (0x4DF, "V"), + (0x4E0, "M", "ӡ"), + (0x4E1, "V"), + (0x4E2, "M", "ӣ"), + (0x4E3, "V"), + (0x4E4, "M", "ӥ"), + (0x4E5, "V"), + (0x4E6, "M", "ӧ"), + (0x4E7, "V"), + (0x4E8, "M", "ө"), + (0x4E9, "V"), + (0x4EA, "M", "ӫ"), + (0x4EB, "V"), + (0x4EC, "M", "ӭ"), + (0x4ED, "V"), + (0x4EE, "M", "ӯ"), + (0x4EF, "V"), + (0x4F0, "M", "ӱ"), + (0x4F1, "V"), + (0x4F2, "M", "ӳ"), + (0x4F3, "V"), + (0x4F4, "M", "ӵ"), + (0x4F5, "V"), + (0x4F6, "M", "ӷ"), + (0x4F7, "V"), + (0x4F8, "M", "ӹ"), + (0x4F9, "V"), + (0x4FA, "M", "ӻ"), + (0x4FB, "V"), + (0x4FC, "M", "ӽ"), + (0x4FD, "V"), + (0x4FE, "M", "ӿ"), + (0x4FF, "V"), + (0x500, "M", "ԁ"), + (0x501, "V"), + (0x502, "M", "ԃ"), + ] + + +def _seg_9() -> List[Union[Tuple[int, str], Tuple[int, str, str]]]: + return [ + (0x503, "V"), + (0x504, "M", "ԅ"), + (0x505, "V"), + (0x506, "M", "ԇ"), + (0x507, "V"), + (0x508, "M", "ԉ"), + (0x509, "V"), + (0x50A, "M", "ԋ"), + (0x50B, "V"), + (0x50C, "M", "ԍ"), + (0x50D, "V"), + (0x50E, "M", "ԏ"), + (0x50F, "V"), + (0x510, "M", "ԑ"), + (0x511, "V"), + (0x512, "M", "ԓ"), + (0x513, "V"), + (0x514, "M", "ԕ"), + (0x515, "V"), + (0x516, "M", "ԗ"), + (0x517, "V"), + (0x518, "M", "ԙ"), + (0x519, "V"), + (0x51A, "M", "ԛ"), + (0x51B, "V"), + (0x51C, "M", "ԝ"), + (0x51D, "V"), + (0x51E, "M", "ԟ"), + (0x51F, "V"), + (0x520, "M", "ԡ"), + (0x521, "V"), + (0x522, "M", "ԣ"), + (0x523, "V"), + (0x524, "M", "ԥ"), + (0x525, "V"), + (0x526, "M", "ԧ"), + (0x527, "V"), + (0x528, "M", "ԩ"), + (0x529, "V"), + (0x52A, "M", "ԫ"), + (0x52B, "V"), + (0x52C, "M", "ԭ"), + (0x52D, "V"), + (0x52E, "M", "ԯ"), + (0x52F, "V"), + (0x530, "X"), + (0x531, "M", "ա"), + (0x532, "M", "բ"), + (0x533, "M", "գ"), + (0x534, "M", "դ"), + (0x535, "M", "ե"), + (0x536, "M", "զ"), + (0x537, "M", "է"), + (0x538, "M", "ը"), + (0x539, "M", "թ"), + (0x53A, "M", "ժ"), + (0x53B, "M", "ի"), + (0x53C, "M", "լ"), + (0x53D, "M", "խ"), + (0x53E, "M", "ծ"), + (0x53F, "M", "կ"), + (0x540, "M", "հ"), + (0x541, "M", "ձ"), + (0x542, "M", "ղ"), + (0x543, "M", "ճ"), + (0x544, "M", "մ"), + (0x545, "M", "յ"), + (0x546, "M", "ն"), + (0x547, "M", "շ"), + (0x548, "M", "ո"), + (0x549, "M", "չ"), + (0x54A, "M", "պ"), + (0x54B, "M", "ջ"), + (0x54C, "M", "ռ"), + (0x54D, "M", "ս"), + (0x54E, "M", "վ"), + (0x54F, "M", "տ"), + (0x550, "M", "ր"), + (0x551, "M", "ց"), + (0x552, "M", "ւ"), + (0x553, "M", "փ"), + (0x554, "M", "ք"), + (0x555, "M", "օ"), + (0x556, "M", "ֆ"), + (0x557, "X"), + (0x559, "V"), + (0x587, "M", "եւ"), + (0x588, "V"), + (0x58B, "X"), + (0x58D, "V"), + (0x590, "X"), + (0x591, "V"), + (0x5C8, "X"), + (0x5D0, "V"), + (0x5EB, "X"), + (0x5EF, "V"), + (0x5F5, "X"), + (0x606, "V"), + (0x61C, "X"), + (0x61D, "V"), + ] + + +def _seg_10() -> List[Union[Tuple[int, str], Tuple[int, str, str]]]: + return [ + (0x675, "M", "اٴ"), + (0x676, "M", "وٴ"), + (0x677, "M", "ۇٴ"), + (0x678, "M", "يٴ"), + (0x679, "V"), + (0x6DD, "X"), + (0x6DE, "V"), + (0x70E, "X"), + (0x710, "V"), + (0x74B, "X"), + (0x74D, "V"), + (0x7B2, "X"), + (0x7C0, "V"), + (0x7FB, "X"), + (0x7FD, "V"), + (0x82E, "X"), + (0x830, "V"), + (0x83F, "X"), + (0x840, "V"), + (0x85C, "X"), + (0x85E, "V"), + (0x85F, "X"), + (0x860, "V"), + (0x86B, "X"), + (0x870, "V"), + (0x88F, "X"), + (0x898, "V"), + (0x8E2, "X"), + (0x8E3, "V"), + (0x958, "M", "क़"), + (0x959, "M", "ख़"), + (0x95A, "M", "ग़"), + (0x95B, "M", "ज़"), + (0x95C, "M", "ड़"), + (0x95D, "M", "ढ़"), + (0x95E, "M", "फ़"), + (0x95F, "M", "य़"), + (0x960, "V"), + (0x984, "X"), + (0x985, "V"), + (0x98D, "X"), + (0x98F, "V"), + (0x991, "X"), + (0x993, "V"), + (0x9A9, "X"), + (0x9AA, "V"), + (0x9B1, "X"), + (0x9B2, "V"), + (0x9B3, "X"), + (0x9B6, "V"), + (0x9BA, "X"), + (0x9BC, "V"), + (0x9C5, "X"), + (0x9C7, "V"), + (0x9C9, "X"), + (0x9CB, "V"), + (0x9CF, "X"), + (0x9D7, "V"), + (0x9D8, "X"), + (0x9DC, "M", "ড়"), + (0x9DD, "M", "ঢ়"), + (0x9DE, "X"), + (0x9DF, "M", "য়"), + (0x9E0, "V"), + (0x9E4, "X"), + (0x9E6, "V"), + (0x9FF, "X"), + (0xA01, "V"), + (0xA04, "X"), + (0xA05, "V"), + (0xA0B, "X"), + (0xA0F, "V"), + (0xA11, "X"), + (0xA13, "V"), + (0xA29, "X"), + (0xA2A, "V"), + (0xA31, "X"), + (0xA32, "V"), + (0xA33, "M", "ਲ਼"), + (0xA34, "X"), + (0xA35, "V"), + (0xA36, "M", "ਸ਼"), + (0xA37, "X"), + (0xA38, "V"), + (0xA3A, "X"), + (0xA3C, "V"), + (0xA3D, "X"), + (0xA3E, "V"), + (0xA43, "X"), + (0xA47, "V"), + (0xA49, "X"), + (0xA4B, "V"), + (0xA4E, "X"), + (0xA51, "V"), + (0xA52, "X"), + (0xA59, "M", "ਖ਼"), + (0xA5A, "M", "ਗ਼"), + (0xA5B, "M", "ਜ਼"), + (0xA5C, "V"), + (0xA5D, "X"), + ] + + +def _seg_11() -> List[Union[Tuple[int, str], Tuple[int, str, str]]]: + return [ + (0xA5E, "M", "ਫ਼"), + (0xA5F, "X"), + (0xA66, "V"), + (0xA77, "X"), + (0xA81, "V"), + (0xA84, "X"), + (0xA85, "V"), + (0xA8E, "X"), + (0xA8F, "V"), + (0xA92, "X"), + (0xA93, "V"), + (0xAA9, "X"), + (0xAAA, "V"), + (0xAB1, "X"), + (0xAB2, "V"), + (0xAB4, "X"), + (0xAB5, "V"), + (0xABA, "X"), + (0xABC, "V"), + (0xAC6, "X"), + (0xAC7, "V"), + (0xACA, "X"), + (0xACB, "V"), + (0xACE, "X"), + (0xAD0, "V"), + (0xAD1, "X"), + (0xAE0, "V"), + (0xAE4, "X"), + (0xAE6, "V"), + (0xAF2, "X"), + (0xAF9, "V"), + (0xB00, "X"), + (0xB01, "V"), + (0xB04, "X"), + (0xB05, "V"), + (0xB0D, "X"), + (0xB0F, "V"), + (0xB11, "X"), + (0xB13, "V"), + (0xB29, "X"), + (0xB2A, "V"), + (0xB31, "X"), + (0xB32, "V"), + (0xB34, "X"), + (0xB35, "V"), + (0xB3A, "X"), + (0xB3C, "V"), + (0xB45, "X"), + (0xB47, "V"), + (0xB49, "X"), + (0xB4B, "V"), + (0xB4E, "X"), + (0xB55, "V"), + (0xB58, "X"), + (0xB5C, "M", "ଡ଼"), + (0xB5D, "M", "ଢ଼"), + (0xB5E, "X"), + (0xB5F, "V"), + (0xB64, "X"), + (0xB66, "V"), + (0xB78, "X"), + (0xB82, "V"), + (0xB84, "X"), + (0xB85, "V"), + (0xB8B, "X"), + (0xB8E, "V"), + (0xB91, "X"), + (0xB92, "V"), + (0xB96, "X"), + (0xB99, "V"), + (0xB9B, "X"), + (0xB9C, "V"), + (0xB9D, "X"), + (0xB9E, "V"), + (0xBA0, "X"), + (0xBA3, "V"), + (0xBA5, "X"), + (0xBA8, "V"), + (0xBAB, "X"), + (0xBAE, "V"), + (0xBBA, "X"), + (0xBBE, "V"), + (0xBC3, "X"), + (0xBC6, "V"), + (0xBC9, "X"), + (0xBCA, "V"), + (0xBCE, "X"), + (0xBD0, "V"), + (0xBD1, "X"), + (0xBD7, "V"), + (0xBD8, "X"), + (0xBE6, "V"), + (0xBFB, "X"), + (0xC00, "V"), + (0xC0D, "X"), + (0xC0E, "V"), + (0xC11, "X"), + (0xC12, "V"), + (0xC29, "X"), + (0xC2A, "V"), + ] + + +def _seg_12() -> List[Union[Tuple[int, str], Tuple[int, str, str]]]: + return [ + (0xC3A, "X"), + (0xC3C, "V"), + (0xC45, "X"), + (0xC46, "V"), + (0xC49, "X"), + (0xC4A, "V"), + (0xC4E, "X"), + (0xC55, "V"), + (0xC57, "X"), + (0xC58, "V"), + (0xC5B, "X"), + (0xC5D, "V"), + (0xC5E, "X"), + (0xC60, "V"), + (0xC64, "X"), + (0xC66, "V"), + (0xC70, "X"), + (0xC77, "V"), + (0xC8D, "X"), + (0xC8E, "V"), + (0xC91, "X"), + (0xC92, "V"), + (0xCA9, "X"), + (0xCAA, "V"), + (0xCB4, "X"), + (0xCB5, "V"), + (0xCBA, "X"), + (0xCBC, "V"), + (0xCC5, "X"), + (0xCC6, "V"), + (0xCC9, "X"), + (0xCCA, "V"), + (0xCCE, "X"), + (0xCD5, "V"), + (0xCD7, "X"), + (0xCDD, "V"), + (0xCDF, "X"), + (0xCE0, "V"), + (0xCE4, "X"), + (0xCE6, "V"), + (0xCF0, "X"), + (0xCF1, "V"), + (0xCF4, "X"), + (0xD00, "V"), + (0xD0D, "X"), + (0xD0E, "V"), + (0xD11, "X"), + (0xD12, "V"), + (0xD45, "X"), + (0xD46, "V"), + (0xD49, "X"), + (0xD4A, "V"), + (0xD50, "X"), + (0xD54, "V"), + (0xD64, "X"), + (0xD66, "V"), + (0xD80, "X"), + (0xD81, "V"), + (0xD84, "X"), + (0xD85, "V"), + (0xD97, "X"), + (0xD9A, "V"), + (0xDB2, "X"), + (0xDB3, "V"), + (0xDBC, "X"), + (0xDBD, "V"), + (0xDBE, "X"), + (0xDC0, "V"), + (0xDC7, "X"), + (0xDCA, "V"), + (0xDCB, "X"), + (0xDCF, "V"), + (0xDD5, "X"), + (0xDD6, "V"), + (0xDD7, "X"), + (0xDD8, "V"), + (0xDE0, "X"), + (0xDE6, "V"), + (0xDF0, "X"), + (0xDF2, "V"), + (0xDF5, "X"), + (0xE01, "V"), + (0xE33, "M", "ํา"), + (0xE34, "V"), + (0xE3B, "X"), + (0xE3F, "V"), + (0xE5C, "X"), + (0xE81, "V"), + (0xE83, "X"), + (0xE84, "V"), + (0xE85, "X"), + (0xE86, "V"), + (0xE8B, "X"), + (0xE8C, "V"), + (0xEA4, "X"), + (0xEA5, "V"), + (0xEA6, "X"), + (0xEA7, "V"), + (0xEB3, "M", "ໍາ"), + (0xEB4, "V"), + ] + + +def _seg_13() -> List[Union[Tuple[int, str], Tuple[int, str, str]]]: + return [ + (0xEBE, "X"), + (0xEC0, "V"), + (0xEC5, "X"), + (0xEC6, "V"), + (0xEC7, "X"), + (0xEC8, "V"), + (0xECF, "X"), + (0xED0, "V"), + (0xEDA, "X"), + (0xEDC, "M", "ຫນ"), + (0xEDD, "M", "ຫມ"), + (0xEDE, "V"), + (0xEE0, "X"), + (0xF00, "V"), + (0xF0C, "M", "་"), + (0xF0D, "V"), + (0xF43, "M", "གྷ"), + (0xF44, "V"), + (0xF48, "X"), + (0xF49, "V"), + (0xF4D, "M", "ཌྷ"), + (0xF4E, "V"), + (0xF52, "M", "དྷ"), + (0xF53, "V"), + (0xF57, "M", "བྷ"), + (0xF58, "V"), + (0xF5C, "M", "ཛྷ"), + (0xF5D, "V"), + (0xF69, "M", "ཀྵ"), + (0xF6A, "V"), + (0xF6D, "X"), + (0xF71, "V"), + (0xF73, "M", "ཱི"), + (0xF74, "V"), + (0xF75, "M", "ཱུ"), + (0xF76, "M", "ྲྀ"), + (0xF77, "M", "ྲཱྀ"), + (0xF78, "M", "ླྀ"), + (0xF79, "M", "ླཱྀ"), + (0xF7A, "V"), + (0xF81, "M", "ཱྀ"), + (0xF82, "V"), + (0xF93, "M", "ྒྷ"), + (0xF94, "V"), + (0xF98, "X"), + (0xF99, "V"), + (0xF9D, "M", "ྜྷ"), + (0xF9E, "V"), + (0xFA2, "M", "ྡྷ"), + (0xFA3, "V"), + (0xFA7, "M", "ྦྷ"), + (0xFA8, "V"), + (0xFAC, "M", "ྫྷ"), + (0xFAD, "V"), + (0xFB9, "M", "ྐྵ"), + (0xFBA, "V"), + (0xFBD, "X"), + (0xFBE, "V"), + (0xFCD, "X"), + (0xFCE, "V"), + (0xFDB, "X"), + (0x1000, "V"), + (0x10A0, "X"), + (0x10C7, "M", "ⴧ"), + (0x10C8, "X"), + (0x10CD, "M", "ⴭ"), + (0x10CE, "X"), + (0x10D0, "V"), + (0x10FC, "M", "ნ"), + (0x10FD, "V"), + (0x115F, "X"), + (0x1161, "V"), + (0x1249, "X"), + (0x124A, "V"), + (0x124E, "X"), + (0x1250, "V"), + (0x1257, "X"), + (0x1258, "V"), + (0x1259, "X"), + (0x125A, "V"), + (0x125E, "X"), + (0x1260, "V"), + (0x1289, "X"), + (0x128A, "V"), + (0x128E, "X"), + (0x1290, "V"), + (0x12B1, "X"), + (0x12B2, "V"), + (0x12B6, "X"), + (0x12B8, "V"), + (0x12BF, "X"), + (0x12C0, "V"), + (0x12C1, "X"), + (0x12C2, "V"), + (0x12C6, "X"), + (0x12C8, "V"), + (0x12D7, "X"), + (0x12D8, "V"), + (0x1311, "X"), + (0x1312, "V"), + ] + + +def _seg_14() -> List[Union[Tuple[int, str], Tuple[int, str, str]]]: + return [ + (0x1316, "X"), + (0x1318, "V"), + (0x135B, "X"), + (0x135D, "V"), + (0x137D, "X"), + (0x1380, "V"), + (0x139A, "X"), + (0x13A0, "V"), + (0x13F6, "X"), + (0x13F8, "M", "Ᏸ"), + (0x13F9, "M", "Ᏹ"), + (0x13FA, "M", "Ᏺ"), + (0x13FB, "M", "Ᏻ"), + (0x13FC, "M", "Ᏼ"), + (0x13FD, "M", "Ᏽ"), + (0x13FE, "X"), + (0x1400, "V"), + (0x1680, "X"), + (0x1681, "V"), + (0x169D, "X"), + (0x16A0, "V"), + (0x16F9, "X"), + (0x1700, "V"), + (0x1716, "X"), + (0x171F, "V"), + (0x1737, "X"), + (0x1740, "V"), + (0x1754, "X"), + (0x1760, "V"), + (0x176D, "X"), + (0x176E, "V"), + (0x1771, "X"), + (0x1772, "V"), + (0x1774, "X"), + (0x1780, "V"), + (0x17B4, "X"), + (0x17B6, "V"), + (0x17DE, "X"), + (0x17E0, "V"), + (0x17EA, "X"), + (0x17F0, "V"), + (0x17FA, "X"), + (0x1800, "V"), + (0x1806, "X"), + (0x1807, "V"), + (0x180B, "I"), + (0x180E, "X"), + (0x180F, "I"), + (0x1810, "V"), + (0x181A, "X"), + (0x1820, "V"), + (0x1879, "X"), + (0x1880, "V"), + (0x18AB, "X"), + (0x18B0, "V"), + (0x18F6, "X"), + (0x1900, "V"), + (0x191F, "X"), + (0x1920, "V"), + (0x192C, "X"), + (0x1930, "V"), + (0x193C, "X"), + (0x1940, "V"), + (0x1941, "X"), + (0x1944, "V"), + (0x196E, "X"), + (0x1970, "V"), + (0x1975, "X"), + (0x1980, "V"), + (0x19AC, "X"), + (0x19B0, "V"), + (0x19CA, "X"), + (0x19D0, "V"), + (0x19DB, "X"), + (0x19DE, "V"), + (0x1A1C, "X"), + (0x1A1E, "V"), + (0x1A5F, "X"), + (0x1A60, "V"), + (0x1A7D, "X"), + (0x1A7F, "V"), + (0x1A8A, "X"), + (0x1A90, "V"), + (0x1A9A, "X"), + (0x1AA0, "V"), + (0x1AAE, "X"), + (0x1AB0, "V"), + (0x1ACF, "X"), + (0x1B00, "V"), + (0x1B4D, "X"), + (0x1B50, "V"), + (0x1B7F, "X"), + (0x1B80, "V"), + (0x1BF4, "X"), + (0x1BFC, "V"), + (0x1C38, "X"), + (0x1C3B, "V"), + (0x1C4A, "X"), + (0x1C4D, "V"), + (0x1C80, "M", "в"), + ] + + +def _seg_15() -> List[Union[Tuple[int, str], Tuple[int, str, str]]]: + return [ + (0x1C81, "M", "д"), + (0x1C82, "M", "о"), + (0x1C83, "M", "с"), + (0x1C84, "M", "т"), + (0x1C86, "M", "ъ"), + (0x1C87, "M", "ѣ"), + (0x1C88, "M", "ꙋ"), + (0x1C89, "X"), + (0x1C90, "M", "ა"), + (0x1C91, "M", "ბ"), + (0x1C92, "M", "გ"), + (0x1C93, "M", "დ"), + (0x1C94, "M", "ე"), + (0x1C95, "M", "ვ"), + (0x1C96, "M", "ზ"), + (0x1C97, "M", "თ"), + (0x1C98, "M", "ი"), + (0x1C99, "M", "კ"), + (0x1C9A, "M", "ლ"), + (0x1C9B, "M", "მ"), + (0x1C9C, "M", "ნ"), + (0x1C9D, "M", "ო"), + (0x1C9E, "M", "პ"), + (0x1C9F, "M", "ჟ"), + (0x1CA0, "M", "რ"), + (0x1CA1, "M", "ს"), + (0x1CA2, "M", "ტ"), + (0x1CA3, "M", "უ"), + (0x1CA4, "M", "ფ"), + (0x1CA5, "M", "ქ"), + (0x1CA6, "M", "ღ"), + (0x1CA7, "M", "ყ"), + (0x1CA8, "M", "შ"), + (0x1CA9, "M", "ჩ"), + (0x1CAA, "M", "ც"), + (0x1CAB, "M", "ძ"), + (0x1CAC, "M", "წ"), + (0x1CAD, "M", "ჭ"), + (0x1CAE, "M", "ხ"), + (0x1CAF, "M", "ჯ"), + (0x1CB0, "M", "ჰ"), + (0x1CB1, "M", "ჱ"), + (0x1CB2, "M", "ჲ"), + (0x1CB3, "M", "ჳ"), + (0x1CB4, "M", "ჴ"), + (0x1CB5, "M", "ჵ"), + (0x1CB6, "M", "ჶ"), + (0x1CB7, "M", "ჷ"), + (0x1CB8, "M", "ჸ"), + (0x1CB9, "M", "ჹ"), + (0x1CBA, "M", "ჺ"), + (0x1CBB, "X"), + (0x1CBD, "M", "ჽ"), + (0x1CBE, "M", "ჾ"), + (0x1CBF, "M", "ჿ"), + (0x1CC0, "V"), + (0x1CC8, "X"), + (0x1CD0, "V"), + (0x1CFB, "X"), + (0x1D00, "V"), + (0x1D2C, "M", "a"), + (0x1D2D, "M", "æ"), + (0x1D2E, "M", "b"), + (0x1D2F, "V"), + (0x1D30, "M", "d"), + (0x1D31, "M", "e"), + (0x1D32, "M", "ǝ"), + (0x1D33, "M", "g"), + (0x1D34, "M", "h"), + (0x1D35, "M", "i"), + (0x1D36, "M", "j"), + (0x1D37, "M", "k"), + (0x1D38, "M", "l"), + (0x1D39, "M", "m"), + (0x1D3A, "M", "n"), + (0x1D3B, "V"), + (0x1D3C, "M", "o"), + (0x1D3D, "M", "ȣ"), + (0x1D3E, "M", "p"), + (0x1D3F, "M", "r"), + (0x1D40, "M", "t"), + (0x1D41, "M", "u"), + (0x1D42, "M", "w"), + (0x1D43, "M", "a"), + (0x1D44, "M", "ɐ"), + (0x1D45, "M", "ɑ"), + (0x1D46, "M", "ᴂ"), + (0x1D47, "M", "b"), + (0x1D48, "M", "d"), + (0x1D49, "M", "e"), + (0x1D4A, "M", "ə"), + (0x1D4B, "M", "ɛ"), + (0x1D4C, "M", "ɜ"), + (0x1D4D, "M", "g"), + (0x1D4E, "V"), + (0x1D4F, "M", "k"), + (0x1D50, "M", "m"), + (0x1D51, "M", "ŋ"), + (0x1D52, "M", "o"), + (0x1D53, "M", "ɔ"), + ] + + +def _seg_16() -> List[Union[Tuple[int, str], Tuple[int, str, str]]]: + return [ + (0x1D54, "M", "ᴖ"), + (0x1D55, "M", "ᴗ"), + (0x1D56, "M", "p"), + (0x1D57, "M", "t"), + (0x1D58, "M", "u"), + (0x1D59, "M", "ᴝ"), + (0x1D5A, "M", "ɯ"), + (0x1D5B, "M", "v"), + (0x1D5C, "M", "ᴥ"), + (0x1D5D, "M", "β"), + (0x1D5E, "M", "γ"), + (0x1D5F, "M", "δ"), + (0x1D60, "M", "φ"), + (0x1D61, "M", "χ"), + (0x1D62, "M", "i"), + (0x1D63, "M", "r"), + (0x1D64, "M", "u"), + (0x1D65, "M", "v"), + (0x1D66, "M", "β"), + (0x1D67, "M", "γ"), + (0x1D68, "M", "ρ"), + (0x1D69, "M", "φ"), + (0x1D6A, "M", "χ"), + (0x1D6B, "V"), + (0x1D78, "M", "н"), + (0x1D79, "V"), + (0x1D9B, "M", "ɒ"), + (0x1D9C, "M", "c"), + (0x1D9D, "M", "ɕ"), + (0x1D9E, "M", "ð"), + (0x1D9F, "M", "ɜ"), + (0x1DA0, "M", "f"), + (0x1DA1, "M", "ɟ"), + (0x1DA2, "M", "ɡ"), + (0x1DA3, "M", "ɥ"), + (0x1DA4, "M", "ɨ"), + (0x1DA5, "M", "ɩ"), + (0x1DA6, "M", "ɪ"), + (0x1DA7, "M", "ᵻ"), + (0x1DA8, "M", "ʝ"), + (0x1DA9, "M", "ɭ"), + (0x1DAA, "M", "ᶅ"), + (0x1DAB, "M", "ʟ"), + (0x1DAC, "M", "ɱ"), + (0x1DAD, "M", "ɰ"), + (0x1DAE, "M", "ɲ"), + (0x1DAF, "M", "ɳ"), + (0x1DB0, "M", "ɴ"), + (0x1DB1, "M", "ɵ"), + (0x1DB2, "M", "ɸ"), + (0x1DB3, "M", "ʂ"), + (0x1DB4, "M", "ʃ"), + (0x1DB5, "M", "ƫ"), + (0x1DB6, "M", "ʉ"), + (0x1DB7, "M", "ʊ"), + (0x1DB8, "M", "ᴜ"), + (0x1DB9, "M", "ʋ"), + (0x1DBA, "M", "ʌ"), + (0x1DBB, "M", "z"), + (0x1DBC, "M", "ʐ"), + (0x1DBD, "M", "ʑ"), + (0x1DBE, "M", "ʒ"), + (0x1DBF, "M", "θ"), + (0x1DC0, "V"), + (0x1E00, "M", "ḁ"), + (0x1E01, "V"), + (0x1E02, "M", "ḃ"), + (0x1E03, "V"), + (0x1E04, "M", "ḅ"), + (0x1E05, "V"), + (0x1E06, "M", "ḇ"), + (0x1E07, "V"), + (0x1E08, "M", "ḉ"), + (0x1E09, "V"), + (0x1E0A, "M", "ḋ"), + (0x1E0B, "V"), + (0x1E0C, "M", "ḍ"), + (0x1E0D, "V"), + (0x1E0E, "M", "ḏ"), + (0x1E0F, "V"), + (0x1E10, "M", "ḑ"), + (0x1E11, "V"), + (0x1E12, "M", "ḓ"), + (0x1E13, "V"), + (0x1E14, "M", "ḕ"), + (0x1E15, "V"), + (0x1E16, "M", "ḗ"), + (0x1E17, "V"), + (0x1E18, "M", "ḙ"), + (0x1E19, "V"), + (0x1E1A, "M", "ḛ"), + (0x1E1B, "V"), + (0x1E1C, "M", "ḝ"), + (0x1E1D, "V"), + (0x1E1E, "M", "ḟ"), + (0x1E1F, "V"), + (0x1E20, "M", "ḡ"), + (0x1E21, "V"), + (0x1E22, "M", "ḣ"), + (0x1E23, "V"), + ] + + +def _seg_17() -> List[Union[Tuple[int, str], Tuple[int, str, str]]]: + return [ + (0x1E24, "M", "ḥ"), + (0x1E25, "V"), + (0x1E26, "M", "ḧ"), + (0x1E27, "V"), + (0x1E28, "M", "ḩ"), + (0x1E29, "V"), + (0x1E2A, "M", "ḫ"), + (0x1E2B, "V"), + (0x1E2C, "M", "ḭ"), + (0x1E2D, "V"), + (0x1E2E, "M", "ḯ"), + (0x1E2F, "V"), + (0x1E30, "M", "ḱ"), + (0x1E31, "V"), + (0x1E32, "M", "ḳ"), + (0x1E33, "V"), + (0x1E34, "M", "ḵ"), + (0x1E35, "V"), + (0x1E36, "M", "ḷ"), + (0x1E37, "V"), + (0x1E38, "M", "ḹ"), + (0x1E39, "V"), + (0x1E3A, "M", "ḻ"), + (0x1E3B, "V"), + (0x1E3C, "M", "ḽ"), + (0x1E3D, "V"), + (0x1E3E, "M", "ḿ"), + (0x1E3F, "V"), + (0x1E40, "M", "ṁ"), + (0x1E41, "V"), + (0x1E42, "M", "ṃ"), + (0x1E43, "V"), + (0x1E44, "M", "ṅ"), + (0x1E45, "V"), + (0x1E46, "M", "ṇ"), + (0x1E47, "V"), + (0x1E48, "M", "ṉ"), + (0x1E49, "V"), + (0x1E4A, "M", "ṋ"), + (0x1E4B, "V"), + (0x1E4C, "M", "ṍ"), + (0x1E4D, "V"), + (0x1E4E, "M", "ṏ"), + (0x1E4F, "V"), + (0x1E50, "M", "ṑ"), + (0x1E51, "V"), + (0x1E52, "M", "ṓ"), + (0x1E53, "V"), + (0x1E54, "M", "ṕ"), + (0x1E55, "V"), + (0x1E56, "M", "ṗ"), + (0x1E57, "V"), + (0x1E58, "M", "ṙ"), + (0x1E59, "V"), + (0x1E5A, "M", "ṛ"), + (0x1E5B, "V"), + (0x1E5C, "M", "ṝ"), + (0x1E5D, "V"), + (0x1E5E, "M", "ṟ"), + (0x1E5F, "V"), + (0x1E60, "M", "ṡ"), + (0x1E61, "V"), + (0x1E62, "M", "ṣ"), + (0x1E63, "V"), + (0x1E64, "M", "ṥ"), + (0x1E65, "V"), + (0x1E66, "M", "ṧ"), + (0x1E67, "V"), + (0x1E68, "M", "ṩ"), + (0x1E69, "V"), + (0x1E6A, "M", "ṫ"), + (0x1E6B, "V"), + (0x1E6C, "M", "ṭ"), + (0x1E6D, "V"), + (0x1E6E, "M", "ṯ"), + (0x1E6F, "V"), + (0x1E70, "M", "ṱ"), + (0x1E71, "V"), + (0x1E72, "M", "ṳ"), + (0x1E73, "V"), + (0x1E74, "M", "ṵ"), + (0x1E75, "V"), + (0x1E76, "M", "ṷ"), + (0x1E77, "V"), + (0x1E78, "M", "ṹ"), + (0x1E79, "V"), + (0x1E7A, "M", "ṻ"), + (0x1E7B, "V"), + (0x1E7C, "M", "ṽ"), + (0x1E7D, "V"), + (0x1E7E, "M", "ṿ"), + (0x1E7F, "V"), + (0x1E80, "M", "ẁ"), + (0x1E81, "V"), + (0x1E82, "M", "ẃ"), + (0x1E83, "V"), + (0x1E84, "M", "ẅ"), + (0x1E85, "V"), + (0x1E86, "M", "ẇ"), + (0x1E87, "V"), + ] + + +def _seg_18() -> List[Union[Tuple[int, str], Tuple[int, str, str]]]: + return [ + (0x1E88, "M", "ẉ"), + (0x1E89, "V"), + (0x1E8A, "M", "ẋ"), + (0x1E8B, "V"), + (0x1E8C, "M", "ẍ"), + (0x1E8D, "V"), + (0x1E8E, "M", "ẏ"), + (0x1E8F, "V"), + (0x1E90, "M", "ẑ"), + (0x1E91, "V"), + (0x1E92, "M", "ẓ"), + (0x1E93, "V"), + (0x1E94, "M", "ẕ"), + (0x1E95, "V"), + (0x1E9A, "M", "aʾ"), + (0x1E9B, "M", "ṡ"), + (0x1E9C, "V"), + (0x1E9E, "M", "ß"), + (0x1E9F, "V"), + (0x1EA0, "M", "ạ"), + (0x1EA1, "V"), + (0x1EA2, "M", "ả"), + (0x1EA3, "V"), + (0x1EA4, "M", "ấ"), + (0x1EA5, "V"), + (0x1EA6, "M", "ầ"), + (0x1EA7, "V"), + (0x1EA8, "M", "ẩ"), + (0x1EA9, "V"), + (0x1EAA, "M", "ẫ"), + (0x1EAB, "V"), + (0x1EAC, "M", "ậ"), + (0x1EAD, "V"), + (0x1EAE, "M", "ắ"), + (0x1EAF, "V"), + (0x1EB0, "M", "ằ"), + (0x1EB1, "V"), + (0x1EB2, "M", "ẳ"), + (0x1EB3, "V"), + (0x1EB4, "M", "ẵ"), + (0x1EB5, "V"), + (0x1EB6, "M", "ặ"), + (0x1EB7, "V"), + (0x1EB8, "M", "ẹ"), + (0x1EB9, "V"), + (0x1EBA, "M", "ẻ"), + (0x1EBB, "V"), + (0x1EBC, "M", "ẽ"), + (0x1EBD, "V"), + (0x1EBE, "M", "ế"), + (0x1EBF, "V"), + (0x1EC0, "M", "ề"), + (0x1EC1, "V"), + (0x1EC2, "M", "ể"), + (0x1EC3, "V"), + (0x1EC4, "M", "ễ"), + (0x1EC5, "V"), + (0x1EC6, "M", "ệ"), + (0x1EC7, "V"), + (0x1EC8, "M", "ỉ"), + (0x1EC9, "V"), + (0x1ECA, "M", "ị"), + (0x1ECB, "V"), + (0x1ECC, "M", "ọ"), + (0x1ECD, "V"), + (0x1ECE, "M", "ỏ"), + (0x1ECF, "V"), + (0x1ED0, "M", "ố"), + (0x1ED1, "V"), + (0x1ED2, "M", "ồ"), + (0x1ED3, "V"), + (0x1ED4, "M", "ổ"), + (0x1ED5, "V"), + (0x1ED6, "M", "ỗ"), + (0x1ED7, "V"), + (0x1ED8, "M", "ộ"), + (0x1ED9, "V"), + (0x1EDA, "M", "ớ"), + (0x1EDB, "V"), + (0x1EDC, "M", "ờ"), + (0x1EDD, "V"), + (0x1EDE, "M", "ở"), + (0x1EDF, "V"), + (0x1EE0, "M", "ỡ"), + (0x1EE1, "V"), + (0x1EE2, "M", "ợ"), + (0x1EE3, "V"), + (0x1EE4, "M", "ụ"), + (0x1EE5, "V"), + (0x1EE6, "M", "ủ"), + (0x1EE7, "V"), + (0x1EE8, "M", "ứ"), + (0x1EE9, "V"), + (0x1EEA, "M", "ừ"), + (0x1EEB, "V"), + (0x1EEC, "M", "ử"), + (0x1EED, "V"), + (0x1EEE, "M", "ữ"), + (0x1EEF, "V"), + (0x1EF0, "M", "ự"), + ] + + +def _seg_19() -> List[Union[Tuple[int, str], Tuple[int, str, str]]]: + return [ + (0x1EF1, "V"), + (0x1EF2, "M", "ỳ"), + (0x1EF3, "V"), + (0x1EF4, "M", "ỵ"), + (0x1EF5, "V"), + (0x1EF6, "M", "ỷ"), + (0x1EF7, "V"), + (0x1EF8, "M", "ỹ"), + (0x1EF9, "V"), + (0x1EFA, "M", "ỻ"), + (0x1EFB, "V"), + (0x1EFC, "M", "ỽ"), + (0x1EFD, "V"), + (0x1EFE, "M", "ỿ"), + (0x1EFF, "V"), + (0x1F08, "M", "ἀ"), + (0x1F09, "M", "ἁ"), + (0x1F0A, "M", "ἂ"), + (0x1F0B, "M", "ἃ"), + (0x1F0C, "M", "ἄ"), + (0x1F0D, "M", "ἅ"), + (0x1F0E, "M", "ἆ"), + (0x1F0F, "M", "ἇ"), + (0x1F10, "V"), + (0x1F16, "X"), + (0x1F18, "M", "ἐ"), + (0x1F19, "M", "ἑ"), + (0x1F1A, "M", "ἒ"), + (0x1F1B, "M", "ἓ"), + (0x1F1C, "M", "ἔ"), + (0x1F1D, "M", "ἕ"), + (0x1F1E, "X"), + (0x1F20, "V"), + (0x1F28, "M", "ἠ"), + (0x1F29, "M", "ἡ"), + (0x1F2A, "M", "ἢ"), + (0x1F2B, "M", "ἣ"), + (0x1F2C, "M", "ἤ"), + (0x1F2D, "M", "ἥ"), + (0x1F2E, "M", "ἦ"), + (0x1F2F, "M", "ἧ"), + (0x1F30, "V"), + (0x1F38, "M", "ἰ"), + (0x1F39, "M", "ἱ"), + (0x1F3A, "M", "ἲ"), + (0x1F3B, "M", "ἳ"), + (0x1F3C, "M", "ἴ"), + (0x1F3D, "M", "ἵ"), + (0x1F3E, "M", "ἶ"), + (0x1F3F, "M", "ἷ"), + (0x1F40, "V"), + (0x1F46, "X"), + (0x1F48, "M", "ὀ"), + (0x1F49, "M", "ὁ"), + (0x1F4A, "M", "ὂ"), + (0x1F4B, "M", "ὃ"), + (0x1F4C, "M", "ὄ"), + (0x1F4D, "M", "ὅ"), + (0x1F4E, "X"), + (0x1F50, "V"), + (0x1F58, "X"), + (0x1F59, "M", "ὑ"), + (0x1F5A, "X"), + (0x1F5B, "M", "ὓ"), + (0x1F5C, "X"), + (0x1F5D, "M", "ὕ"), + (0x1F5E, "X"), + (0x1F5F, "M", "ὗ"), + (0x1F60, "V"), + (0x1F68, "M", "ὠ"), + (0x1F69, "M", "ὡ"), + (0x1F6A, "M", "ὢ"), + (0x1F6B, "M", "ὣ"), + (0x1F6C, "M", "ὤ"), + (0x1F6D, "M", "ὥ"), + (0x1F6E, "M", "ὦ"), + (0x1F6F, "M", "ὧ"), + (0x1F70, "V"), + (0x1F71, "M", "ά"), + (0x1F72, "V"), + (0x1F73, "M", "έ"), + (0x1F74, "V"), + (0x1F75, "M", "ή"), + (0x1F76, "V"), + (0x1F77, "M", "ί"), + (0x1F78, "V"), + (0x1F79, "M", "ό"), + (0x1F7A, "V"), + (0x1F7B, "M", "ύ"), + (0x1F7C, "V"), + (0x1F7D, "M", "ώ"), + (0x1F7E, "X"), + (0x1F80, "M", "ἀι"), + (0x1F81, "M", "ἁι"), + (0x1F82, "M", "ἂι"), + (0x1F83, "M", "ἃι"), + (0x1F84, "M", "ἄι"), + (0x1F85, "M", "ἅι"), + (0x1F86, "M", "ἆι"), + (0x1F87, "M", "ἇι"), + ] + + +def _seg_20() -> List[Union[Tuple[int, str], Tuple[int, str, str]]]: + return [ + (0x1F88, "M", "ἀι"), + (0x1F89, "M", "ἁι"), + (0x1F8A, "M", "ἂι"), + (0x1F8B, "M", "ἃι"), + (0x1F8C, "M", "ἄι"), + (0x1F8D, "M", "ἅι"), + (0x1F8E, "M", "ἆι"), + (0x1F8F, "M", "ἇι"), + (0x1F90, "M", "ἠι"), + (0x1F91, "M", "ἡι"), + (0x1F92, "M", "ἢι"), + (0x1F93, "M", "ἣι"), + (0x1F94, "M", "ἤι"), + (0x1F95, "M", "ἥι"), + (0x1F96, "M", "ἦι"), + (0x1F97, "M", "ἧι"), + (0x1F98, "M", "ἠι"), + (0x1F99, "M", "ἡι"), + (0x1F9A, "M", "ἢι"), + (0x1F9B, "M", "ἣι"), + (0x1F9C, "M", "ἤι"), + (0x1F9D, "M", "ἥι"), + (0x1F9E, "M", "ἦι"), + (0x1F9F, "M", "ἧι"), + (0x1FA0, "M", "ὠι"), + (0x1FA1, "M", "ὡι"), + (0x1FA2, "M", "ὢι"), + (0x1FA3, "M", "ὣι"), + (0x1FA4, "M", "ὤι"), + (0x1FA5, "M", "ὥι"), + (0x1FA6, "M", "ὦι"), + (0x1FA7, "M", "ὧι"), + (0x1FA8, "M", "ὠι"), + (0x1FA9, "M", "ὡι"), + (0x1FAA, "M", "ὢι"), + (0x1FAB, "M", "ὣι"), + (0x1FAC, "M", "ὤι"), + (0x1FAD, "M", "ὥι"), + (0x1FAE, "M", "ὦι"), + (0x1FAF, "M", "ὧι"), + (0x1FB0, "V"), + (0x1FB2, "M", "ὰι"), + (0x1FB3, "M", "αι"), + (0x1FB4, "M", "άι"), + (0x1FB5, "X"), + (0x1FB6, "V"), + (0x1FB7, "M", "ᾶι"), + (0x1FB8, "M", "ᾰ"), + (0x1FB9, "M", "ᾱ"), + (0x1FBA, "M", "ὰ"), + (0x1FBB, "M", "ά"), + (0x1FBC, "M", "αι"), + (0x1FBD, "3", " ̓"), + (0x1FBE, "M", "ι"), + (0x1FBF, "3", " ̓"), + (0x1FC0, "3", " ͂"), + (0x1FC1, "3", " ̈͂"), + (0x1FC2, "M", "ὴι"), + (0x1FC3, "M", "ηι"), + (0x1FC4, "M", "ήι"), + (0x1FC5, "X"), + (0x1FC6, "V"), + (0x1FC7, "M", "ῆι"), + (0x1FC8, "M", "ὲ"), + (0x1FC9, "M", "έ"), + (0x1FCA, "M", "ὴ"), + (0x1FCB, "M", "ή"), + (0x1FCC, "M", "ηι"), + (0x1FCD, "3", " ̓̀"), + (0x1FCE, "3", " ̓́"), + (0x1FCF, "3", " ̓͂"), + (0x1FD0, "V"), + (0x1FD3, "M", "ΐ"), + (0x1FD4, "X"), + (0x1FD6, "V"), + (0x1FD8, "M", "ῐ"), + (0x1FD9, "M", "ῑ"), + (0x1FDA, "M", "ὶ"), + (0x1FDB, "M", "ί"), + (0x1FDC, "X"), + (0x1FDD, "3", " ̔̀"), + (0x1FDE, "3", " ̔́"), + (0x1FDF, "3", " ̔͂"), + (0x1FE0, "V"), + (0x1FE3, "M", "ΰ"), + (0x1FE4, "V"), + (0x1FE8, "M", "ῠ"), + (0x1FE9, "M", "ῡ"), + (0x1FEA, "M", "ὺ"), + (0x1FEB, "M", "ύ"), + (0x1FEC, "M", "ῥ"), + (0x1FED, "3", " ̈̀"), + (0x1FEE, "3", " ̈́"), + (0x1FEF, "3", "`"), + (0x1FF0, "X"), + (0x1FF2, "M", "ὼι"), + (0x1FF3, "M", "ωι"), + (0x1FF4, "M", "ώι"), + (0x1FF5, "X"), + (0x1FF6, "V"), + ] + + +def _seg_21() -> List[Union[Tuple[int, str], Tuple[int, str, str]]]: + return [ + (0x1FF7, "M", "ῶι"), + (0x1FF8, "M", "ὸ"), + (0x1FF9, "M", "ό"), + (0x1FFA, "M", "ὼ"), + (0x1FFB, "M", "ώ"), + (0x1FFC, "M", "ωι"), + (0x1FFD, "3", " ́"), + (0x1FFE, "3", " ̔"), + (0x1FFF, "X"), + (0x2000, "3", " "), + (0x200B, "I"), + (0x200C, "D", ""), + (0x200E, "X"), + (0x2010, "V"), + (0x2011, "M", "‐"), + (0x2012, "V"), + (0x2017, "3", " ̳"), + (0x2018, "V"), + (0x2024, "X"), + (0x2027, "V"), + (0x2028, "X"), + (0x202F, "3", " "), + (0x2030, "V"), + (0x2033, "M", "′′"), + (0x2034, "M", "′′′"), + (0x2035, "V"), + (0x2036, "M", "‵‵"), + (0x2037, "M", "‵‵‵"), + (0x2038, "V"), + (0x203C, "3", "!!"), + (0x203D, "V"), + (0x203E, "3", " ̅"), + (0x203F, "V"), + (0x2047, "3", "??"), + (0x2048, "3", "?!"), + (0x2049, "3", "!?"), + (0x204A, "V"), + (0x2057, "M", "′′′′"), + (0x2058, "V"), + (0x205F, "3", " "), + (0x2060, "I"), + (0x2061, "X"), + (0x2064, "I"), + (0x2065, "X"), + (0x2070, "M", "0"), + (0x2071, "M", "i"), + (0x2072, "X"), + (0x2074, "M", "4"), + (0x2075, "M", "5"), + (0x2076, "M", "6"), + (0x2077, "M", "7"), + (0x2078, "M", "8"), + (0x2079, "M", "9"), + (0x207A, "3", "+"), + (0x207B, "M", "−"), + (0x207C, "3", "="), + (0x207D, "3", "("), + (0x207E, "3", ")"), + (0x207F, "M", "n"), + (0x2080, "M", "0"), + (0x2081, "M", "1"), + (0x2082, "M", "2"), + (0x2083, "M", "3"), + (0x2084, "M", "4"), + (0x2085, "M", "5"), + (0x2086, "M", "6"), + (0x2087, "M", "7"), + (0x2088, "M", "8"), + (0x2089, "M", "9"), + (0x208A, "3", "+"), + (0x208B, "M", "−"), + (0x208C, "3", "="), + (0x208D, "3", "("), + (0x208E, "3", ")"), + (0x208F, "X"), + (0x2090, "M", "a"), + (0x2091, "M", "e"), + (0x2092, "M", "o"), + (0x2093, "M", "x"), + (0x2094, "M", "ə"), + (0x2095, "M", "h"), + (0x2096, "M", "k"), + (0x2097, "M", "l"), + (0x2098, "M", "m"), + (0x2099, "M", "n"), + (0x209A, "M", "p"), + (0x209B, "M", "s"), + (0x209C, "M", "t"), + (0x209D, "X"), + (0x20A0, "V"), + (0x20A8, "M", "rs"), + (0x20A9, "V"), + (0x20C1, "X"), + (0x20D0, "V"), + (0x20F1, "X"), + (0x2100, "3", "a/c"), + (0x2101, "3", "a/s"), + (0x2102, "M", "c"), + (0x2103, "M", "°c"), + (0x2104, "V"), + ] + + +def _seg_22() -> List[Union[Tuple[int, str], Tuple[int, str, str]]]: + return [ + (0x2105, "3", "c/o"), + (0x2106, "3", "c/u"), + (0x2107, "M", "ɛ"), + (0x2108, "V"), + (0x2109, "M", "°f"), + (0x210A, "M", "g"), + (0x210B, "M", "h"), + (0x210F, "M", "ħ"), + (0x2110, "M", "i"), + (0x2112, "M", "l"), + (0x2114, "V"), + (0x2115, "M", "n"), + (0x2116, "M", "no"), + (0x2117, "V"), + (0x2119, "M", "p"), + (0x211A, "M", "q"), + (0x211B, "M", "r"), + (0x211E, "V"), + (0x2120, "M", "sm"), + (0x2121, "M", "tel"), + (0x2122, "M", "tm"), + (0x2123, "V"), + (0x2124, "M", "z"), + (0x2125, "V"), + (0x2126, "M", "ω"), + (0x2127, "V"), + (0x2128, "M", "z"), + (0x2129, "V"), + (0x212A, "M", "k"), + (0x212B, "M", "å"), + (0x212C, "M", "b"), + (0x212D, "M", "c"), + (0x212E, "V"), + (0x212F, "M", "e"), + (0x2131, "M", "f"), + (0x2132, "X"), + (0x2133, "M", "m"), + (0x2134, "M", "o"), + (0x2135, "M", "א"), + (0x2136, "M", "ב"), + (0x2137, "M", "ג"), + (0x2138, "M", "ד"), + (0x2139, "M", "i"), + (0x213A, "V"), + (0x213B, "M", "fax"), + (0x213C, "M", "π"), + (0x213D, "M", "γ"), + (0x213F, "M", "π"), + (0x2140, "M", "∑"), + (0x2141, "V"), + (0x2145, "M", "d"), + (0x2147, "M", "e"), + (0x2148, "M", "i"), + (0x2149, "M", "j"), + (0x214A, "V"), + (0x2150, "M", "1⁄7"), + (0x2151, "M", "1⁄9"), + (0x2152, "M", "1⁄10"), + (0x2153, "M", "1⁄3"), + (0x2154, "M", "2⁄3"), + (0x2155, "M", "1⁄5"), + (0x2156, "M", "2⁄5"), + (0x2157, "M", "3⁄5"), + (0x2158, "M", "4⁄5"), + (0x2159, "M", "1⁄6"), + (0x215A, "M", "5⁄6"), + (0x215B, "M", "1⁄8"), + (0x215C, "M", "3⁄8"), + (0x215D, "M", "5⁄8"), + (0x215E, "M", "7⁄8"), + (0x215F, "M", "1⁄"), + (0x2160, "M", "i"), + (0x2161, "M", "ii"), + (0x2162, "M", "iii"), + (0x2163, "M", "iv"), + (0x2164, "M", "v"), + (0x2165, "M", "vi"), + (0x2166, "M", "vii"), + (0x2167, "M", "viii"), + (0x2168, "M", "ix"), + (0x2169, "M", "x"), + (0x216A, "M", "xi"), + (0x216B, "M", "xii"), + (0x216C, "M", "l"), + (0x216D, "M", "c"), + (0x216E, "M", "d"), + (0x216F, "M", "m"), + (0x2170, "M", "i"), + (0x2171, "M", "ii"), + (0x2172, "M", "iii"), + (0x2173, "M", "iv"), + (0x2174, "M", "v"), + (0x2175, "M", "vi"), + (0x2176, "M", "vii"), + (0x2177, "M", "viii"), + (0x2178, "M", "ix"), + (0x2179, "M", "x"), + (0x217A, "M", "xi"), + (0x217B, "M", "xii"), + (0x217C, "M", "l"), + ] + + +def _seg_23() -> List[Union[Tuple[int, str], Tuple[int, str, str]]]: + return [ + (0x217D, "M", "c"), + (0x217E, "M", "d"), + (0x217F, "M", "m"), + (0x2180, "V"), + (0x2183, "X"), + (0x2184, "V"), + (0x2189, "M", "0⁄3"), + (0x218A, "V"), + (0x218C, "X"), + (0x2190, "V"), + (0x222C, "M", "∫∫"), + (0x222D, "M", "∫∫∫"), + (0x222E, "V"), + (0x222F, "M", "∮∮"), + (0x2230, "M", "∮∮∮"), + (0x2231, "V"), + (0x2329, "M", "〈"), + (0x232A, "M", "〉"), + (0x232B, "V"), + (0x2427, "X"), + (0x2440, "V"), + (0x244B, "X"), + (0x2460, "M", "1"), + (0x2461, "M", "2"), + (0x2462, "M", "3"), + (0x2463, "M", "4"), + (0x2464, "M", "5"), + (0x2465, "M", "6"), + (0x2466, "M", "7"), + (0x2467, "M", "8"), + (0x2468, "M", "9"), + (0x2469, "M", "10"), + (0x246A, "M", "11"), + (0x246B, "M", "12"), + (0x246C, "M", "13"), + (0x246D, "M", "14"), + (0x246E, "M", "15"), + (0x246F, "M", "16"), + (0x2470, "M", "17"), + (0x2471, "M", "18"), + (0x2472, "M", "19"), + (0x2473, "M", "20"), + (0x2474, "3", "(1)"), + (0x2475, "3", "(2)"), + (0x2476, "3", "(3)"), + (0x2477, "3", "(4)"), + (0x2478, "3", "(5)"), + (0x2479, "3", "(6)"), + (0x247A, "3", "(7)"), + (0x247B, "3", "(8)"), + (0x247C, "3", "(9)"), + (0x247D, "3", "(10)"), + (0x247E, "3", "(11)"), + (0x247F, "3", "(12)"), + (0x2480, "3", "(13)"), + (0x2481, "3", "(14)"), + (0x2482, "3", "(15)"), + (0x2483, "3", "(16)"), + (0x2484, "3", "(17)"), + (0x2485, "3", "(18)"), + (0x2486, "3", "(19)"), + (0x2487, "3", "(20)"), + (0x2488, "X"), + (0x249C, "3", "(a)"), + (0x249D, "3", "(b)"), + (0x249E, "3", "(c)"), + (0x249F, "3", "(d)"), + (0x24A0, "3", "(e)"), + (0x24A1, "3", "(f)"), + (0x24A2, "3", "(g)"), + (0x24A3, "3", "(h)"), + (0x24A4, "3", "(i)"), + (0x24A5, "3", "(j)"), + (0x24A6, "3", "(k)"), + (0x24A7, "3", "(l)"), + (0x24A8, "3", "(m)"), + (0x24A9, "3", "(n)"), + (0x24AA, "3", "(o)"), + (0x24AB, "3", "(p)"), + (0x24AC, "3", "(q)"), + (0x24AD, "3", "(r)"), + (0x24AE, "3", "(s)"), + (0x24AF, "3", "(t)"), + (0x24B0, "3", "(u)"), + (0x24B1, "3", "(v)"), + (0x24B2, "3", "(w)"), + (0x24B3, "3", "(x)"), + (0x24B4, "3", "(y)"), + (0x24B5, "3", "(z)"), + (0x24B6, "M", "a"), + (0x24B7, "M", "b"), + (0x24B8, "M", "c"), + (0x24B9, "M", "d"), + (0x24BA, "M", "e"), + (0x24BB, "M", "f"), + (0x24BC, "M", "g"), + (0x24BD, "M", "h"), + (0x24BE, "M", "i"), + (0x24BF, "M", "j"), + (0x24C0, "M", "k"), + ] + + +def _seg_24() -> List[Union[Tuple[int, str], Tuple[int, str, str]]]: + return [ + (0x24C1, "M", "l"), + (0x24C2, "M", "m"), + (0x24C3, "M", "n"), + (0x24C4, "M", "o"), + (0x24C5, "M", "p"), + (0x24C6, "M", "q"), + (0x24C7, "M", "r"), + (0x24C8, "M", "s"), + (0x24C9, "M", "t"), + (0x24CA, "M", "u"), + (0x24CB, "M", "v"), + (0x24CC, "M", "w"), + (0x24CD, "M", "x"), + (0x24CE, "M", "y"), + (0x24CF, "M", "z"), + (0x24D0, "M", "a"), + (0x24D1, "M", "b"), + (0x24D2, "M", "c"), + (0x24D3, "M", "d"), + (0x24D4, "M", "e"), + (0x24D5, "M", "f"), + (0x24D6, "M", "g"), + (0x24D7, "M", "h"), + (0x24D8, "M", "i"), + (0x24D9, "M", "j"), + (0x24DA, "M", "k"), + (0x24DB, "M", "l"), + (0x24DC, "M", "m"), + (0x24DD, "M", "n"), + (0x24DE, "M", "o"), + (0x24DF, "M", "p"), + (0x24E0, "M", "q"), + (0x24E1, "M", "r"), + (0x24E2, "M", "s"), + (0x24E3, "M", "t"), + (0x24E4, "M", "u"), + (0x24E5, "M", "v"), + (0x24E6, "M", "w"), + (0x24E7, "M", "x"), + (0x24E8, "M", "y"), + (0x24E9, "M", "z"), + (0x24EA, "M", "0"), + (0x24EB, "V"), + (0x2A0C, "M", "∫∫∫∫"), + (0x2A0D, "V"), + (0x2A74, "3", "::="), + (0x2A75, "3", "=="), + (0x2A76, "3", "==="), + (0x2A77, "V"), + (0x2ADC, "M", "⫝̸"), + (0x2ADD, "V"), + (0x2B74, "X"), + (0x2B76, "V"), + (0x2B96, "X"), + (0x2B97, "V"), + (0x2C00, "M", "ⰰ"), + (0x2C01, "M", "ⰱ"), + (0x2C02, "M", "ⰲ"), + (0x2C03, "M", "ⰳ"), + (0x2C04, "M", "ⰴ"), + (0x2C05, "M", "ⰵ"), + (0x2C06, "M", "ⰶ"), + (0x2C07, "M", "ⰷ"), + (0x2C08, "M", "ⰸ"), + (0x2C09, "M", "ⰹ"), + (0x2C0A, "M", "ⰺ"), + (0x2C0B, "M", "ⰻ"), + (0x2C0C, "M", "ⰼ"), + (0x2C0D, "M", "ⰽ"), + (0x2C0E, "M", "ⰾ"), + (0x2C0F, "M", "ⰿ"), + (0x2C10, "M", "ⱀ"), + (0x2C11, "M", "ⱁ"), + (0x2C12, "M", "ⱂ"), + (0x2C13, "M", "ⱃ"), + (0x2C14, "M", "ⱄ"), + (0x2C15, "M", "ⱅ"), + (0x2C16, "M", "ⱆ"), + (0x2C17, "M", "ⱇ"), + (0x2C18, "M", "ⱈ"), + (0x2C19, "M", "ⱉ"), + (0x2C1A, "M", "ⱊ"), + (0x2C1B, "M", "ⱋ"), + (0x2C1C, "M", "ⱌ"), + (0x2C1D, "M", "ⱍ"), + (0x2C1E, "M", "ⱎ"), + (0x2C1F, "M", "ⱏ"), + (0x2C20, "M", "ⱐ"), + (0x2C21, "M", "ⱑ"), + (0x2C22, "M", "ⱒ"), + (0x2C23, "M", "ⱓ"), + (0x2C24, "M", "ⱔ"), + (0x2C25, "M", "ⱕ"), + (0x2C26, "M", "ⱖ"), + (0x2C27, "M", "ⱗ"), + (0x2C28, "M", "ⱘ"), + (0x2C29, "M", "ⱙ"), + (0x2C2A, "M", "ⱚ"), + (0x2C2B, "M", "ⱛ"), + (0x2C2C, "M", "ⱜ"), + ] + + +def _seg_25() -> List[Union[Tuple[int, str], Tuple[int, str, str]]]: + return [ + (0x2C2D, "M", "ⱝ"), + (0x2C2E, "M", "ⱞ"), + (0x2C2F, "M", "ⱟ"), + (0x2C30, "V"), + (0x2C60, "M", "ⱡ"), + (0x2C61, "V"), + (0x2C62, "M", "ɫ"), + (0x2C63, "M", "ᵽ"), + (0x2C64, "M", "ɽ"), + (0x2C65, "V"), + (0x2C67, "M", "ⱨ"), + (0x2C68, "V"), + (0x2C69, "M", "ⱪ"), + (0x2C6A, "V"), + (0x2C6B, "M", "ⱬ"), + (0x2C6C, "V"), + (0x2C6D, "M", "ɑ"), + (0x2C6E, "M", "ɱ"), + (0x2C6F, "M", "ɐ"), + (0x2C70, "M", "ɒ"), + (0x2C71, "V"), + (0x2C72, "M", "ⱳ"), + (0x2C73, "V"), + (0x2C75, "M", "ⱶ"), + (0x2C76, "V"), + (0x2C7C, "M", "j"), + (0x2C7D, "M", "v"), + (0x2C7E, "M", "ȿ"), + (0x2C7F, "M", "ɀ"), + (0x2C80, "M", "ⲁ"), + (0x2C81, "V"), + (0x2C82, "M", "ⲃ"), + (0x2C83, "V"), + (0x2C84, "M", "ⲅ"), + (0x2C85, "V"), + (0x2C86, "M", "ⲇ"), + (0x2C87, "V"), + (0x2C88, "M", "ⲉ"), + (0x2C89, "V"), + (0x2C8A, "M", "ⲋ"), + (0x2C8B, "V"), + (0x2C8C, "M", "ⲍ"), + (0x2C8D, "V"), + (0x2C8E, "M", "ⲏ"), + (0x2C8F, "V"), + (0x2C90, "M", "ⲑ"), + (0x2C91, "V"), + (0x2C92, "M", "ⲓ"), + (0x2C93, "V"), + (0x2C94, "M", "ⲕ"), + (0x2C95, "V"), + (0x2C96, "M", "ⲗ"), + (0x2C97, "V"), + (0x2C98, "M", "ⲙ"), + (0x2C99, "V"), + (0x2C9A, "M", "ⲛ"), + (0x2C9B, "V"), + (0x2C9C, "M", "ⲝ"), + (0x2C9D, "V"), + (0x2C9E, "M", "ⲟ"), + (0x2C9F, "V"), + (0x2CA0, "M", "ⲡ"), + (0x2CA1, "V"), + (0x2CA2, "M", "ⲣ"), + (0x2CA3, "V"), + (0x2CA4, "M", "ⲥ"), + (0x2CA5, "V"), + (0x2CA6, "M", "ⲧ"), + (0x2CA7, "V"), + (0x2CA8, "M", "ⲩ"), + (0x2CA9, "V"), + (0x2CAA, "M", "ⲫ"), + (0x2CAB, "V"), + (0x2CAC, "M", "ⲭ"), + (0x2CAD, "V"), + (0x2CAE, "M", "ⲯ"), + (0x2CAF, "V"), + (0x2CB0, "M", "ⲱ"), + (0x2CB1, "V"), + (0x2CB2, "M", "ⲳ"), + (0x2CB3, "V"), + (0x2CB4, "M", "ⲵ"), + (0x2CB5, "V"), + (0x2CB6, "M", "ⲷ"), + (0x2CB7, "V"), + (0x2CB8, "M", "ⲹ"), + (0x2CB9, "V"), + (0x2CBA, "M", "ⲻ"), + (0x2CBB, "V"), + (0x2CBC, "M", "ⲽ"), + (0x2CBD, "V"), + (0x2CBE, "M", "ⲿ"), + (0x2CBF, "V"), + (0x2CC0, "M", "ⳁ"), + (0x2CC1, "V"), + (0x2CC2, "M", "ⳃ"), + (0x2CC3, "V"), + (0x2CC4, "M", "ⳅ"), + (0x2CC5, "V"), + (0x2CC6, "M", "ⳇ"), + ] + + +def _seg_26() -> List[Union[Tuple[int, str], Tuple[int, str, str]]]: + return [ + (0x2CC7, "V"), + (0x2CC8, "M", "ⳉ"), + (0x2CC9, "V"), + (0x2CCA, "M", "ⳋ"), + (0x2CCB, "V"), + (0x2CCC, "M", "ⳍ"), + (0x2CCD, "V"), + (0x2CCE, "M", "ⳏ"), + (0x2CCF, "V"), + (0x2CD0, "M", "ⳑ"), + (0x2CD1, "V"), + (0x2CD2, "M", "ⳓ"), + (0x2CD3, "V"), + (0x2CD4, "M", "ⳕ"), + (0x2CD5, "V"), + (0x2CD6, "M", "ⳗ"), + (0x2CD7, "V"), + (0x2CD8, "M", "ⳙ"), + (0x2CD9, "V"), + (0x2CDA, "M", "ⳛ"), + (0x2CDB, "V"), + (0x2CDC, "M", "ⳝ"), + (0x2CDD, "V"), + (0x2CDE, "M", "ⳟ"), + (0x2CDF, "V"), + (0x2CE0, "M", "ⳡ"), + (0x2CE1, "V"), + (0x2CE2, "M", "ⳣ"), + (0x2CE3, "V"), + (0x2CEB, "M", "ⳬ"), + (0x2CEC, "V"), + (0x2CED, "M", "ⳮ"), + (0x2CEE, "V"), + (0x2CF2, "M", "ⳳ"), + (0x2CF3, "V"), + (0x2CF4, "X"), + (0x2CF9, "V"), + (0x2D26, "X"), + (0x2D27, "V"), + (0x2D28, "X"), + (0x2D2D, "V"), + (0x2D2E, "X"), + (0x2D30, "V"), + (0x2D68, "X"), + (0x2D6F, "M", "ⵡ"), + (0x2D70, "V"), + (0x2D71, "X"), + (0x2D7F, "V"), + (0x2D97, "X"), + (0x2DA0, "V"), + (0x2DA7, "X"), + (0x2DA8, "V"), + (0x2DAF, "X"), + (0x2DB0, "V"), + (0x2DB7, "X"), + (0x2DB8, "V"), + (0x2DBF, "X"), + (0x2DC0, "V"), + (0x2DC7, "X"), + (0x2DC8, "V"), + (0x2DCF, "X"), + (0x2DD0, "V"), + (0x2DD7, "X"), + (0x2DD8, "V"), + (0x2DDF, "X"), + (0x2DE0, "V"), + (0x2E5E, "X"), + (0x2E80, "V"), + (0x2E9A, "X"), + (0x2E9B, "V"), + (0x2E9F, "M", "母"), + (0x2EA0, "V"), + (0x2EF3, "M", "龟"), + (0x2EF4, "X"), + (0x2F00, "M", "一"), + (0x2F01, "M", "丨"), + (0x2F02, "M", "丶"), + (0x2F03, "M", "丿"), + (0x2F04, "M", "乙"), + (0x2F05, "M", "亅"), + (0x2F06, "M", "二"), + (0x2F07, "M", "亠"), + (0x2F08, "M", "人"), + (0x2F09, "M", "儿"), + (0x2F0A, "M", "入"), + (0x2F0B, "M", "八"), + (0x2F0C, "M", "冂"), + (0x2F0D, "M", "冖"), + (0x2F0E, "M", "冫"), + (0x2F0F, "M", "几"), + (0x2F10, "M", "凵"), + (0x2F11, "M", "刀"), + (0x2F12, "M", "力"), + (0x2F13, "M", "勹"), + (0x2F14, "M", "匕"), + (0x2F15, "M", "匚"), + (0x2F16, "M", "匸"), + (0x2F17, "M", "十"), + (0x2F18, "M", "卜"), + (0x2F19, "M", "卩"), + ] + + +def _seg_27() -> List[Union[Tuple[int, str], Tuple[int, str, str]]]: + return [ + (0x2F1A, "M", "厂"), + (0x2F1B, "M", "厶"), + (0x2F1C, "M", "又"), + (0x2F1D, "M", "口"), + (0x2F1E, "M", "囗"), + (0x2F1F, "M", "土"), + (0x2F20, "M", "士"), + (0x2F21, "M", "夂"), + (0x2F22, "M", "夊"), + (0x2F23, "M", "夕"), + (0x2F24, "M", "大"), + (0x2F25, "M", "女"), + (0x2F26, "M", "子"), + (0x2F27, "M", "宀"), + (0x2F28, "M", "寸"), + (0x2F29, "M", "小"), + (0x2F2A, "M", "尢"), + (0x2F2B, "M", "尸"), + (0x2F2C, "M", "屮"), + (0x2F2D, "M", "山"), + (0x2F2E, "M", "巛"), + (0x2F2F, "M", "工"), + (0x2F30, "M", "己"), + (0x2F31, "M", "巾"), + (0x2F32, "M", "干"), + (0x2F33, "M", "幺"), + (0x2F34, "M", "广"), + (0x2F35, "M", "廴"), + (0x2F36, "M", "廾"), + (0x2F37, "M", "弋"), + (0x2F38, "M", "弓"), + (0x2F39, "M", "彐"), + (0x2F3A, "M", "彡"), + (0x2F3B, "M", "彳"), + (0x2F3C, "M", "心"), + (0x2F3D, "M", "戈"), + (0x2F3E, "M", "戶"), + (0x2F3F, "M", "手"), + (0x2F40, "M", "支"), + (0x2F41, "M", "攴"), + (0x2F42, "M", "文"), + (0x2F43, "M", "斗"), + (0x2F44, "M", "斤"), + (0x2F45, "M", "方"), + (0x2F46, "M", "无"), + (0x2F47, "M", "日"), + (0x2F48, "M", "曰"), + (0x2F49, "M", "月"), + (0x2F4A, "M", "木"), + (0x2F4B, "M", "欠"), + (0x2F4C, "M", "止"), + (0x2F4D, "M", "歹"), + (0x2F4E, "M", "殳"), + (0x2F4F, "M", "毋"), + (0x2F50, "M", "比"), + (0x2F51, "M", "毛"), + (0x2F52, "M", "氏"), + (0x2F53, "M", "气"), + (0x2F54, "M", "水"), + (0x2F55, "M", "火"), + (0x2F56, "M", "爪"), + (0x2F57, "M", "父"), + (0x2F58, "M", "爻"), + (0x2F59, "M", "爿"), + (0x2F5A, "M", "片"), + (0x2F5B, "M", "牙"), + (0x2F5C, "M", "牛"), + (0x2F5D, "M", "犬"), + (0x2F5E, "M", "玄"), + (0x2F5F, "M", "玉"), + (0x2F60, "M", "瓜"), + (0x2F61, "M", "瓦"), + (0x2F62, "M", "甘"), + (0x2F63, "M", "生"), + (0x2F64, "M", "用"), + (0x2F65, "M", "田"), + (0x2F66, "M", "疋"), + (0x2F67, "M", "疒"), + (0x2F68, "M", "癶"), + (0x2F69, "M", "白"), + (0x2F6A, "M", "皮"), + (0x2F6B, "M", "皿"), + (0x2F6C, "M", "目"), + (0x2F6D, "M", "矛"), + (0x2F6E, "M", "矢"), + (0x2F6F, "M", "石"), + (0x2F70, "M", "示"), + (0x2F71, "M", "禸"), + (0x2F72, "M", "禾"), + (0x2F73, "M", "穴"), + (0x2F74, "M", "立"), + (0x2F75, "M", "竹"), + (0x2F76, "M", "米"), + (0x2F77, "M", "糸"), + (0x2F78, "M", "缶"), + (0x2F79, "M", "网"), + (0x2F7A, "M", "羊"), + (0x2F7B, "M", "羽"), + (0x2F7C, "M", "老"), + (0x2F7D, "M", "而"), + ] + + +def _seg_28() -> List[Union[Tuple[int, str], Tuple[int, str, str]]]: + return [ + (0x2F7E, "M", "耒"), + (0x2F7F, "M", "耳"), + (0x2F80, "M", "聿"), + (0x2F81, "M", "肉"), + (0x2F82, "M", "臣"), + (0x2F83, "M", "自"), + (0x2F84, "M", "至"), + (0x2F85, "M", "臼"), + (0x2F86, "M", "舌"), + (0x2F87, "M", "舛"), + (0x2F88, "M", "舟"), + (0x2F89, "M", "艮"), + (0x2F8A, "M", "色"), + (0x2F8B, "M", "艸"), + (0x2F8C, "M", "虍"), + (0x2F8D, "M", "虫"), + (0x2F8E, "M", "血"), + (0x2F8F, "M", "行"), + (0x2F90, "M", "衣"), + (0x2F91, "M", "襾"), + (0x2F92, "M", "見"), + (0x2F93, "M", "角"), + (0x2F94, "M", "言"), + (0x2F95, "M", "谷"), + (0x2F96, "M", "豆"), + (0x2F97, "M", "豕"), + (0x2F98, "M", "豸"), + (0x2F99, "M", "貝"), + (0x2F9A, "M", "赤"), + (0x2F9B, "M", "走"), + (0x2F9C, "M", "足"), + (0x2F9D, "M", "身"), + (0x2F9E, "M", "車"), + (0x2F9F, "M", "辛"), + (0x2FA0, "M", "辰"), + (0x2FA1, "M", "辵"), + (0x2FA2, "M", "邑"), + (0x2FA3, "M", "酉"), + (0x2FA4, "M", "釆"), + (0x2FA5, "M", "里"), + (0x2FA6, "M", "金"), + (0x2FA7, "M", "長"), + (0x2FA8, "M", "門"), + (0x2FA9, "M", "阜"), + (0x2FAA, "M", "隶"), + (0x2FAB, "M", "隹"), + (0x2FAC, "M", "雨"), + (0x2FAD, "M", "靑"), + (0x2FAE, "M", "非"), + (0x2FAF, "M", "面"), + (0x2FB0, "M", "革"), + (0x2FB1, "M", "韋"), + (0x2FB2, "M", "韭"), + (0x2FB3, "M", "音"), + (0x2FB4, "M", "頁"), + (0x2FB5, "M", "風"), + (0x2FB6, "M", "飛"), + (0x2FB7, "M", "食"), + (0x2FB8, "M", "首"), + (0x2FB9, "M", "香"), + (0x2FBA, "M", "馬"), + (0x2FBB, "M", "骨"), + (0x2FBC, "M", "高"), + (0x2FBD, "M", "髟"), + (0x2FBE, "M", "鬥"), + (0x2FBF, "M", "鬯"), + (0x2FC0, "M", "鬲"), + (0x2FC1, "M", "鬼"), + (0x2FC2, "M", "魚"), + (0x2FC3, "M", "鳥"), + (0x2FC4, "M", "鹵"), + (0x2FC5, "M", "鹿"), + (0x2FC6, "M", "麥"), + (0x2FC7, "M", "麻"), + (0x2FC8, "M", "黃"), + (0x2FC9, "M", "黍"), + (0x2FCA, "M", "黑"), + (0x2FCB, "M", "黹"), + (0x2FCC, "M", "黽"), + (0x2FCD, "M", "鼎"), + (0x2FCE, "M", "鼓"), + (0x2FCF, "M", "鼠"), + (0x2FD0, "M", "鼻"), + (0x2FD1, "M", "齊"), + (0x2FD2, "M", "齒"), + (0x2FD3, "M", "龍"), + (0x2FD4, "M", "龜"), + (0x2FD5, "M", "龠"), + (0x2FD6, "X"), + (0x3000, "3", " "), + (0x3001, "V"), + (0x3002, "M", "."), + (0x3003, "V"), + (0x3036, "M", "〒"), + (0x3037, "V"), + (0x3038, "M", "十"), + (0x3039, "M", "卄"), + (0x303A, "M", "卅"), + (0x303B, "V"), + (0x3040, "X"), + ] + + +def _seg_29() -> List[Union[Tuple[int, str], Tuple[int, str, str]]]: + return [ + (0x3041, "V"), + (0x3097, "X"), + (0x3099, "V"), + (0x309B, "3", " ゙"), + (0x309C, "3", " ゚"), + (0x309D, "V"), + (0x309F, "M", "より"), + (0x30A0, "V"), + (0x30FF, "M", "コト"), + (0x3100, "X"), + (0x3105, "V"), + (0x3130, "X"), + (0x3131, "M", "ᄀ"), + (0x3132, "M", "ᄁ"), + (0x3133, "M", "ᆪ"), + (0x3134, "M", "ᄂ"), + (0x3135, "M", "ᆬ"), + (0x3136, "M", "ᆭ"), + (0x3137, "M", "ᄃ"), + (0x3138, "M", "ᄄ"), + (0x3139, "M", "ᄅ"), + (0x313A, "M", "ᆰ"), + (0x313B, "M", "ᆱ"), + (0x313C, "M", "ᆲ"), + (0x313D, "M", "ᆳ"), + (0x313E, "M", "ᆴ"), + (0x313F, "M", "ᆵ"), + (0x3140, "M", "ᄚ"), + (0x3141, "M", "ᄆ"), + (0x3142, "M", "ᄇ"), + (0x3143, "M", "ᄈ"), + (0x3144, "M", "ᄡ"), + (0x3145, "M", "ᄉ"), + (0x3146, "M", "ᄊ"), + (0x3147, "M", "ᄋ"), + (0x3148, "M", "ᄌ"), + (0x3149, "M", "ᄍ"), + (0x314A, "M", "ᄎ"), + (0x314B, "M", "ᄏ"), + (0x314C, "M", "ᄐ"), + (0x314D, "M", "ᄑ"), + (0x314E, "M", "ᄒ"), + (0x314F, "M", "ᅡ"), + (0x3150, "M", "ᅢ"), + (0x3151, "M", "ᅣ"), + (0x3152, "M", "ᅤ"), + (0x3153, "M", "ᅥ"), + (0x3154, "M", "ᅦ"), + (0x3155, "M", "ᅧ"), + (0x3156, "M", "ᅨ"), + (0x3157, "M", "ᅩ"), + (0x3158, "M", "ᅪ"), + (0x3159, "M", "ᅫ"), + (0x315A, "M", "ᅬ"), + (0x315B, "M", "ᅭ"), + (0x315C, "M", "ᅮ"), + (0x315D, "M", "ᅯ"), + (0x315E, "M", "ᅰ"), + (0x315F, "M", "ᅱ"), + (0x3160, "M", "ᅲ"), + (0x3161, "M", "ᅳ"), + (0x3162, "M", "ᅴ"), + (0x3163, "M", "ᅵ"), + (0x3164, "X"), + (0x3165, "M", "ᄔ"), + (0x3166, "M", "ᄕ"), + (0x3167, "M", "ᇇ"), + (0x3168, "M", "ᇈ"), + (0x3169, "M", "ᇌ"), + (0x316A, "M", "ᇎ"), + (0x316B, "M", "ᇓ"), + (0x316C, "M", "ᇗ"), + (0x316D, "M", "ᇙ"), + (0x316E, "M", "ᄜ"), + (0x316F, "M", "ᇝ"), + (0x3170, "M", "ᇟ"), + (0x3171, "M", "ᄝ"), + (0x3172, "M", "ᄞ"), + (0x3173, "M", "ᄠ"), + (0x3174, "M", "ᄢ"), + (0x3175, "M", "ᄣ"), + (0x3176, "M", "ᄧ"), + (0x3177, "M", "ᄩ"), + (0x3178, "M", "ᄫ"), + (0x3179, "M", "ᄬ"), + (0x317A, "M", "ᄭ"), + (0x317B, "M", "ᄮ"), + (0x317C, "M", "ᄯ"), + (0x317D, "M", "ᄲ"), + (0x317E, "M", "ᄶ"), + (0x317F, "M", "ᅀ"), + (0x3180, "M", "ᅇ"), + (0x3181, "M", "ᅌ"), + (0x3182, "M", "ᇱ"), + (0x3183, "M", "ᇲ"), + (0x3184, "M", "ᅗ"), + (0x3185, "M", "ᅘ"), + (0x3186, "M", "ᅙ"), + (0x3187, "M", "ᆄ"), + (0x3188, "M", "ᆅ"), + ] + + +def _seg_30() -> List[Union[Tuple[int, str], Tuple[int, str, str]]]: + return [ + (0x3189, "M", "ᆈ"), + (0x318A, "M", "ᆑ"), + (0x318B, "M", "ᆒ"), + (0x318C, "M", "ᆔ"), + (0x318D, "M", "ᆞ"), + (0x318E, "M", "ᆡ"), + (0x318F, "X"), + (0x3190, "V"), + (0x3192, "M", "一"), + (0x3193, "M", "二"), + (0x3194, "M", "三"), + (0x3195, "M", "四"), + (0x3196, "M", "上"), + (0x3197, "M", "中"), + (0x3198, "M", "下"), + (0x3199, "M", "甲"), + (0x319A, "M", "乙"), + (0x319B, "M", "丙"), + (0x319C, "M", "丁"), + (0x319D, "M", "天"), + (0x319E, "M", "地"), + (0x319F, "M", "人"), + (0x31A0, "V"), + (0x31E4, "X"), + (0x31F0, "V"), + (0x3200, "3", "(ᄀ)"), + (0x3201, "3", "(ᄂ)"), + (0x3202, "3", "(ᄃ)"), + (0x3203, "3", "(ᄅ)"), + (0x3204, "3", "(ᄆ)"), + (0x3205, "3", "(ᄇ)"), + (0x3206, "3", "(ᄉ)"), + (0x3207, "3", "(ᄋ)"), + (0x3208, "3", "(ᄌ)"), + (0x3209, "3", "(ᄎ)"), + (0x320A, "3", "(ᄏ)"), + (0x320B, "3", "(ᄐ)"), + (0x320C, "3", "(ᄑ)"), + (0x320D, "3", "(ᄒ)"), + (0x320E, "3", "(가)"), + (0x320F, "3", "(나)"), + (0x3210, "3", "(다)"), + (0x3211, "3", "(라)"), + (0x3212, "3", "(마)"), + (0x3213, "3", "(바)"), + (0x3214, "3", "(사)"), + (0x3215, "3", "(아)"), + (0x3216, "3", "(자)"), + (0x3217, "3", "(차)"), + (0x3218, "3", "(카)"), + (0x3219, "3", "(타)"), + (0x321A, "3", "(파)"), + (0x321B, "3", "(하)"), + (0x321C, "3", "(주)"), + (0x321D, "3", "(오전)"), + (0x321E, "3", "(오후)"), + (0x321F, "X"), + (0x3220, "3", "(一)"), + (0x3221, "3", "(二)"), + (0x3222, "3", "(三)"), + (0x3223, "3", "(四)"), + (0x3224, "3", "(五)"), + (0x3225, "3", "(六)"), + (0x3226, "3", "(七)"), + (0x3227, "3", "(八)"), + (0x3228, "3", "(九)"), + (0x3229, "3", "(十)"), + (0x322A, "3", "(月)"), + (0x322B, "3", "(火)"), + (0x322C, "3", "(水)"), + (0x322D, "3", "(木)"), + (0x322E, "3", "(金)"), + (0x322F, "3", "(土)"), + (0x3230, "3", "(日)"), + (0x3231, "3", "(株)"), + (0x3232, "3", "(有)"), + (0x3233, "3", "(社)"), + (0x3234, "3", "(名)"), + (0x3235, "3", "(特)"), + (0x3236, "3", "(財)"), + (0x3237, "3", "(祝)"), + (0x3238, "3", "(労)"), + (0x3239, "3", "(代)"), + (0x323A, "3", "(呼)"), + (0x323B, "3", "(学)"), + (0x323C, "3", "(監)"), + (0x323D, "3", "(企)"), + (0x323E, "3", "(資)"), + (0x323F, "3", "(協)"), + (0x3240, "3", "(祭)"), + (0x3241, "3", "(休)"), + (0x3242, "3", "(自)"), + (0x3243, "3", "(至)"), + (0x3244, "M", "問"), + (0x3245, "M", "幼"), + (0x3246, "M", "文"), + (0x3247, "M", "箏"), + (0x3248, "V"), + (0x3250, "M", "pte"), + (0x3251, "M", "21"), + ] + + +def _seg_31() -> List[Union[Tuple[int, str], Tuple[int, str, str]]]: + return [ + (0x3252, "M", "22"), + (0x3253, "M", "23"), + (0x3254, "M", "24"), + (0x3255, "M", "25"), + (0x3256, "M", "26"), + (0x3257, "M", "27"), + (0x3258, "M", "28"), + (0x3259, "M", "29"), + (0x325A, "M", "30"), + (0x325B, "M", "31"), + (0x325C, "M", "32"), + (0x325D, "M", "33"), + (0x325E, "M", "34"), + (0x325F, "M", "35"), + (0x3260, "M", "ᄀ"), + (0x3261, "M", "ᄂ"), + (0x3262, "M", "ᄃ"), + (0x3263, "M", "ᄅ"), + (0x3264, "M", "ᄆ"), + (0x3265, "M", "ᄇ"), + (0x3266, "M", "ᄉ"), + (0x3267, "M", "ᄋ"), + (0x3268, "M", "ᄌ"), + (0x3269, "M", "ᄎ"), + (0x326A, "M", "ᄏ"), + (0x326B, "M", "ᄐ"), + (0x326C, "M", "ᄑ"), + (0x326D, "M", "ᄒ"), + (0x326E, "M", "가"), + (0x326F, "M", "나"), + (0x3270, "M", "다"), + (0x3271, "M", "라"), + (0x3272, "M", "마"), + (0x3273, "M", "바"), + (0x3274, "M", "사"), + (0x3275, "M", "아"), + (0x3276, "M", "자"), + (0x3277, "M", "차"), + (0x3278, "M", "카"), + (0x3279, "M", "타"), + (0x327A, "M", "파"), + (0x327B, "M", "하"), + (0x327C, "M", "참고"), + (0x327D, "M", "주의"), + (0x327E, "M", "우"), + (0x327F, "V"), + (0x3280, "M", "一"), + (0x3281, "M", "二"), + (0x3282, "M", "三"), + (0x3283, "M", "四"), + (0x3284, "M", "五"), + (0x3285, "M", "六"), + (0x3286, "M", "七"), + (0x3287, "M", "八"), + (0x3288, "M", "九"), + (0x3289, "M", "十"), + (0x328A, "M", "月"), + (0x328B, "M", "火"), + (0x328C, "M", "水"), + (0x328D, "M", "木"), + (0x328E, "M", "金"), + (0x328F, "M", "土"), + (0x3290, "M", "日"), + (0x3291, "M", "株"), + (0x3292, "M", "有"), + (0x3293, "M", "社"), + (0x3294, "M", "名"), + (0x3295, "M", "特"), + (0x3296, "M", "財"), + (0x3297, "M", "祝"), + (0x3298, "M", "労"), + (0x3299, "M", "秘"), + (0x329A, "M", "男"), + (0x329B, "M", "女"), + (0x329C, "M", "適"), + (0x329D, "M", "優"), + (0x329E, "M", "印"), + (0x329F, "M", "注"), + (0x32A0, "M", "項"), + (0x32A1, "M", "休"), + (0x32A2, "M", "写"), + (0x32A3, "M", "正"), + (0x32A4, "M", "上"), + (0x32A5, "M", "中"), + (0x32A6, "M", "下"), + (0x32A7, "M", "左"), + (0x32A8, "M", "右"), + (0x32A9, "M", "医"), + (0x32AA, "M", "宗"), + (0x32AB, "M", "学"), + (0x32AC, "M", "監"), + (0x32AD, "M", "企"), + (0x32AE, "M", "資"), + (0x32AF, "M", "協"), + (0x32B0, "M", "夜"), + (0x32B1, "M", "36"), + (0x32B2, "M", "37"), + (0x32B3, "M", "38"), + (0x32B4, "M", "39"), + (0x32B5, "M", "40"), + ] + + +def _seg_32() -> List[Union[Tuple[int, str], Tuple[int, str, str]]]: + return [ + (0x32B6, "M", "41"), + (0x32B7, "M", "42"), + (0x32B8, "M", "43"), + (0x32B9, "M", "44"), + (0x32BA, "M", "45"), + (0x32BB, "M", "46"), + (0x32BC, "M", "47"), + (0x32BD, "M", "48"), + (0x32BE, "M", "49"), + (0x32BF, "M", "50"), + (0x32C0, "M", "1月"), + (0x32C1, "M", "2月"), + (0x32C2, "M", "3月"), + (0x32C3, "M", "4月"), + (0x32C4, "M", "5月"), + (0x32C5, "M", "6月"), + (0x32C6, "M", "7月"), + (0x32C7, "M", "8月"), + (0x32C8, "M", "9月"), + (0x32C9, "M", "10月"), + (0x32CA, "M", "11月"), + (0x32CB, "M", "12月"), + (0x32CC, "M", "hg"), + (0x32CD, "M", "erg"), + (0x32CE, "M", "ev"), + (0x32CF, "M", "ltd"), + (0x32D0, "M", "ア"), + (0x32D1, "M", "イ"), + (0x32D2, "M", "ウ"), + (0x32D3, "M", "エ"), + (0x32D4, "M", "オ"), + (0x32D5, "M", "カ"), + (0x32D6, "M", "キ"), + (0x32D7, "M", "ク"), + (0x32D8, "M", "ケ"), + (0x32D9, "M", "コ"), + (0x32DA, "M", "サ"), + (0x32DB, "M", "シ"), + (0x32DC, "M", "ス"), + (0x32DD, "M", "セ"), + (0x32DE, "M", "ソ"), + (0x32DF, "M", "タ"), + (0x32E0, "M", "チ"), + (0x32E1, "M", "ツ"), + (0x32E2, "M", "テ"), + (0x32E3, "M", "ト"), + (0x32E4, "M", "ナ"), + (0x32E5, "M", "ニ"), + (0x32E6, "M", "ヌ"), + (0x32E7, "M", "ネ"), + (0x32E8, "M", "ノ"), + (0x32E9, "M", "ハ"), + (0x32EA, "M", "ヒ"), + (0x32EB, "M", "フ"), + (0x32EC, "M", "ヘ"), + (0x32ED, "M", "ホ"), + (0x32EE, "M", "マ"), + (0x32EF, "M", "ミ"), + (0x32F0, "M", "ム"), + (0x32F1, "M", "メ"), + (0x32F2, "M", "モ"), + (0x32F3, "M", "ヤ"), + (0x32F4, "M", "ユ"), + (0x32F5, "M", "ヨ"), + (0x32F6, "M", "ラ"), + (0x32F7, "M", "リ"), + (0x32F8, "M", "ル"), + (0x32F9, "M", "レ"), + (0x32FA, "M", "ロ"), + (0x32FB, "M", "ワ"), + (0x32FC, "M", "ヰ"), + (0x32FD, "M", "ヱ"), + (0x32FE, "M", "ヲ"), + (0x32FF, "M", "令和"), + (0x3300, "M", "アパート"), + (0x3301, "M", "アルファ"), + (0x3302, "M", "アンペア"), + (0x3303, "M", "アール"), + (0x3304, "M", "イニング"), + (0x3305, "M", "インチ"), + (0x3306, "M", "ウォン"), + (0x3307, "M", "エスクード"), + (0x3308, "M", "エーカー"), + (0x3309, "M", "オンス"), + (0x330A, "M", "オーム"), + (0x330B, "M", "カイリ"), + (0x330C, "M", "カラット"), + (0x330D, "M", "カロリー"), + (0x330E, "M", "ガロン"), + (0x330F, "M", "ガンマ"), + (0x3310, "M", "ギガ"), + (0x3311, "M", "ギニー"), + (0x3312, "M", "キュリー"), + (0x3313, "M", "ギルダー"), + (0x3314, "M", "キロ"), + (0x3315, "M", "キログラム"), + (0x3316, "M", "キロメートル"), + (0x3317, "M", "キロワット"), + (0x3318, "M", "グラム"), + (0x3319, "M", "グラムトン"), + ] + + +def _seg_33() -> List[Union[Tuple[int, str], Tuple[int, str, str]]]: + return [ + (0x331A, "M", "クルゼイロ"), + (0x331B, "M", "クローネ"), + (0x331C, "M", "ケース"), + (0x331D, "M", "コルナ"), + (0x331E, "M", "コーポ"), + (0x331F, "M", "サイクル"), + (0x3320, "M", "サンチーム"), + (0x3321, "M", "シリング"), + (0x3322, "M", "センチ"), + (0x3323, "M", "セント"), + (0x3324, "M", "ダース"), + (0x3325, "M", "デシ"), + (0x3326, "M", "ドル"), + (0x3327, "M", "トン"), + (0x3328, "M", "ナノ"), + (0x3329, "M", "ノット"), + (0x332A, "M", "ハイツ"), + (0x332B, "M", "パーセント"), + (0x332C, "M", "パーツ"), + (0x332D, "M", "バーレル"), + (0x332E, "M", "ピアストル"), + (0x332F, "M", "ピクル"), + (0x3330, "M", "ピコ"), + (0x3331, "M", "ビル"), + (0x3332, "M", "ファラッド"), + (0x3333, "M", "フィート"), + (0x3334, "M", "ブッシェル"), + (0x3335, "M", "フラン"), + (0x3336, "M", "ヘクタール"), + (0x3337, "M", "ペソ"), + (0x3338, "M", "ペニヒ"), + (0x3339, "M", "ヘルツ"), + (0x333A, "M", "ペンス"), + (0x333B, "M", "ページ"), + (0x333C, "M", "ベータ"), + (0x333D, "M", "ポイント"), + (0x333E, "M", "ボルト"), + (0x333F, "M", "ホン"), + (0x3340, "M", "ポンド"), + (0x3341, "M", "ホール"), + (0x3342, "M", "ホーン"), + (0x3343, "M", "マイクロ"), + (0x3344, "M", "マイル"), + (0x3345, "M", "マッハ"), + (0x3346, "M", "マルク"), + (0x3347, "M", "マンション"), + (0x3348, "M", "ミクロン"), + (0x3349, "M", "ミリ"), + (0x334A, "M", "ミリバール"), + (0x334B, "M", "メガ"), + (0x334C, "M", "メガトン"), + (0x334D, "M", "メートル"), + (0x334E, "M", "ヤード"), + (0x334F, "M", "ヤール"), + (0x3350, "M", "ユアン"), + (0x3351, "M", "リットル"), + (0x3352, "M", "リラ"), + (0x3353, "M", "ルピー"), + (0x3354, "M", "ルーブル"), + (0x3355, "M", "レム"), + (0x3356, "M", "レントゲン"), + (0x3357, "M", "ワット"), + (0x3358, "M", "0点"), + (0x3359, "M", "1点"), + (0x335A, "M", "2点"), + (0x335B, "M", "3点"), + (0x335C, "M", "4点"), + (0x335D, "M", "5点"), + (0x335E, "M", "6点"), + (0x335F, "M", "7点"), + (0x3360, "M", "8点"), + (0x3361, "M", "9点"), + (0x3362, "M", "10点"), + (0x3363, "M", "11点"), + (0x3364, "M", "12点"), + (0x3365, "M", "13点"), + (0x3366, "M", "14点"), + (0x3367, "M", "15点"), + (0x3368, "M", "16点"), + (0x3369, "M", "17点"), + (0x336A, "M", "18点"), + (0x336B, "M", "19点"), + (0x336C, "M", "20点"), + (0x336D, "M", "21点"), + (0x336E, "M", "22点"), + (0x336F, "M", "23点"), + (0x3370, "M", "24点"), + (0x3371, "M", "hpa"), + (0x3372, "M", "da"), + (0x3373, "M", "au"), + (0x3374, "M", "bar"), + (0x3375, "M", "ov"), + (0x3376, "M", "pc"), + (0x3377, "M", "dm"), + (0x3378, "M", "dm2"), + (0x3379, "M", "dm3"), + (0x337A, "M", "iu"), + (0x337B, "M", "平成"), + (0x337C, "M", "昭和"), + (0x337D, "M", "大正"), + ] + + +def _seg_34() -> List[Union[Tuple[int, str], Tuple[int, str, str]]]: + return [ + (0x337E, "M", "明治"), + (0x337F, "M", "株式会社"), + (0x3380, "M", "pa"), + (0x3381, "M", "na"), + (0x3382, "M", "μa"), + (0x3383, "M", "ma"), + (0x3384, "M", "ka"), + (0x3385, "M", "kb"), + (0x3386, "M", "mb"), + (0x3387, "M", "gb"), + (0x3388, "M", "cal"), + (0x3389, "M", "kcal"), + (0x338A, "M", "pf"), + (0x338B, "M", "nf"), + (0x338C, "M", "μf"), + (0x338D, "M", "μg"), + (0x338E, "M", "mg"), + (0x338F, "M", "kg"), + (0x3390, "M", "hz"), + (0x3391, "M", "khz"), + (0x3392, "M", "mhz"), + (0x3393, "M", "ghz"), + (0x3394, "M", "thz"), + (0x3395, "M", "μl"), + (0x3396, "M", "ml"), + (0x3397, "M", "dl"), + (0x3398, "M", "kl"), + (0x3399, "M", "fm"), + (0x339A, "M", "nm"), + (0x339B, "M", "μm"), + (0x339C, "M", "mm"), + (0x339D, "M", "cm"), + (0x339E, "M", "km"), + (0x339F, "M", "mm2"), + (0x33A0, "M", "cm2"), + (0x33A1, "M", "m2"), + (0x33A2, "M", "km2"), + (0x33A3, "M", "mm3"), + (0x33A4, "M", "cm3"), + (0x33A5, "M", "m3"), + (0x33A6, "M", "km3"), + (0x33A7, "M", "m∕s"), + (0x33A8, "M", "m∕s2"), + (0x33A9, "M", "pa"), + (0x33AA, "M", "kpa"), + (0x33AB, "M", "mpa"), + (0x33AC, "M", "gpa"), + (0x33AD, "M", "rad"), + (0x33AE, "M", "rad∕s"), + (0x33AF, "M", "rad∕s2"), + (0x33B0, "M", "ps"), + (0x33B1, "M", "ns"), + (0x33B2, "M", "μs"), + (0x33B3, "M", "ms"), + (0x33B4, "M", "pv"), + (0x33B5, "M", "nv"), + (0x33B6, "M", "μv"), + (0x33B7, "M", "mv"), + (0x33B8, "M", "kv"), + (0x33B9, "M", "mv"), + (0x33BA, "M", "pw"), + (0x33BB, "M", "nw"), + (0x33BC, "M", "μw"), + (0x33BD, "M", "mw"), + (0x33BE, "M", "kw"), + (0x33BF, "M", "mw"), + (0x33C0, "M", "kω"), + (0x33C1, "M", "mω"), + (0x33C2, "X"), + (0x33C3, "M", "bq"), + (0x33C4, "M", "cc"), + (0x33C5, "M", "cd"), + (0x33C6, "M", "c∕kg"), + (0x33C7, "X"), + (0x33C8, "M", "db"), + (0x33C9, "M", "gy"), + (0x33CA, "M", "ha"), + (0x33CB, "M", "hp"), + (0x33CC, "M", "in"), + (0x33CD, "M", "kk"), + (0x33CE, "M", "km"), + (0x33CF, "M", "kt"), + (0x33D0, "M", "lm"), + (0x33D1, "M", "ln"), + (0x33D2, "M", "log"), + (0x33D3, "M", "lx"), + (0x33D4, "M", "mb"), + (0x33D5, "M", "mil"), + (0x33D6, "M", "mol"), + (0x33D7, "M", "ph"), + (0x33D8, "X"), + (0x33D9, "M", "ppm"), + (0x33DA, "M", "pr"), + (0x33DB, "M", "sr"), + (0x33DC, "M", "sv"), + (0x33DD, "M", "wb"), + (0x33DE, "M", "v∕m"), + (0x33DF, "M", "a∕m"), + (0x33E0, "M", "1日"), + (0x33E1, "M", "2日"), + ] + + +def _seg_35() -> List[Union[Tuple[int, str], Tuple[int, str, str]]]: + return [ + (0x33E2, "M", "3日"), + (0x33E3, "M", "4日"), + (0x33E4, "M", "5日"), + (0x33E5, "M", "6日"), + (0x33E6, "M", "7日"), + (0x33E7, "M", "8日"), + (0x33E8, "M", "9日"), + (0x33E9, "M", "10日"), + (0x33EA, "M", "11日"), + (0x33EB, "M", "12日"), + (0x33EC, "M", "13日"), + (0x33ED, "M", "14日"), + (0x33EE, "M", "15日"), + (0x33EF, "M", "16日"), + (0x33F0, "M", "17日"), + (0x33F1, "M", "18日"), + (0x33F2, "M", "19日"), + (0x33F3, "M", "20日"), + (0x33F4, "M", "21日"), + (0x33F5, "M", "22日"), + (0x33F6, "M", "23日"), + (0x33F7, "M", "24日"), + (0x33F8, "M", "25日"), + (0x33F9, "M", "26日"), + (0x33FA, "M", "27日"), + (0x33FB, "M", "28日"), + (0x33FC, "M", "29日"), + (0x33FD, "M", "30日"), + (0x33FE, "M", "31日"), + (0x33FF, "M", "gal"), + (0x3400, "V"), + (0xA48D, "X"), + (0xA490, "V"), + (0xA4C7, "X"), + (0xA4D0, "V"), + (0xA62C, "X"), + (0xA640, "M", "ꙁ"), + (0xA641, "V"), + (0xA642, "M", "ꙃ"), + (0xA643, "V"), + (0xA644, "M", "ꙅ"), + (0xA645, "V"), + (0xA646, "M", "ꙇ"), + (0xA647, "V"), + (0xA648, "M", "ꙉ"), + (0xA649, "V"), + (0xA64A, "M", "ꙋ"), + (0xA64B, "V"), + (0xA64C, "M", "ꙍ"), + (0xA64D, "V"), + (0xA64E, "M", "ꙏ"), + (0xA64F, "V"), + (0xA650, "M", "ꙑ"), + (0xA651, "V"), + (0xA652, "M", "ꙓ"), + (0xA653, "V"), + (0xA654, "M", "ꙕ"), + (0xA655, "V"), + (0xA656, "M", "ꙗ"), + (0xA657, "V"), + (0xA658, "M", "ꙙ"), + (0xA659, "V"), + (0xA65A, "M", "ꙛ"), + (0xA65B, "V"), + (0xA65C, "M", "ꙝ"), + (0xA65D, "V"), + (0xA65E, "M", "ꙟ"), + (0xA65F, "V"), + (0xA660, "M", "ꙡ"), + (0xA661, "V"), + (0xA662, "M", "ꙣ"), + (0xA663, "V"), + (0xA664, "M", "ꙥ"), + (0xA665, "V"), + (0xA666, "M", "ꙧ"), + (0xA667, "V"), + (0xA668, "M", "ꙩ"), + (0xA669, "V"), + (0xA66A, "M", "ꙫ"), + (0xA66B, "V"), + (0xA66C, "M", "ꙭ"), + (0xA66D, "V"), + (0xA680, "M", "ꚁ"), + (0xA681, "V"), + (0xA682, "M", "ꚃ"), + (0xA683, "V"), + (0xA684, "M", "ꚅ"), + (0xA685, "V"), + (0xA686, "M", "ꚇ"), + (0xA687, "V"), + (0xA688, "M", "ꚉ"), + (0xA689, "V"), + (0xA68A, "M", "ꚋ"), + (0xA68B, "V"), + (0xA68C, "M", "ꚍ"), + (0xA68D, "V"), + (0xA68E, "M", "ꚏ"), + (0xA68F, "V"), + (0xA690, "M", "ꚑ"), + (0xA691, "V"), + ] + + +def _seg_36() -> List[Union[Tuple[int, str], Tuple[int, str, str]]]: + return [ + (0xA692, "M", "ꚓ"), + (0xA693, "V"), + (0xA694, "M", "ꚕ"), + (0xA695, "V"), + (0xA696, "M", "ꚗ"), + (0xA697, "V"), + (0xA698, "M", "ꚙ"), + (0xA699, "V"), + (0xA69A, "M", "ꚛ"), + (0xA69B, "V"), + (0xA69C, "M", "ъ"), + (0xA69D, "M", "ь"), + (0xA69E, "V"), + (0xA6F8, "X"), + (0xA700, "V"), + (0xA722, "M", "ꜣ"), + (0xA723, "V"), + (0xA724, "M", "ꜥ"), + (0xA725, "V"), + (0xA726, "M", "ꜧ"), + (0xA727, "V"), + (0xA728, "M", "ꜩ"), + (0xA729, "V"), + (0xA72A, "M", "ꜫ"), + (0xA72B, "V"), + (0xA72C, "M", "ꜭ"), + (0xA72D, "V"), + (0xA72E, "M", "ꜯ"), + (0xA72F, "V"), + (0xA732, "M", "ꜳ"), + (0xA733, "V"), + (0xA734, "M", "ꜵ"), + (0xA735, "V"), + (0xA736, "M", "ꜷ"), + (0xA737, "V"), + (0xA738, "M", "ꜹ"), + (0xA739, "V"), + (0xA73A, "M", "ꜻ"), + (0xA73B, "V"), + (0xA73C, "M", "ꜽ"), + (0xA73D, "V"), + (0xA73E, "M", "ꜿ"), + (0xA73F, "V"), + (0xA740, "M", "ꝁ"), + (0xA741, "V"), + (0xA742, "M", "ꝃ"), + (0xA743, "V"), + (0xA744, "M", "ꝅ"), + (0xA745, "V"), + (0xA746, "M", "ꝇ"), + (0xA747, "V"), + (0xA748, "M", "ꝉ"), + (0xA749, "V"), + (0xA74A, "M", "ꝋ"), + (0xA74B, "V"), + (0xA74C, "M", "ꝍ"), + (0xA74D, "V"), + (0xA74E, "M", "ꝏ"), + (0xA74F, "V"), + (0xA750, "M", "ꝑ"), + (0xA751, "V"), + (0xA752, "M", "ꝓ"), + (0xA753, "V"), + (0xA754, "M", "ꝕ"), + (0xA755, "V"), + (0xA756, "M", "ꝗ"), + (0xA757, "V"), + (0xA758, "M", "ꝙ"), + (0xA759, "V"), + (0xA75A, "M", "ꝛ"), + (0xA75B, "V"), + (0xA75C, "M", "ꝝ"), + (0xA75D, "V"), + (0xA75E, "M", "ꝟ"), + (0xA75F, "V"), + (0xA760, "M", "ꝡ"), + (0xA761, "V"), + (0xA762, "M", "ꝣ"), + (0xA763, "V"), + (0xA764, "M", "ꝥ"), + (0xA765, "V"), + (0xA766, "M", "ꝧ"), + (0xA767, "V"), + (0xA768, "M", "ꝩ"), + (0xA769, "V"), + (0xA76A, "M", "ꝫ"), + (0xA76B, "V"), + (0xA76C, "M", "ꝭ"), + (0xA76D, "V"), + (0xA76E, "M", "ꝯ"), + (0xA76F, "V"), + (0xA770, "M", "ꝯ"), + (0xA771, "V"), + (0xA779, "M", "ꝺ"), + (0xA77A, "V"), + (0xA77B, "M", "ꝼ"), + (0xA77C, "V"), + (0xA77D, "M", "ᵹ"), + (0xA77E, "M", "ꝿ"), + (0xA77F, "V"), + ] + + +def _seg_37() -> List[Union[Tuple[int, str], Tuple[int, str, str]]]: + return [ + (0xA780, "M", "ꞁ"), + (0xA781, "V"), + (0xA782, "M", "ꞃ"), + (0xA783, "V"), + (0xA784, "M", "ꞅ"), + (0xA785, "V"), + (0xA786, "M", "ꞇ"), + (0xA787, "V"), + (0xA78B, "M", "ꞌ"), + (0xA78C, "V"), + (0xA78D, "M", "ɥ"), + (0xA78E, "V"), + (0xA790, "M", "ꞑ"), + (0xA791, "V"), + (0xA792, "M", "ꞓ"), + (0xA793, "V"), + (0xA796, "M", "ꞗ"), + (0xA797, "V"), + (0xA798, "M", "ꞙ"), + (0xA799, "V"), + (0xA79A, "M", "ꞛ"), + (0xA79B, "V"), + (0xA79C, "M", "ꞝ"), + (0xA79D, "V"), + (0xA79E, "M", "ꞟ"), + (0xA79F, "V"), + (0xA7A0, "M", "ꞡ"), + (0xA7A1, "V"), + (0xA7A2, "M", "ꞣ"), + (0xA7A3, "V"), + (0xA7A4, "M", "ꞥ"), + (0xA7A5, "V"), + (0xA7A6, "M", "ꞧ"), + (0xA7A7, "V"), + (0xA7A8, "M", "ꞩ"), + (0xA7A9, "V"), + (0xA7AA, "M", "ɦ"), + (0xA7AB, "M", "ɜ"), + (0xA7AC, "M", "ɡ"), + (0xA7AD, "M", "ɬ"), + (0xA7AE, "M", "ɪ"), + (0xA7AF, "V"), + (0xA7B0, "M", "ʞ"), + (0xA7B1, "M", "ʇ"), + (0xA7B2, "M", "ʝ"), + (0xA7B3, "M", "ꭓ"), + (0xA7B4, "M", "ꞵ"), + (0xA7B5, "V"), + (0xA7B6, "M", "ꞷ"), + (0xA7B7, "V"), + (0xA7B8, "M", "ꞹ"), + (0xA7B9, "V"), + (0xA7BA, "M", "ꞻ"), + (0xA7BB, "V"), + (0xA7BC, "M", "ꞽ"), + (0xA7BD, "V"), + (0xA7BE, "M", "ꞿ"), + (0xA7BF, "V"), + (0xA7C0, "M", "ꟁ"), + (0xA7C1, "V"), + (0xA7C2, "M", "ꟃ"), + (0xA7C3, "V"), + (0xA7C4, "M", "ꞔ"), + (0xA7C5, "M", "ʂ"), + (0xA7C6, "M", "ᶎ"), + (0xA7C7, "M", "ꟈ"), + (0xA7C8, "V"), + (0xA7C9, "M", "ꟊ"), + (0xA7CA, "V"), + (0xA7CB, "X"), + (0xA7D0, "M", "ꟑ"), + (0xA7D1, "V"), + (0xA7D2, "X"), + (0xA7D3, "V"), + (0xA7D4, "X"), + (0xA7D5, "V"), + (0xA7D6, "M", "ꟗ"), + (0xA7D7, "V"), + (0xA7D8, "M", "ꟙ"), + (0xA7D9, "V"), + (0xA7DA, "X"), + (0xA7F2, "M", "c"), + (0xA7F3, "M", "f"), + (0xA7F4, "M", "q"), + (0xA7F5, "M", "ꟶ"), + (0xA7F6, "V"), + (0xA7F8, "M", "ħ"), + (0xA7F9, "M", "œ"), + (0xA7FA, "V"), + (0xA82D, "X"), + (0xA830, "V"), + (0xA83A, "X"), + (0xA840, "V"), + (0xA878, "X"), + (0xA880, "V"), + (0xA8C6, "X"), + (0xA8CE, "V"), + (0xA8DA, "X"), + (0xA8E0, "V"), + (0xA954, "X"), + ] + + +def _seg_38() -> List[Union[Tuple[int, str], Tuple[int, str, str]]]: + return [ + (0xA95F, "V"), + (0xA97D, "X"), + (0xA980, "V"), + (0xA9CE, "X"), + (0xA9CF, "V"), + (0xA9DA, "X"), + (0xA9DE, "V"), + (0xA9FF, "X"), + (0xAA00, "V"), + (0xAA37, "X"), + (0xAA40, "V"), + (0xAA4E, "X"), + (0xAA50, "V"), + (0xAA5A, "X"), + (0xAA5C, "V"), + (0xAAC3, "X"), + (0xAADB, "V"), + (0xAAF7, "X"), + (0xAB01, "V"), + (0xAB07, "X"), + (0xAB09, "V"), + (0xAB0F, "X"), + (0xAB11, "V"), + (0xAB17, "X"), + (0xAB20, "V"), + (0xAB27, "X"), + (0xAB28, "V"), + (0xAB2F, "X"), + (0xAB30, "V"), + (0xAB5C, "M", "ꜧ"), + (0xAB5D, "M", "ꬷ"), + (0xAB5E, "M", "ɫ"), + (0xAB5F, "M", "ꭒ"), + (0xAB60, "V"), + (0xAB69, "M", "ʍ"), + (0xAB6A, "V"), + (0xAB6C, "X"), + (0xAB70, "M", "Ꭰ"), + (0xAB71, "M", "Ꭱ"), + (0xAB72, "M", "Ꭲ"), + (0xAB73, "M", "Ꭳ"), + (0xAB74, "M", "Ꭴ"), + (0xAB75, "M", "Ꭵ"), + (0xAB76, "M", "Ꭶ"), + (0xAB77, "M", "Ꭷ"), + (0xAB78, "M", "Ꭸ"), + (0xAB79, "M", "Ꭹ"), + (0xAB7A, "M", "Ꭺ"), + (0xAB7B, "M", "Ꭻ"), + (0xAB7C, "M", "Ꭼ"), + (0xAB7D, "M", "Ꭽ"), + (0xAB7E, "M", "Ꭾ"), + (0xAB7F, "M", "Ꭿ"), + (0xAB80, "M", "Ꮀ"), + (0xAB81, "M", "Ꮁ"), + (0xAB82, "M", "Ꮂ"), + (0xAB83, "M", "Ꮃ"), + (0xAB84, "M", "Ꮄ"), + (0xAB85, "M", "Ꮅ"), + (0xAB86, "M", "Ꮆ"), + (0xAB87, "M", "Ꮇ"), + (0xAB88, "M", "Ꮈ"), + (0xAB89, "M", "Ꮉ"), + (0xAB8A, "M", "Ꮊ"), + (0xAB8B, "M", "Ꮋ"), + (0xAB8C, "M", "Ꮌ"), + (0xAB8D, "M", "Ꮍ"), + (0xAB8E, "M", "Ꮎ"), + (0xAB8F, "M", "Ꮏ"), + (0xAB90, "M", "Ꮐ"), + (0xAB91, "M", "Ꮑ"), + (0xAB92, "M", "Ꮒ"), + (0xAB93, "M", "Ꮓ"), + (0xAB94, "M", "Ꮔ"), + (0xAB95, "M", "Ꮕ"), + (0xAB96, "M", "Ꮖ"), + (0xAB97, "M", "Ꮗ"), + (0xAB98, "M", "Ꮘ"), + (0xAB99, "M", "Ꮙ"), + (0xAB9A, "M", "Ꮚ"), + (0xAB9B, "M", "Ꮛ"), + (0xAB9C, "M", "Ꮜ"), + (0xAB9D, "M", "Ꮝ"), + (0xAB9E, "M", "Ꮞ"), + (0xAB9F, "M", "Ꮟ"), + (0xABA0, "M", "Ꮠ"), + (0xABA1, "M", "Ꮡ"), + (0xABA2, "M", "Ꮢ"), + (0xABA3, "M", "Ꮣ"), + (0xABA4, "M", "Ꮤ"), + (0xABA5, "M", "Ꮥ"), + (0xABA6, "M", "Ꮦ"), + (0xABA7, "M", "Ꮧ"), + (0xABA8, "M", "Ꮨ"), + (0xABA9, "M", "Ꮩ"), + (0xABAA, "M", "Ꮪ"), + (0xABAB, "M", "Ꮫ"), + (0xABAC, "M", "Ꮬ"), + (0xABAD, "M", "Ꮭ"), + (0xABAE, "M", "Ꮮ"), + ] + + +def _seg_39() -> List[Union[Tuple[int, str], Tuple[int, str, str]]]: + return [ + (0xABAF, "M", "Ꮯ"), + (0xABB0, "M", "Ꮰ"), + (0xABB1, "M", "Ꮱ"), + (0xABB2, "M", "Ꮲ"), + (0xABB3, "M", "Ꮳ"), + (0xABB4, "M", "Ꮴ"), + (0xABB5, "M", "Ꮵ"), + (0xABB6, "M", "Ꮶ"), + (0xABB7, "M", "Ꮷ"), + (0xABB8, "M", "Ꮸ"), + (0xABB9, "M", "Ꮹ"), + (0xABBA, "M", "Ꮺ"), + (0xABBB, "M", "Ꮻ"), + (0xABBC, "M", "Ꮼ"), + (0xABBD, "M", "Ꮽ"), + (0xABBE, "M", "Ꮾ"), + (0xABBF, "M", "Ꮿ"), + (0xABC0, "V"), + (0xABEE, "X"), + (0xABF0, "V"), + (0xABFA, "X"), + (0xAC00, "V"), + (0xD7A4, "X"), + (0xD7B0, "V"), + (0xD7C7, "X"), + (0xD7CB, "V"), + (0xD7FC, "X"), + (0xF900, "M", "豈"), + (0xF901, "M", "更"), + (0xF902, "M", "車"), + (0xF903, "M", "賈"), + (0xF904, "M", "滑"), + (0xF905, "M", "串"), + (0xF906, "M", "句"), + (0xF907, "M", "龜"), + (0xF909, "M", "契"), + (0xF90A, "M", "金"), + (0xF90B, "M", "喇"), + (0xF90C, "M", "奈"), + (0xF90D, "M", "懶"), + (0xF90E, "M", "癩"), + (0xF90F, "M", "羅"), + (0xF910, "M", "蘿"), + (0xF911, "M", "螺"), + (0xF912, "M", "裸"), + (0xF913, "M", "邏"), + (0xF914, "M", "樂"), + (0xF915, "M", "洛"), + (0xF916, "M", "烙"), + (0xF917, "M", "珞"), + (0xF918, "M", "落"), + (0xF919, "M", "酪"), + (0xF91A, "M", "駱"), + (0xF91B, "M", "亂"), + (0xF91C, "M", "卵"), + (0xF91D, "M", "欄"), + (0xF91E, "M", "爛"), + (0xF91F, "M", "蘭"), + (0xF920, "M", "鸞"), + (0xF921, "M", "嵐"), + (0xF922, "M", "濫"), + (0xF923, "M", "藍"), + (0xF924, "M", "襤"), + (0xF925, "M", "拉"), + (0xF926, "M", "臘"), + (0xF927, "M", "蠟"), + (0xF928, "M", "廊"), + (0xF929, "M", "朗"), + (0xF92A, "M", "浪"), + (0xF92B, "M", "狼"), + (0xF92C, "M", "郎"), + (0xF92D, "M", "來"), + (0xF92E, "M", "冷"), + (0xF92F, "M", "勞"), + (0xF930, "M", "擄"), + (0xF931, "M", "櫓"), + (0xF932, "M", "爐"), + (0xF933, "M", "盧"), + (0xF934, "M", "老"), + (0xF935, "M", "蘆"), + (0xF936, "M", "虜"), + (0xF937, "M", "路"), + (0xF938, "M", "露"), + (0xF939, "M", "魯"), + (0xF93A, "M", "鷺"), + (0xF93B, "M", "碌"), + (0xF93C, "M", "祿"), + (0xF93D, "M", "綠"), + (0xF93E, "M", "菉"), + (0xF93F, "M", "錄"), + (0xF940, "M", "鹿"), + (0xF941, "M", "論"), + (0xF942, "M", "壟"), + (0xF943, "M", "弄"), + (0xF944, "M", "籠"), + (0xF945, "M", "聾"), + (0xF946, "M", "牢"), + (0xF947, "M", "磊"), + (0xF948, "M", "賂"), + (0xF949, "M", "雷"), + ] + + +def _seg_40() -> List[Union[Tuple[int, str], Tuple[int, str, str]]]: + return [ + (0xF94A, "M", "壘"), + (0xF94B, "M", "屢"), + (0xF94C, "M", "樓"), + (0xF94D, "M", "淚"), + (0xF94E, "M", "漏"), + (0xF94F, "M", "累"), + (0xF950, "M", "縷"), + (0xF951, "M", "陋"), + (0xF952, "M", "勒"), + (0xF953, "M", "肋"), + (0xF954, "M", "凜"), + (0xF955, "M", "凌"), + (0xF956, "M", "稜"), + (0xF957, "M", "綾"), + (0xF958, "M", "菱"), + (0xF959, "M", "陵"), + (0xF95A, "M", "讀"), + (0xF95B, "M", "拏"), + (0xF95C, "M", "樂"), + (0xF95D, "M", "諾"), + (0xF95E, "M", "丹"), + (0xF95F, "M", "寧"), + (0xF960, "M", "怒"), + (0xF961, "M", "率"), + (0xF962, "M", "異"), + (0xF963, "M", "北"), + (0xF964, "M", "磻"), + (0xF965, "M", "便"), + (0xF966, "M", "復"), + (0xF967, "M", "不"), + (0xF968, "M", "泌"), + (0xF969, "M", "數"), + (0xF96A, "M", "索"), + (0xF96B, "M", "參"), + (0xF96C, "M", "塞"), + (0xF96D, "M", "省"), + (0xF96E, "M", "葉"), + (0xF96F, "M", "說"), + (0xF970, "M", "殺"), + (0xF971, "M", "辰"), + (0xF972, "M", "沈"), + (0xF973, "M", "拾"), + (0xF974, "M", "若"), + (0xF975, "M", "掠"), + (0xF976, "M", "略"), + (0xF977, "M", "亮"), + (0xF978, "M", "兩"), + (0xF979, "M", "凉"), + (0xF97A, "M", "梁"), + (0xF97B, "M", "糧"), + (0xF97C, "M", "良"), + (0xF97D, "M", "諒"), + (0xF97E, "M", "量"), + (0xF97F, "M", "勵"), + (0xF980, "M", "呂"), + (0xF981, "M", "女"), + (0xF982, "M", "廬"), + (0xF983, "M", "旅"), + (0xF984, "M", "濾"), + (0xF985, "M", "礪"), + (0xF986, "M", "閭"), + (0xF987, "M", "驪"), + (0xF988, "M", "麗"), + (0xF989, "M", "黎"), + (0xF98A, "M", "力"), + (0xF98B, "M", "曆"), + (0xF98C, "M", "歷"), + (0xF98D, "M", "轢"), + (0xF98E, "M", "年"), + (0xF98F, "M", "憐"), + (0xF990, "M", "戀"), + (0xF991, "M", "撚"), + (0xF992, "M", "漣"), + (0xF993, "M", "煉"), + (0xF994, "M", "璉"), + (0xF995, "M", "秊"), + (0xF996, "M", "練"), + (0xF997, "M", "聯"), + (0xF998, "M", "輦"), + (0xF999, "M", "蓮"), + (0xF99A, "M", "連"), + (0xF99B, "M", "鍊"), + (0xF99C, "M", "列"), + (0xF99D, "M", "劣"), + (0xF99E, "M", "咽"), + (0xF99F, "M", "烈"), + (0xF9A0, "M", "裂"), + (0xF9A1, "M", "說"), + (0xF9A2, "M", "廉"), + (0xF9A3, "M", "念"), + (0xF9A4, "M", "捻"), + (0xF9A5, "M", "殮"), + (0xF9A6, "M", "簾"), + (0xF9A7, "M", "獵"), + (0xF9A8, "M", "令"), + (0xF9A9, "M", "囹"), + (0xF9AA, "M", "寧"), + (0xF9AB, "M", "嶺"), + (0xF9AC, "M", "怜"), + (0xF9AD, "M", "玲"), + ] + + +def _seg_41() -> List[Union[Tuple[int, str], Tuple[int, str, str]]]: + return [ + (0xF9AE, "M", "瑩"), + (0xF9AF, "M", "羚"), + (0xF9B0, "M", "聆"), + (0xF9B1, "M", "鈴"), + (0xF9B2, "M", "零"), + (0xF9B3, "M", "靈"), + (0xF9B4, "M", "領"), + (0xF9B5, "M", "例"), + (0xF9B6, "M", "禮"), + (0xF9B7, "M", "醴"), + (0xF9B8, "M", "隸"), + (0xF9B9, "M", "惡"), + (0xF9BA, "M", "了"), + (0xF9BB, "M", "僚"), + (0xF9BC, "M", "寮"), + (0xF9BD, "M", "尿"), + (0xF9BE, "M", "料"), + (0xF9BF, "M", "樂"), + (0xF9C0, "M", "燎"), + (0xF9C1, "M", "療"), + (0xF9C2, "M", "蓼"), + (0xF9C3, "M", "遼"), + (0xF9C4, "M", "龍"), + (0xF9C5, "M", "暈"), + (0xF9C6, "M", "阮"), + (0xF9C7, "M", "劉"), + (0xF9C8, "M", "杻"), + (0xF9C9, "M", "柳"), + (0xF9CA, "M", "流"), + (0xF9CB, "M", "溜"), + (0xF9CC, "M", "琉"), + (0xF9CD, "M", "留"), + (0xF9CE, "M", "硫"), + (0xF9CF, "M", "紐"), + (0xF9D0, "M", "類"), + (0xF9D1, "M", "六"), + (0xF9D2, "M", "戮"), + (0xF9D3, "M", "陸"), + (0xF9D4, "M", "倫"), + (0xF9D5, "M", "崙"), + (0xF9D6, "M", "淪"), + (0xF9D7, "M", "輪"), + (0xF9D8, "M", "律"), + (0xF9D9, "M", "慄"), + (0xF9DA, "M", "栗"), + (0xF9DB, "M", "率"), + (0xF9DC, "M", "隆"), + (0xF9DD, "M", "利"), + (0xF9DE, "M", "吏"), + (0xF9DF, "M", "履"), + (0xF9E0, "M", "易"), + (0xF9E1, "M", "李"), + (0xF9E2, "M", "梨"), + (0xF9E3, "M", "泥"), + (0xF9E4, "M", "理"), + (0xF9E5, "M", "痢"), + (0xF9E6, "M", "罹"), + (0xF9E7, "M", "裏"), + (0xF9E8, "M", "裡"), + (0xF9E9, "M", "里"), + (0xF9EA, "M", "離"), + (0xF9EB, "M", "匿"), + (0xF9EC, "M", "溺"), + (0xF9ED, "M", "吝"), + (0xF9EE, "M", "燐"), + (0xF9EF, "M", "璘"), + (0xF9F0, "M", "藺"), + (0xF9F1, "M", "隣"), + (0xF9F2, "M", "鱗"), + (0xF9F3, "M", "麟"), + (0xF9F4, "M", "林"), + (0xF9F5, "M", "淋"), + (0xF9F6, "M", "臨"), + (0xF9F7, "M", "立"), + (0xF9F8, "M", "笠"), + (0xF9F9, "M", "粒"), + (0xF9FA, "M", "狀"), + (0xF9FB, "M", "炙"), + (0xF9FC, "M", "識"), + (0xF9FD, "M", "什"), + (0xF9FE, "M", "茶"), + (0xF9FF, "M", "刺"), + (0xFA00, "M", "切"), + (0xFA01, "M", "度"), + (0xFA02, "M", "拓"), + (0xFA03, "M", "糖"), + (0xFA04, "M", "宅"), + (0xFA05, "M", "洞"), + (0xFA06, "M", "暴"), + (0xFA07, "M", "輻"), + (0xFA08, "M", "行"), + (0xFA09, "M", "降"), + (0xFA0A, "M", "見"), + (0xFA0B, "M", "廓"), + (0xFA0C, "M", "兀"), + (0xFA0D, "M", "嗀"), + (0xFA0E, "V"), + (0xFA10, "M", "塚"), + (0xFA11, "V"), + (0xFA12, "M", "晴"), + ] + + +def _seg_42() -> List[Union[Tuple[int, str], Tuple[int, str, str]]]: + return [ + (0xFA13, "V"), + (0xFA15, "M", "凞"), + (0xFA16, "M", "猪"), + (0xFA17, "M", "益"), + (0xFA18, "M", "礼"), + (0xFA19, "M", "神"), + (0xFA1A, "M", "祥"), + (0xFA1B, "M", "福"), + (0xFA1C, "M", "靖"), + (0xFA1D, "M", "精"), + (0xFA1E, "M", "羽"), + (0xFA1F, "V"), + (0xFA20, "M", "蘒"), + (0xFA21, "V"), + (0xFA22, "M", "諸"), + (0xFA23, "V"), + (0xFA25, "M", "逸"), + (0xFA26, "M", "都"), + (0xFA27, "V"), + (0xFA2A, "M", "飯"), + (0xFA2B, "M", "飼"), + (0xFA2C, "M", "館"), + (0xFA2D, "M", "鶴"), + (0xFA2E, "M", "郞"), + (0xFA2F, "M", "隷"), + (0xFA30, "M", "侮"), + (0xFA31, "M", "僧"), + (0xFA32, "M", "免"), + (0xFA33, "M", "勉"), + (0xFA34, "M", "勤"), + (0xFA35, "M", "卑"), + (0xFA36, "M", "喝"), + (0xFA37, "M", "嘆"), + (0xFA38, "M", "器"), + (0xFA39, "M", "塀"), + (0xFA3A, "M", "墨"), + (0xFA3B, "M", "層"), + (0xFA3C, "M", "屮"), + (0xFA3D, "M", "悔"), + (0xFA3E, "M", "慨"), + (0xFA3F, "M", "憎"), + (0xFA40, "M", "懲"), + (0xFA41, "M", "敏"), + (0xFA42, "M", "既"), + (0xFA43, "M", "暑"), + (0xFA44, "M", "梅"), + (0xFA45, "M", "海"), + (0xFA46, "M", "渚"), + (0xFA47, "M", "漢"), + (0xFA48, "M", "煮"), + (0xFA49, "M", "爫"), + (0xFA4A, "M", "琢"), + (0xFA4B, "M", "碑"), + (0xFA4C, "M", "社"), + (0xFA4D, "M", "祉"), + (0xFA4E, "M", "祈"), + (0xFA4F, "M", "祐"), + (0xFA50, "M", "祖"), + (0xFA51, "M", "祝"), + (0xFA52, "M", "禍"), + (0xFA53, "M", "禎"), + (0xFA54, "M", "穀"), + (0xFA55, "M", "突"), + (0xFA56, "M", "節"), + (0xFA57, "M", "練"), + (0xFA58, "M", "縉"), + (0xFA59, "M", "繁"), + (0xFA5A, "M", "署"), + (0xFA5B, "M", "者"), + (0xFA5C, "M", "臭"), + (0xFA5D, "M", "艹"), + (0xFA5F, "M", "著"), + (0xFA60, "M", "褐"), + (0xFA61, "M", "視"), + (0xFA62, "M", "謁"), + (0xFA63, "M", "謹"), + (0xFA64, "M", "賓"), + (0xFA65, "M", "贈"), + (0xFA66, "M", "辶"), + (0xFA67, "M", "逸"), + (0xFA68, "M", "難"), + (0xFA69, "M", "響"), + (0xFA6A, "M", "頻"), + (0xFA6B, "M", "恵"), + (0xFA6C, "M", "𤋮"), + (0xFA6D, "M", "舘"), + (0xFA6E, "X"), + (0xFA70, "M", "並"), + (0xFA71, "M", "况"), + (0xFA72, "M", "全"), + (0xFA73, "M", "侀"), + (0xFA74, "M", "充"), + (0xFA75, "M", "冀"), + (0xFA76, "M", "勇"), + (0xFA77, "M", "勺"), + (0xFA78, "M", "喝"), + (0xFA79, "M", "啕"), + (0xFA7A, "M", "喙"), + (0xFA7B, "M", "嗢"), + (0xFA7C, "M", "塚"), + ] + + +def _seg_43() -> List[Union[Tuple[int, str], Tuple[int, str, str]]]: + return [ + (0xFA7D, "M", "墳"), + (0xFA7E, "M", "奄"), + (0xFA7F, "M", "奔"), + (0xFA80, "M", "婢"), + (0xFA81, "M", "嬨"), + (0xFA82, "M", "廒"), + (0xFA83, "M", "廙"), + (0xFA84, "M", "彩"), + (0xFA85, "M", "徭"), + (0xFA86, "M", "惘"), + (0xFA87, "M", "慎"), + (0xFA88, "M", "愈"), + (0xFA89, "M", "憎"), + (0xFA8A, "M", "慠"), + (0xFA8B, "M", "懲"), + (0xFA8C, "M", "戴"), + (0xFA8D, "M", "揄"), + (0xFA8E, "M", "搜"), + (0xFA8F, "M", "摒"), + (0xFA90, "M", "敖"), + (0xFA91, "M", "晴"), + (0xFA92, "M", "朗"), + (0xFA93, "M", "望"), + (0xFA94, "M", "杖"), + (0xFA95, "M", "歹"), + (0xFA96, "M", "殺"), + (0xFA97, "M", "流"), + (0xFA98, "M", "滛"), + (0xFA99, "M", "滋"), + (0xFA9A, "M", "漢"), + (0xFA9B, "M", "瀞"), + (0xFA9C, "M", "煮"), + (0xFA9D, "M", "瞧"), + (0xFA9E, "M", "爵"), + (0xFA9F, "M", "犯"), + (0xFAA0, "M", "猪"), + (0xFAA1, "M", "瑱"), + (0xFAA2, "M", "甆"), + (0xFAA3, "M", "画"), + (0xFAA4, "M", "瘝"), + (0xFAA5, "M", "瘟"), + (0xFAA6, "M", "益"), + (0xFAA7, "M", "盛"), + (0xFAA8, "M", "直"), + (0xFAA9, "M", "睊"), + (0xFAAA, "M", "着"), + (0xFAAB, "M", "磌"), + (0xFAAC, "M", "窱"), + (0xFAAD, "M", "節"), + (0xFAAE, "M", "类"), + (0xFAAF, "M", "絛"), + (0xFAB0, "M", "練"), + (0xFAB1, "M", "缾"), + (0xFAB2, "M", "者"), + (0xFAB3, "M", "荒"), + (0xFAB4, "M", "華"), + (0xFAB5, "M", "蝹"), + (0xFAB6, "M", "襁"), + (0xFAB7, "M", "覆"), + (0xFAB8, "M", "視"), + (0xFAB9, "M", "調"), + (0xFABA, "M", "諸"), + (0xFABB, "M", "請"), + (0xFABC, "M", "謁"), + (0xFABD, "M", "諾"), + (0xFABE, "M", "諭"), + (0xFABF, "M", "謹"), + (0xFAC0, "M", "變"), + (0xFAC1, "M", "贈"), + (0xFAC2, "M", "輸"), + (0xFAC3, "M", "遲"), + (0xFAC4, "M", "醙"), + (0xFAC5, "M", "鉶"), + (0xFAC6, "M", "陼"), + (0xFAC7, "M", "難"), + (0xFAC8, "M", "靖"), + (0xFAC9, "M", "韛"), + (0xFACA, "M", "響"), + (0xFACB, "M", "頋"), + (0xFACC, "M", "頻"), + (0xFACD, "M", "鬒"), + (0xFACE, "M", "龜"), + (0xFACF, "M", "𢡊"), + (0xFAD0, "M", "𢡄"), + (0xFAD1, "M", "𣏕"), + (0xFAD2, "M", "㮝"), + (0xFAD3, "M", "䀘"), + (0xFAD4, "M", "䀹"), + (0xFAD5, "M", "𥉉"), + (0xFAD6, "M", "𥳐"), + (0xFAD7, "M", "𧻓"), + (0xFAD8, "M", "齃"), + (0xFAD9, "M", "龎"), + (0xFADA, "X"), + (0xFB00, "M", "ff"), + (0xFB01, "M", "fi"), + (0xFB02, "M", "fl"), + (0xFB03, "M", "ffi"), + (0xFB04, "M", "ffl"), + (0xFB05, "M", "st"), + ] + + +def _seg_44() -> List[Union[Tuple[int, str], Tuple[int, str, str]]]: + return [ + (0xFB07, "X"), + (0xFB13, "M", "մն"), + (0xFB14, "M", "մե"), + (0xFB15, "M", "մի"), + (0xFB16, "M", "վն"), + (0xFB17, "M", "մխ"), + (0xFB18, "X"), + (0xFB1D, "M", "יִ"), + (0xFB1E, "V"), + (0xFB1F, "M", "ײַ"), + (0xFB20, "M", "ע"), + (0xFB21, "M", "א"), + (0xFB22, "M", "ד"), + (0xFB23, "M", "ה"), + (0xFB24, "M", "כ"), + (0xFB25, "M", "ל"), + (0xFB26, "M", "ם"), + (0xFB27, "M", "ר"), + (0xFB28, "M", "ת"), + (0xFB29, "3", "+"), + (0xFB2A, "M", "שׁ"), + (0xFB2B, "M", "שׂ"), + (0xFB2C, "M", "שּׁ"), + (0xFB2D, "M", "שּׂ"), + (0xFB2E, "M", "אַ"), + (0xFB2F, "M", "אָ"), + (0xFB30, "M", "אּ"), + (0xFB31, "M", "בּ"), + (0xFB32, "M", "גּ"), + (0xFB33, "M", "דּ"), + (0xFB34, "M", "הּ"), + (0xFB35, "M", "וּ"), + (0xFB36, "M", "זּ"), + (0xFB37, "X"), + (0xFB38, "M", "טּ"), + (0xFB39, "M", "יּ"), + (0xFB3A, "M", "ךּ"), + (0xFB3B, "M", "כּ"), + (0xFB3C, "M", "לּ"), + (0xFB3D, "X"), + (0xFB3E, "M", "מּ"), + (0xFB3F, "X"), + (0xFB40, "M", "נּ"), + (0xFB41, "M", "סּ"), + (0xFB42, "X"), + (0xFB43, "M", "ףּ"), + (0xFB44, "M", "פּ"), + (0xFB45, "X"), + (0xFB46, "M", "צּ"), + (0xFB47, "M", "קּ"), + (0xFB48, "M", "רּ"), + (0xFB49, "M", "שּ"), + (0xFB4A, "M", "תּ"), + (0xFB4B, "M", "וֹ"), + (0xFB4C, "M", "בֿ"), + (0xFB4D, "M", "כֿ"), + (0xFB4E, "M", "פֿ"), + (0xFB4F, "M", "אל"), + (0xFB50, "M", "ٱ"), + (0xFB52, "M", "ٻ"), + (0xFB56, "M", "پ"), + (0xFB5A, "M", "ڀ"), + (0xFB5E, "M", "ٺ"), + (0xFB62, "M", "ٿ"), + (0xFB66, "M", "ٹ"), + (0xFB6A, "M", "ڤ"), + (0xFB6E, "M", "ڦ"), + (0xFB72, "M", "ڄ"), + (0xFB76, "M", "ڃ"), + (0xFB7A, "M", "چ"), + (0xFB7E, "M", "ڇ"), + (0xFB82, "M", "ڍ"), + (0xFB84, "M", "ڌ"), + (0xFB86, "M", "ڎ"), + (0xFB88, "M", "ڈ"), + (0xFB8A, "M", "ژ"), + (0xFB8C, "M", "ڑ"), + (0xFB8E, "M", "ک"), + (0xFB92, "M", "گ"), + (0xFB96, "M", "ڳ"), + (0xFB9A, "M", "ڱ"), + (0xFB9E, "M", "ں"), + (0xFBA0, "M", "ڻ"), + (0xFBA4, "M", "ۀ"), + (0xFBA6, "M", "ہ"), + (0xFBAA, "M", "ھ"), + (0xFBAE, "M", "ے"), + (0xFBB0, "M", "ۓ"), + (0xFBB2, "V"), + (0xFBC3, "X"), + (0xFBD3, "M", "ڭ"), + (0xFBD7, "M", "ۇ"), + (0xFBD9, "M", "ۆ"), + (0xFBDB, "M", "ۈ"), + (0xFBDD, "M", "ۇٴ"), + (0xFBDE, "M", "ۋ"), + (0xFBE0, "M", "ۅ"), + (0xFBE2, "M", "ۉ"), + (0xFBE4, "M", "ې"), + (0xFBE8, "M", "ى"), + ] + + +def _seg_45() -> List[Union[Tuple[int, str], Tuple[int, str, str]]]: + return [ + (0xFBEA, "M", "ئا"), + (0xFBEC, "M", "ئە"), + (0xFBEE, "M", "ئو"), + (0xFBF0, "M", "ئۇ"), + (0xFBF2, "M", "ئۆ"), + (0xFBF4, "M", "ئۈ"), + (0xFBF6, "M", "ئې"), + (0xFBF9, "M", "ئى"), + (0xFBFC, "M", "ی"), + (0xFC00, "M", "ئج"), + (0xFC01, "M", "ئح"), + (0xFC02, "M", "ئم"), + (0xFC03, "M", "ئى"), + (0xFC04, "M", "ئي"), + (0xFC05, "M", "بج"), + (0xFC06, "M", "بح"), + (0xFC07, "M", "بخ"), + (0xFC08, "M", "بم"), + (0xFC09, "M", "بى"), + (0xFC0A, "M", "بي"), + (0xFC0B, "M", "تج"), + (0xFC0C, "M", "تح"), + (0xFC0D, "M", "تخ"), + (0xFC0E, "M", "تم"), + (0xFC0F, "M", "تى"), + (0xFC10, "M", "تي"), + (0xFC11, "M", "ثج"), + (0xFC12, "M", "ثم"), + (0xFC13, "M", "ثى"), + (0xFC14, "M", "ثي"), + (0xFC15, "M", "جح"), + (0xFC16, "M", "جم"), + (0xFC17, "M", "حج"), + (0xFC18, "M", "حم"), + (0xFC19, "M", "خج"), + (0xFC1A, "M", "خح"), + (0xFC1B, "M", "خم"), + (0xFC1C, "M", "سج"), + (0xFC1D, "M", "سح"), + (0xFC1E, "M", "سخ"), + (0xFC1F, "M", "سم"), + (0xFC20, "M", "صح"), + (0xFC21, "M", "صم"), + (0xFC22, "M", "ضج"), + (0xFC23, "M", "ضح"), + (0xFC24, "M", "ضخ"), + (0xFC25, "M", "ضم"), + (0xFC26, "M", "طح"), + (0xFC27, "M", "طم"), + (0xFC28, "M", "ظم"), + (0xFC29, "M", "عج"), + (0xFC2A, "M", "عم"), + (0xFC2B, "M", "غج"), + (0xFC2C, "M", "غم"), + (0xFC2D, "M", "فج"), + (0xFC2E, "M", "فح"), + (0xFC2F, "M", "فخ"), + (0xFC30, "M", "فم"), + (0xFC31, "M", "فى"), + (0xFC32, "M", "في"), + (0xFC33, "M", "قح"), + (0xFC34, "M", "قم"), + (0xFC35, "M", "قى"), + (0xFC36, "M", "قي"), + (0xFC37, "M", "كا"), + (0xFC38, "M", "كج"), + (0xFC39, "M", "كح"), + (0xFC3A, "M", "كخ"), + (0xFC3B, "M", "كل"), + (0xFC3C, "M", "كم"), + (0xFC3D, "M", "كى"), + (0xFC3E, "M", "كي"), + (0xFC3F, "M", "لج"), + (0xFC40, "M", "لح"), + (0xFC41, "M", "لخ"), + (0xFC42, "M", "لم"), + (0xFC43, "M", "لى"), + (0xFC44, "M", "لي"), + (0xFC45, "M", "مج"), + (0xFC46, "M", "مح"), + (0xFC47, "M", "مخ"), + (0xFC48, "M", "مم"), + (0xFC49, "M", "مى"), + (0xFC4A, "M", "مي"), + (0xFC4B, "M", "نج"), + (0xFC4C, "M", "نح"), + (0xFC4D, "M", "نخ"), + (0xFC4E, "M", "نم"), + (0xFC4F, "M", "نى"), + (0xFC50, "M", "ني"), + (0xFC51, "M", "هج"), + (0xFC52, "M", "هم"), + (0xFC53, "M", "هى"), + (0xFC54, "M", "هي"), + (0xFC55, "M", "يج"), + (0xFC56, "M", "يح"), + (0xFC57, "M", "يخ"), + (0xFC58, "M", "يم"), + (0xFC59, "M", "يى"), + (0xFC5A, "M", "يي"), + ] + + +def _seg_46() -> List[Union[Tuple[int, str], Tuple[int, str, str]]]: + return [ + (0xFC5B, "M", "ذٰ"), + (0xFC5C, "M", "رٰ"), + (0xFC5D, "M", "ىٰ"), + (0xFC5E, "3", " ٌّ"), + (0xFC5F, "3", " ٍّ"), + (0xFC60, "3", " َّ"), + (0xFC61, "3", " ُّ"), + (0xFC62, "3", " ِّ"), + (0xFC63, "3", " ّٰ"), + (0xFC64, "M", "ئر"), + (0xFC65, "M", "ئز"), + (0xFC66, "M", "ئم"), + (0xFC67, "M", "ئن"), + (0xFC68, "M", "ئى"), + (0xFC69, "M", "ئي"), + (0xFC6A, "M", "بر"), + (0xFC6B, "M", "بز"), + (0xFC6C, "M", "بم"), + (0xFC6D, "M", "بن"), + (0xFC6E, "M", "بى"), + (0xFC6F, "M", "بي"), + (0xFC70, "M", "تر"), + (0xFC71, "M", "تز"), + (0xFC72, "M", "تم"), + (0xFC73, "M", "تن"), + (0xFC74, "M", "تى"), + (0xFC75, "M", "تي"), + (0xFC76, "M", "ثر"), + (0xFC77, "M", "ثز"), + (0xFC78, "M", "ثم"), + (0xFC79, "M", "ثن"), + (0xFC7A, "M", "ثى"), + (0xFC7B, "M", "ثي"), + (0xFC7C, "M", "فى"), + (0xFC7D, "M", "في"), + (0xFC7E, "M", "قى"), + (0xFC7F, "M", "قي"), + (0xFC80, "M", "كا"), + (0xFC81, "M", "كل"), + (0xFC82, "M", "كم"), + (0xFC83, "M", "كى"), + (0xFC84, "M", "كي"), + (0xFC85, "M", "لم"), + (0xFC86, "M", "لى"), + (0xFC87, "M", "لي"), + (0xFC88, "M", "ما"), + (0xFC89, "M", "مم"), + (0xFC8A, "M", "نر"), + (0xFC8B, "M", "نز"), + (0xFC8C, "M", "نم"), + (0xFC8D, "M", "نن"), + (0xFC8E, "M", "نى"), + (0xFC8F, "M", "ني"), + (0xFC90, "M", "ىٰ"), + (0xFC91, "M", "ير"), + (0xFC92, "M", "يز"), + (0xFC93, "M", "يم"), + (0xFC94, "M", "ين"), + (0xFC95, "M", "يى"), + (0xFC96, "M", "يي"), + (0xFC97, "M", "ئج"), + (0xFC98, "M", "ئح"), + (0xFC99, "M", "ئخ"), + (0xFC9A, "M", "ئم"), + (0xFC9B, "M", "ئه"), + (0xFC9C, "M", "بج"), + (0xFC9D, "M", "بح"), + (0xFC9E, "M", "بخ"), + (0xFC9F, "M", "بم"), + (0xFCA0, "M", "به"), + (0xFCA1, "M", "تج"), + (0xFCA2, "M", "تح"), + (0xFCA3, "M", "تخ"), + (0xFCA4, "M", "تم"), + (0xFCA5, "M", "ته"), + (0xFCA6, "M", "ثم"), + (0xFCA7, "M", "جح"), + (0xFCA8, "M", "جم"), + (0xFCA9, "M", "حج"), + (0xFCAA, "M", "حم"), + (0xFCAB, "M", "خج"), + (0xFCAC, "M", "خم"), + (0xFCAD, "M", "سج"), + (0xFCAE, "M", "سح"), + (0xFCAF, "M", "سخ"), + (0xFCB0, "M", "سم"), + (0xFCB1, "M", "صح"), + (0xFCB2, "M", "صخ"), + (0xFCB3, "M", "صم"), + (0xFCB4, "M", "ضج"), + (0xFCB5, "M", "ضح"), + (0xFCB6, "M", "ضخ"), + (0xFCB7, "M", "ضم"), + (0xFCB8, "M", "طح"), + (0xFCB9, "M", "ظم"), + (0xFCBA, "M", "عج"), + (0xFCBB, "M", "عم"), + (0xFCBC, "M", "غج"), + (0xFCBD, "M", "غم"), + (0xFCBE, "M", "فج"), + ] + + +def _seg_47() -> List[Union[Tuple[int, str], Tuple[int, str, str]]]: + return [ + (0xFCBF, "M", "فح"), + (0xFCC0, "M", "فخ"), + (0xFCC1, "M", "فم"), + (0xFCC2, "M", "قح"), + (0xFCC3, "M", "قم"), + (0xFCC4, "M", "كج"), + (0xFCC5, "M", "كح"), + (0xFCC6, "M", "كخ"), + (0xFCC7, "M", "كل"), + (0xFCC8, "M", "كم"), + (0xFCC9, "M", "لج"), + (0xFCCA, "M", "لح"), + (0xFCCB, "M", "لخ"), + (0xFCCC, "M", "لم"), + (0xFCCD, "M", "له"), + (0xFCCE, "M", "مج"), + (0xFCCF, "M", "مح"), + (0xFCD0, "M", "مخ"), + (0xFCD1, "M", "مم"), + (0xFCD2, "M", "نج"), + (0xFCD3, "M", "نح"), + (0xFCD4, "M", "نخ"), + (0xFCD5, "M", "نم"), + (0xFCD6, "M", "نه"), + (0xFCD7, "M", "هج"), + (0xFCD8, "M", "هم"), + (0xFCD9, "M", "هٰ"), + (0xFCDA, "M", "يج"), + (0xFCDB, "M", "يح"), + (0xFCDC, "M", "يخ"), + (0xFCDD, "M", "يم"), + (0xFCDE, "M", "يه"), + (0xFCDF, "M", "ئم"), + (0xFCE0, "M", "ئه"), + (0xFCE1, "M", "بم"), + (0xFCE2, "M", "به"), + (0xFCE3, "M", "تم"), + (0xFCE4, "M", "ته"), + (0xFCE5, "M", "ثم"), + (0xFCE6, "M", "ثه"), + (0xFCE7, "M", "سم"), + (0xFCE8, "M", "سه"), + (0xFCE9, "M", "شم"), + (0xFCEA, "M", "شه"), + (0xFCEB, "M", "كل"), + (0xFCEC, "M", "كم"), + (0xFCED, "M", "لم"), + (0xFCEE, "M", "نم"), + (0xFCEF, "M", "نه"), + (0xFCF0, "M", "يم"), + (0xFCF1, "M", "يه"), + (0xFCF2, "M", "ـَّ"), + (0xFCF3, "M", "ـُّ"), + (0xFCF4, "M", "ـِّ"), + (0xFCF5, "M", "طى"), + (0xFCF6, "M", "طي"), + (0xFCF7, "M", "عى"), + (0xFCF8, "M", "عي"), + (0xFCF9, "M", "غى"), + (0xFCFA, "M", "غي"), + (0xFCFB, "M", "سى"), + (0xFCFC, "M", "سي"), + (0xFCFD, "M", "شى"), + (0xFCFE, "M", "شي"), + (0xFCFF, "M", "حى"), + (0xFD00, "M", "حي"), + (0xFD01, "M", "جى"), + (0xFD02, "M", "جي"), + (0xFD03, "M", "خى"), + (0xFD04, "M", "خي"), + (0xFD05, "M", "صى"), + (0xFD06, "M", "صي"), + (0xFD07, "M", "ضى"), + (0xFD08, "M", "ضي"), + (0xFD09, "M", "شج"), + (0xFD0A, "M", "شح"), + (0xFD0B, "M", "شخ"), + (0xFD0C, "M", "شم"), + (0xFD0D, "M", "شر"), + (0xFD0E, "M", "سر"), + (0xFD0F, "M", "صر"), + (0xFD10, "M", "ضر"), + (0xFD11, "M", "طى"), + (0xFD12, "M", "طي"), + (0xFD13, "M", "عى"), + (0xFD14, "M", "عي"), + (0xFD15, "M", "غى"), + (0xFD16, "M", "غي"), + (0xFD17, "M", "سى"), + (0xFD18, "M", "سي"), + (0xFD19, "M", "شى"), + (0xFD1A, "M", "شي"), + (0xFD1B, "M", "حى"), + (0xFD1C, "M", "حي"), + (0xFD1D, "M", "جى"), + (0xFD1E, "M", "جي"), + (0xFD1F, "M", "خى"), + (0xFD20, "M", "خي"), + (0xFD21, "M", "صى"), + (0xFD22, "M", "صي"), + ] + + +def _seg_48() -> List[Union[Tuple[int, str], Tuple[int, str, str]]]: + return [ + (0xFD23, "M", "ضى"), + (0xFD24, "M", "ضي"), + (0xFD25, "M", "شج"), + (0xFD26, "M", "شح"), + (0xFD27, "M", "شخ"), + (0xFD28, "M", "شم"), + (0xFD29, "M", "شر"), + (0xFD2A, "M", "سر"), + (0xFD2B, "M", "صر"), + (0xFD2C, "M", "ضر"), + (0xFD2D, "M", "شج"), + (0xFD2E, "M", "شح"), + (0xFD2F, "M", "شخ"), + (0xFD30, "M", "شم"), + (0xFD31, "M", "سه"), + (0xFD32, "M", "شه"), + (0xFD33, "M", "طم"), + (0xFD34, "M", "سج"), + (0xFD35, "M", "سح"), + (0xFD36, "M", "سخ"), + (0xFD37, "M", "شج"), + (0xFD38, "M", "شح"), + (0xFD39, "M", "شخ"), + (0xFD3A, "M", "طم"), + (0xFD3B, "M", "ظم"), + (0xFD3C, "M", "اً"), + (0xFD3E, "V"), + (0xFD50, "M", "تجم"), + (0xFD51, "M", "تحج"), + (0xFD53, "M", "تحم"), + (0xFD54, "M", "تخم"), + (0xFD55, "M", "تمج"), + (0xFD56, "M", "تمح"), + (0xFD57, "M", "تمخ"), + (0xFD58, "M", "جمح"), + (0xFD5A, "M", "حمي"), + (0xFD5B, "M", "حمى"), + (0xFD5C, "M", "سحج"), + (0xFD5D, "M", "سجح"), + (0xFD5E, "M", "سجى"), + (0xFD5F, "M", "سمح"), + (0xFD61, "M", "سمج"), + (0xFD62, "M", "سمم"), + (0xFD64, "M", "صحح"), + (0xFD66, "M", "صمم"), + (0xFD67, "M", "شحم"), + (0xFD69, "M", "شجي"), + (0xFD6A, "M", "شمخ"), + (0xFD6C, "M", "شمم"), + (0xFD6E, "M", "ضحى"), + (0xFD6F, "M", "ضخم"), + (0xFD71, "M", "طمح"), + (0xFD73, "M", "طمم"), + (0xFD74, "M", "طمي"), + (0xFD75, "M", "عجم"), + (0xFD76, "M", "عمم"), + (0xFD78, "M", "عمى"), + (0xFD79, "M", "غمم"), + (0xFD7A, "M", "غمي"), + (0xFD7B, "M", "غمى"), + (0xFD7C, "M", "فخم"), + (0xFD7E, "M", "قمح"), + (0xFD7F, "M", "قمم"), + (0xFD80, "M", "لحم"), + (0xFD81, "M", "لحي"), + (0xFD82, "M", "لحى"), + (0xFD83, "M", "لجج"), + (0xFD85, "M", "لخم"), + (0xFD87, "M", "لمح"), + (0xFD89, "M", "محج"), + (0xFD8A, "M", "محم"), + (0xFD8B, "M", "محي"), + (0xFD8C, "M", "مجح"), + (0xFD8D, "M", "مجم"), + (0xFD8E, "M", "مخج"), + (0xFD8F, "M", "مخم"), + (0xFD90, "X"), + (0xFD92, "M", "مجخ"), + (0xFD93, "M", "همج"), + (0xFD94, "M", "همم"), + (0xFD95, "M", "نحم"), + (0xFD96, "M", "نحى"), + (0xFD97, "M", "نجم"), + (0xFD99, "M", "نجى"), + (0xFD9A, "M", "نمي"), + (0xFD9B, "M", "نمى"), + (0xFD9C, "M", "يمم"), + (0xFD9E, "M", "بخي"), + (0xFD9F, "M", "تجي"), + (0xFDA0, "M", "تجى"), + (0xFDA1, "M", "تخي"), + (0xFDA2, "M", "تخى"), + (0xFDA3, "M", "تمي"), + (0xFDA4, "M", "تمى"), + (0xFDA5, "M", "جمي"), + (0xFDA6, "M", "جحى"), + (0xFDA7, "M", "جمى"), + (0xFDA8, "M", "سخى"), + (0xFDA9, "M", "صحي"), + (0xFDAA, "M", "شحي"), + ] + + +def _seg_49() -> List[Union[Tuple[int, str], Tuple[int, str, str]]]: + return [ + (0xFDAB, "M", "ضحي"), + (0xFDAC, "M", "لجي"), + (0xFDAD, "M", "لمي"), + (0xFDAE, "M", "يحي"), + (0xFDAF, "M", "يجي"), + (0xFDB0, "M", "يمي"), + (0xFDB1, "M", "ممي"), + (0xFDB2, "M", "قمي"), + (0xFDB3, "M", "نحي"), + (0xFDB4, "M", "قمح"), + (0xFDB5, "M", "لحم"), + (0xFDB6, "M", "عمي"), + (0xFDB7, "M", "كمي"), + (0xFDB8, "M", "نجح"), + (0xFDB9, "M", "مخي"), + (0xFDBA, "M", "لجم"), + (0xFDBB, "M", "كمم"), + (0xFDBC, "M", "لجم"), + (0xFDBD, "M", "نجح"), + (0xFDBE, "M", "جحي"), + (0xFDBF, "M", "حجي"), + (0xFDC0, "M", "مجي"), + (0xFDC1, "M", "فمي"), + (0xFDC2, "M", "بحي"), + (0xFDC3, "M", "كمم"), + (0xFDC4, "M", "عجم"), + (0xFDC5, "M", "صمم"), + (0xFDC6, "M", "سخي"), + (0xFDC7, "M", "نجي"), + (0xFDC8, "X"), + (0xFDCF, "V"), + (0xFDD0, "X"), + (0xFDF0, "M", "صلے"), + (0xFDF1, "M", "قلے"), + (0xFDF2, "M", "الله"), + (0xFDF3, "M", "اكبر"), + (0xFDF4, "M", "محمد"), + (0xFDF5, "M", "صلعم"), + (0xFDF6, "M", "رسول"), + (0xFDF7, "M", "عليه"), + (0xFDF8, "M", "وسلم"), + (0xFDF9, "M", "صلى"), + (0xFDFA, "3", "صلى الله عليه وسلم"), + (0xFDFB, "3", "جل جلاله"), + (0xFDFC, "M", "ریال"), + (0xFDFD, "V"), + (0xFE00, "I"), + (0xFE10, "3", ","), + (0xFE11, "M", "、"), + (0xFE12, "X"), + (0xFE13, "3", ":"), + (0xFE14, "3", ";"), + (0xFE15, "3", "!"), + (0xFE16, "3", "?"), + (0xFE17, "M", "〖"), + (0xFE18, "M", "〗"), + (0xFE19, "X"), + (0xFE20, "V"), + (0xFE30, "X"), + (0xFE31, "M", "—"), + (0xFE32, "M", "–"), + (0xFE33, "3", "_"), + (0xFE35, "3", "("), + (0xFE36, "3", ")"), + (0xFE37, "3", "{"), + (0xFE38, "3", "}"), + (0xFE39, "M", "〔"), + (0xFE3A, "M", "〕"), + (0xFE3B, "M", "【"), + (0xFE3C, "M", "】"), + (0xFE3D, "M", "《"), + (0xFE3E, "M", "》"), + (0xFE3F, "M", "〈"), + (0xFE40, "M", "〉"), + (0xFE41, "M", "「"), + (0xFE42, "M", "」"), + (0xFE43, "M", "『"), + (0xFE44, "M", "』"), + (0xFE45, "V"), + (0xFE47, "3", "["), + (0xFE48, "3", "]"), + (0xFE49, "3", " ̅"), + (0xFE4D, "3", "_"), + (0xFE50, "3", ","), + (0xFE51, "M", "、"), + (0xFE52, "X"), + (0xFE54, "3", ";"), + (0xFE55, "3", ":"), + (0xFE56, "3", "?"), + (0xFE57, "3", "!"), + (0xFE58, "M", "—"), + (0xFE59, "3", "("), + (0xFE5A, "3", ")"), + (0xFE5B, "3", "{"), + (0xFE5C, "3", "}"), + (0xFE5D, "M", "〔"), + (0xFE5E, "M", "〕"), + (0xFE5F, "3", "#"), + (0xFE60, "3", "&"), + (0xFE61, "3", "*"), + ] + + +def _seg_50() -> List[Union[Tuple[int, str], Tuple[int, str, str]]]: + return [ + (0xFE62, "3", "+"), + (0xFE63, "M", "-"), + (0xFE64, "3", "<"), + (0xFE65, "3", ">"), + (0xFE66, "3", "="), + (0xFE67, "X"), + (0xFE68, "3", "\\"), + (0xFE69, "3", "$"), + (0xFE6A, "3", "%"), + (0xFE6B, "3", "@"), + (0xFE6C, "X"), + (0xFE70, "3", " ً"), + (0xFE71, "M", "ـً"), + (0xFE72, "3", " ٌ"), + (0xFE73, "V"), + (0xFE74, "3", " ٍ"), + (0xFE75, "X"), + (0xFE76, "3", " َ"), + (0xFE77, "M", "ـَ"), + (0xFE78, "3", " ُ"), + (0xFE79, "M", "ـُ"), + (0xFE7A, "3", " ِ"), + (0xFE7B, "M", "ـِ"), + (0xFE7C, "3", " ّ"), + (0xFE7D, "M", "ـّ"), + (0xFE7E, "3", " ْ"), + (0xFE7F, "M", "ـْ"), + (0xFE80, "M", "ء"), + (0xFE81, "M", "آ"), + (0xFE83, "M", "أ"), + (0xFE85, "M", "ؤ"), + (0xFE87, "M", "إ"), + (0xFE89, "M", "ئ"), + (0xFE8D, "M", "ا"), + (0xFE8F, "M", "ب"), + (0xFE93, "M", "ة"), + (0xFE95, "M", "ت"), + (0xFE99, "M", "ث"), + (0xFE9D, "M", "ج"), + (0xFEA1, "M", "ح"), + (0xFEA5, "M", "خ"), + (0xFEA9, "M", "د"), + (0xFEAB, "M", "ذ"), + (0xFEAD, "M", "ر"), + (0xFEAF, "M", "ز"), + (0xFEB1, "M", "س"), + (0xFEB5, "M", "ش"), + (0xFEB9, "M", "ص"), + (0xFEBD, "M", "ض"), + (0xFEC1, "M", "ط"), + (0xFEC5, "M", "ظ"), + (0xFEC9, "M", "ع"), + (0xFECD, "M", "غ"), + (0xFED1, "M", "ف"), + (0xFED5, "M", "ق"), + (0xFED9, "M", "ك"), + (0xFEDD, "M", "ل"), + (0xFEE1, "M", "م"), + (0xFEE5, "M", "ن"), + (0xFEE9, "M", "ه"), + (0xFEED, "M", "و"), + (0xFEEF, "M", "ى"), + (0xFEF1, "M", "ي"), + (0xFEF5, "M", "لآ"), + (0xFEF7, "M", "لأ"), + (0xFEF9, "M", "لإ"), + (0xFEFB, "M", "لا"), + (0xFEFD, "X"), + (0xFEFF, "I"), + (0xFF00, "X"), + (0xFF01, "3", "!"), + (0xFF02, "3", '"'), + (0xFF03, "3", "#"), + (0xFF04, "3", "$"), + (0xFF05, "3", "%"), + (0xFF06, "3", "&"), + (0xFF07, "3", "'"), + (0xFF08, "3", "("), + (0xFF09, "3", ")"), + (0xFF0A, "3", "*"), + (0xFF0B, "3", "+"), + (0xFF0C, "3", ","), + (0xFF0D, "M", "-"), + (0xFF0E, "M", "."), + (0xFF0F, "3", "/"), + (0xFF10, "M", "0"), + (0xFF11, "M", "1"), + (0xFF12, "M", "2"), + (0xFF13, "M", "3"), + (0xFF14, "M", "4"), + (0xFF15, "M", "5"), + (0xFF16, "M", "6"), + (0xFF17, "M", "7"), + (0xFF18, "M", "8"), + (0xFF19, "M", "9"), + (0xFF1A, "3", ":"), + (0xFF1B, "3", ";"), + (0xFF1C, "3", "<"), + (0xFF1D, "3", "="), + (0xFF1E, "3", ">"), + ] + + +def _seg_51() -> List[Union[Tuple[int, str], Tuple[int, str, str]]]: + return [ + (0xFF1F, "3", "?"), + (0xFF20, "3", "@"), + (0xFF21, "M", "a"), + (0xFF22, "M", "b"), + (0xFF23, "M", "c"), + (0xFF24, "M", "d"), + (0xFF25, "M", "e"), + (0xFF26, "M", "f"), + (0xFF27, "M", "g"), + (0xFF28, "M", "h"), + (0xFF29, "M", "i"), + (0xFF2A, "M", "j"), + (0xFF2B, "M", "k"), + (0xFF2C, "M", "l"), + (0xFF2D, "M", "m"), + (0xFF2E, "M", "n"), + (0xFF2F, "M", "o"), + (0xFF30, "M", "p"), + (0xFF31, "M", "q"), + (0xFF32, "M", "r"), + (0xFF33, "M", "s"), + (0xFF34, "M", "t"), + (0xFF35, "M", "u"), + (0xFF36, "M", "v"), + (0xFF37, "M", "w"), + (0xFF38, "M", "x"), + (0xFF39, "M", "y"), + (0xFF3A, "M", "z"), + (0xFF3B, "3", "["), + (0xFF3C, "3", "\\"), + (0xFF3D, "3", "]"), + (0xFF3E, "3", "^"), + (0xFF3F, "3", "_"), + (0xFF40, "3", "`"), + (0xFF41, "M", "a"), + (0xFF42, "M", "b"), + (0xFF43, "M", "c"), + (0xFF44, "M", "d"), + (0xFF45, "M", "e"), + (0xFF46, "M", "f"), + (0xFF47, "M", "g"), + (0xFF48, "M", "h"), + (0xFF49, "M", "i"), + (0xFF4A, "M", "j"), + (0xFF4B, "M", "k"), + (0xFF4C, "M", "l"), + (0xFF4D, "M", "m"), + (0xFF4E, "M", "n"), + (0xFF4F, "M", "o"), + (0xFF50, "M", "p"), + (0xFF51, "M", "q"), + (0xFF52, "M", "r"), + (0xFF53, "M", "s"), + (0xFF54, "M", "t"), + (0xFF55, "M", "u"), + (0xFF56, "M", "v"), + (0xFF57, "M", "w"), + (0xFF58, "M", "x"), + (0xFF59, "M", "y"), + (0xFF5A, "M", "z"), + (0xFF5B, "3", "{"), + (0xFF5C, "3", "|"), + (0xFF5D, "3", "}"), + (0xFF5E, "3", "~"), + (0xFF5F, "M", "⦅"), + (0xFF60, "M", "⦆"), + (0xFF61, "M", "."), + (0xFF62, "M", "「"), + (0xFF63, "M", "」"), + (0xFF64, "M", "、"), + (0xFF65, "M", "・"), + (0xFF66, "M", "ヲ"), + (0xFF67, "M", "ァ"), + (0xFF68, "M", "ィ"), + (0xFF69, "M", "ゥ"), + (0xFF6A, "M", "ェ"), + (0xFF6B, "M", "ォ"), + (0xFF6C, "M", "ャ"), + (0xFF6D, "M", "ュ"), + (0xFF6E, "M", "ョ"), + (0xFF6F, "M", "ッ"), + (0xFF70, "M", "ー"), + (0xFF71, "M", "ア"), + (0xFF72, "M", "イ"), + (0xFF73, "M", "ウ"), + (0xFF74, "M", "エ"), + (0xFF75, "M", "オ"), + (0xFF76, "M", "カ"), + (0xFF77, "M", "キ"), + (0xFF78, "M", "ク"), + (0xFF79, "M", "ケ"), + (0xFF7A, "M", "コ"), + (0xFF7B, "M", "サ"), + (0xFF7C, "M", "シ"), + (0xFF7D, "M", "ス"), + (0xFF7E, "M", "セ"), + (0xFF7F, "M", "ソ"), + (0xFF80, "M", "タ"), + (0xFF81, "M", "チ"), + (0xFF82, "M", "ツ"), + ] + + +def _seg_52() -> List[Union[Tuple[int, str], Tuple[int, str, str]]]: + return [ + (0xFF83, "M", "テ"), + (0xFF84, "M", "ト"), + (0xFF85, "M", "ナ"), + (0xFF86, "M", "ニ"), + (0xFF87, "M", "ヌ"), + (0xFF88, "M", "ネ"), + (0xFF89, "M", "ノ"), + (0xFF8A, "M", "ハ"), + (0xFF8B, "M", "ヒ"), + (0xFF8C, "M", "フ"), + (0xFF8D, "M", "ヘ"), + (0xFF8E, "M", "ホ"), + (0xFF8F, "M", "マ"), + (0xFF90, "M", "ミ"), + (0xFF91, "M", "ム"), + (0xFF92, "M", "メ"), + (0xFF93, "M", "モ"), + (0xFF94, "M", "ヤ"), + (0xFF95, "M", "ユ"), + (0xFF96, "M", "ヨ"), + (0xFF97, "M", "ラ"), + (0xFF98, "M", "リ"), + (0xFF99, "M", "ル"), + (0xFF9A, "M", "レ"), + (0xFF9B, "M", "ロ"), + (0xFF9C, "M", "ワ"), + (0xFF9D, "M", "ン"), + (0xFF9E, "M", "゙"), + (0xFF9F, "M", "゚"), + (0xFFA0, "X"), + (0xFFA1, "M", "ᄀ"), + (0xFFA2, "M", "ᄁ"), + (0xFFA3, "M", "ᆪ"), + (0xFFA4, "M", "ᄂ"), + (0xFFA5, "M", "ᆬ"), + (0xFFA6, "M", "ᆭ"), + (0xFFA7, "M", "ᄃ"), + (0xFFA8, "M", "ᄄ"), + (0xFFA9, "M", "ᄅ"), + (0xFFAA, "M", "ᆰ"), + (0xFFAB, "M", "ᆱ"), + (0xFFAC, "M", "ᆲ"), + (0xFFAD, "M", "ᆳ"), + (0xFFAE, "M", "ᆴ"), + (0xFFAF, "M", "ᆵ"), + (0xFFB0, "M", "ᄚ"), + (0xFFB1, "M", "ᄆ"), + (0xFFB2, "M", "ᄇ"), + (0xFFB3, "M", "ᄈ"), + (0xFFB4, "M", "ᄡ"), + (0xFFB5, "M", "ᄉ"), + (0xFFB6, "M", "ᄊ"), + (0xFFB7, "M", "ᄋ"), + (0xFFB8, "M", "ᄌ"), + (0xFFB9, "M", "ᄍ"), + (0xFFBA, "M", "ᄎ"), + (0xFFBB, "M", "ᄏ"), + (0xFFBC, "M", "ᄐ"), + (0xFFBD, "M", "ᄑ"), + (0xFFBE, "M", "ᄒ"), + (0xFFBF, "X"), + (0xFFC2, "M", "ᅡ"), + (0xFFC3, "M", "ᅢ"), + (0xFFC4, "M", "ᅣ"), + (0xFFC5, "M", "ᅤ"), + (0xFFC6, "M", "ᅥ"), + (0xFFC7, "M", "ᅦ"), + (0xFFC8, "X"), + (0xFFCA, "M", "ᅧ"), + (0xFFCB, "M", "ᅨ"), + (0xFFCC, "M", "ᅩ"), + (0xFFCD, "M", "ᅪ"), + (0xFFCE, "M", "ᅫ"), + (0xFFCF, "M", "ᅬ"), + (0xFFD0, "X"), + (0xFFD2, "M", "ᅭ"), + (0xFFD3, "M", "ᅮ"), + (0xFFD4, "M", "ᅯ"), + (0xFFD5, "M", "ᅰ"), + (0xFFD6, "M", "ᅱ"), + (0xFFD7, "M", "ᅲ"), + (0xFFD8, "X"), + (0xFFDA, "M", "ᅳ"), + (0xFFDB, "M", "ᅴ"), + (0xFFDC, "M", "ᅵ"), + (0xFFDD, "X"), + (0xFFE0, "M", "¢"), + (0xFFE1, "M", "£"), + (0xFFE2, "M", "¬"), + (0xFFE3, "3", " ̄"), + (0xFFE4, "M", "¦"), + (0xFFE5, "M", "¥"), + (0xFFE6, "M", "₩"), + (0xFFE7, "X"), + (0xFFE8, "M", "│"), + (0xFFE9, "M", "←"), + (0xFFEA, "M", "↑"), + (0xFFEB, "M", "→"), + (0xFFEC, "M", "↓"), + (0xFFED, "M", "■"), + ] + + +def _seg_53() -> List[Union[Tuple[int, str], Tuple[int, str, str]]]: + return [ + (0xFFEE, "M", "○"), + (0xFFEF, "X"), + (0x10000, "V"), + (0x1000C, "X"), + (0x1000D, "V"), + (0x10027, "X"), + (0x10028, "V"), + (0x1003B, "X"), + (0x1003C, "V"), + (0x1003E, "X"), + (0x1003F, "V"), + (0x1004E, "X"), + (0x10050, "V"), + (0x1005E, "X"), + (0x10080, "V"), + (0x100FB, "X"), + (0x10100, "V"), + (0x10103, "X"), + (0x10107, "V"), + (0x10134, "X"), + (0x10137, "V"), + (0x1018F, "X"), + (0x10190, "V"), + (0x1019D, "X"), + (0x101A0, "V"), + (0x101A1, "X"), + (0x101D0, "V"), + (0x101FE, "X"), + (0x10280, "V"), + (0x1029D, "X"), + (0x102A0, "V"), + (0x102D1, "X"), + (0x102E0, "V"), + (0x102FC, "X"), + (0x10300, "V"), + (0x10324, "X"), + (0x1032D, "V"), + (0x1034B, "X"), + (0x10350, "V"), + (0x1037B, "X"), + (0x10380, "V"), + (0x1039E, "X"), + (0x1039F, "V"), + (0x103C4, "X"), + (0x103C8, "V"), + (0x103D6, "X"), + (0x10400, "M", "𐐨"), + (0x10401, "M", "𐐩"), + (0x10402, "M", "𐐪"), + (0x10403, "M", "𐐫"), + (0x10404, "M", "𐐬"), + (0x10405, "M", "𐐭"), + (0x10406, "M", "𐐮"), + (0x10407, "M", "𐐯"), + (0x10408, "M", "𐐰"), + (0x10409, "M", "𐐱"), + (0x1040A, "M", "𐐲"), + (0x1040B, "M", "𐐳"), + (0x1040C, "M", "𐐴"), + (0x1040D, "M", "𐐵"), + (0x1040E, "M", "𐐶"), + (0x1040F, "M", "𐐷"), + (0x10410, "M", "𐐸"), + (0x10411, "M", "𐐹"), + (0x10412, "M", "𐐺"), + (0x10413, "M", "𐐻"), + (0x10414, "M", "𐐼"), + (0x10415, "M", "𐐽"), + (0x10416, "M", "𐐾"), + (0x10417, "M", "𐐿"), + (0x10418, "M", "𐑀"), + (0x10419, "M", "𐑁"), + (0x1041A, "M", "𐑂"), + (0x1041B, "M", "𐑃"), + (0x1041C, "M", "𐑄"), + (0x1041D, "M", "𐑅"), + (0x1041E, "M", "𐑆"), + (0x1041F, "M", "𐑇"), + (0x10420, "M", "𐑈"), + (0x10421, "M", "𐑉"), + (0x10422, "M", "𐑊"), + (0x10423, "M", "𐑋"), + (0x10424, "M", "𐑌"), + (0x10425, "M", "𐑍"), + (0x10426, "M", "𐑎"), + (0x10427, "M", "𐑏"), + (0x10428, "V"), + (0x1049E, "X"), + (0x104A0, "V"), + (0x104AA, "X"), + (0x104B0, "M", "𐓘"), + (0x104B1, "M", "𐓙"), + (0x104B2, "M", "𐓚"), + (0x104B3, "M", "𐓛"), + (0x104B4, "M", "𐓜"), + (0x104B5, "M", "𐓝"), + (0x104B6, "M", "𐓞"), + (0x104B7, "M", "𐓟"), + (0x104B8, "M", "𐓠"), + (0x104B9, "M", "𐓡"), + ] + + +def _seg_54() -> List[Union[Tuple[int, str], Tuple[int, str, str]]]: + return [ + (0x104BA, "M", "𐓢"), + (0x104BB, "M", "𐓣"), + (0x104BC, "M", "𐓤"), + (0x104BD, "M", "𐓥"), + (0x104BE, "M", "𐓦"), + (0x104BF, "M", "𐓧"), + (0x104C0, "M", "𐓨"), + (0x104C1, "M", "𐓩"), + (0x104C2, "M", "𐓪"), + (0x104C3, "M", "𐓫"), + (0x104C4, "M", "𐓬"), + (0x104C5, "M", "𐓭"), + (0x104C6, "M", "𐓮"), + (0x104C7, "M", "𐓯"), + (0x104C8, "M", "𐓰"), + (0x104C9, "M", "𐓱"), + (0x104CA, "M", "𐓲"), + (0x104CB, "M", "𐓳"), + (0x104CC, "M", "𐓴"), + (0x104CD, "M", "𐓵"), + (0x104CE, "M", "𐓶"), + (0x104CF, "M", "𐓷"), + (0x104D0, "M", "𐓸"), + (0x104D1, "M", "𐓹"), + (0x104D2, "M", "𐓺"), + (0x104D3, "M", "𐓻"), + (0x104D4, "X"), + (0x104D8, "V"), + (0x104FC, "X"), + (0x10500, "V"), + (0x10528, "X"), + (0x10530, "V"), + (0x10564, "X"), + (0x1056F, "V"), + (0x10570, "M", "𐖗"), + (0x10571, "M", "𐖘"), + (0x10572, "M", "𐖙"), + (0x10573, "M", "𐖚"), + (0x10574, "M", "𐖛"), + (0x10575, "M", "𐖜"), + (0x10576, "M", "𐖝"), + (0x10577, "M", "𐖞"), + (0x10578, "M", "𐖟"), + (0x10579, "M", "𐖠"), + (0x1057A, "M", "𐖡"), + (0x1057B, "X"), + (0x1057C, "M", "𐖣"), + (0x1057D, "M", "𐖤"), + (0x1057E, "M", "𐖥"), + (0x1057F, "M", "𐖦"), + (0x10580, "M", "𐖧"), + (0x10581, "M", "𐖨"), + (0x10582, "M", "𐖩"), + (0x10583, "M", "𐖪"), + (0x10584, "M", "𐖫"), + (0x10585, "M", "𐖬"), + (0x10586, "M", "𐖭"), + (0x10587, "M", "𐖮"), + (0x10588, "M", "𐖯"), + (0x10589, "M", "𐖰"), + (0x1058A, "M", "𐖱"), + (0x1058B, "X"), + (0x1058C, "M", "𐖳"), + (0x1058D, "M", "𐖴"), + (0x1058E, "M", "𐖵"), + (0x1058F, "M", "𐖶"), + (0x10590, "M", "𐖷"), + (0x10591, "M", "𐖸"), + (0x10592, "M", "𐖹"), + (0x10593, "X"), + (0x10594, "M", "𐖻"), + (0x10595, "M", "𐖼"), + (0x10596, "X"), + (0x10597, "V"), + (0x105A2, "X"), + (0x105A3, "V"), + (0x105B2, "X"), + (0x105B3, "V"), + (0x105BA, "X"), + (0x105BB, "V"), + (0x105BD, "X"), + (0x10600, "V"), + (0x10737, "X"), + (0x10740, "V"), + (0x10756, "X"), + (0x10760, "V"), + (0x10768, "X"), + (0x10780, "V"), + (0x10781, "M", "ː"), + (0x10782, "M", "ˑ"), + (0x10783, "M", "æ"), + (0x10784, "M", "ʙ"), + (0x10785, "M", "ɓ"), + (0x10786, "X"), + (0x10787, "M", "ʣ"), + (0x10788, "M", "ꭦ"), + (0x10789, "M", "ʥ"), + (0x1078A, "M", "ʤ"), + (0x1078B, "M", "ɖ"), + (0x1078C, "M", "ɗ"), + ] + + +def _seg_55() -> List[Union[Tuple[int, str], Tuple[int, str, str]]]: + return [ + (0x1078D, "M", "ᶑ"), + (0x1078E, "M", "ɘ"), + (0x1078F, "M", "ɞ"), + (0x10790, "M", "ʩ"), + (0x10791, "M", "ɤ"), + (0x10792, "M", "ɢ"), + (0x10793, "M", "ɠ"), + (0x10794, "M", "ʛ"), + (0x10795, "M", "ħ"), + (0x10796, "M", "ʜ"), + (0x10797, "M", "ɧ"), + (0x10798, "M", "ʄ"), + (0x10799, "M", "ʪ"), + (0x1079A, "M", "ʫ"), + (0x1079B, "M", "ɬ"), + (0x1079C, "M", "𝼄"), + (0x1079D, "M", "ꞎ"), + (0x1079E, "M", "ɮ"), + (0x1079F, "M", "𝼅"), + (0x107A0, "M", "ʎ"), + (0x107A1, "M", "𝼆"), + (0x107A2, "M", "ø"), + (0x107A3, "M", "ɶ"), + (0x107A4, "M", "ɷ"), + (0x107A5, "M", "q"), + (0x107A6, "M", "ɺ"), + (0x107A7, "M", "𝼈"), + (0x107A8, "M", "ɽ"), + (0x107A9, "M", "ɾ"), + (0x107AA, "M", "ʀ"), + (0x107AB, "M", "ʨ"), + (0x107AC, "M", "ʦ"), + (0x107AD, "M", "ꭧ"), + (0x107AE, "M", "ʧ"), + (0x107AF, "M", "ʈ"), + (0x107B0, "M", "ⱱ"), + (0x107B1, "X"), + (0x107B2, "M", "ʏ"), + (0x107B3, "M", "ʡ"), + (0x107B4, "M", "ʢ"), + (0x107B5, "M", "ʘ"), + (0x107B6, "M", "ǀ"), + (0x107B7, "M", "ǁ"), + (0x107B8, "M", "ǂ"), + (0x107B9, "M", "𝼊"), + (0x107BA, "M", "𝼞"), + (0x107BB, "X"), + (0x10800, "V"), + (0x10806, "X"), + (0x10808, "V"), + (0x10809, "X"), + (0x1080A, "V"), + (0x10836, "X"), + (0x10837, "V"), + (0x10839, "X"), + (0x1083C, "V"), + (0x1083D, "X"), + (0x1083F, "V"), + (0x10856, "X"), + (0x10857, "V"), + (0x1089F, "X"), + (0x108A7, "V"), + (0x108B0, "X"), + (0x108E0, "V"), + (0x108F3, "X"), + (0x108F4, "V"), + (0x108F6, "X"), + (0x108FB, "V"), + (0x1091C, "X"), + (0x1091F, "V"), + (0x1093A, "X"), + (0x1093F, "V"), + (0x10940, "X"), + (0x10980, "V"), + (0x109B8, "X"), + (0x109BC, "V"), + (0x109D0, "X"), + (0x109D2, "V"), + (0x10A04, "X"), + (0x10A05, "V"), + (0x10A07, "X"), + (0x10A0C, "V"), + (0x10A14, "X"), + (0x10A15, "V"), + (0x10A18, "X"), + (0x10A19, "V"), + (0x10A36, "X"), + (0x10A38, "V"), + (0x10A3B, "X"), + (0x10A3F, "V"), + (0x10A49, "X"), + (0x10A50, "V"), + (0x10A59, "X"), + (0x10A60, "V"), + (0x10AA0, "X"), + (0x10AC0, "V"), + (0x10AE7, "X"), + (0x10AEB, "V"), + (0x10AF7, "X"), + (0x10B00, "V"), + ] + + +def _seg_56() -> List[Union[Tuple[int, str], Tuple[int, str, str]]]: + return [ + (0x10B36, "X"), + (0x10B39, "V"), + (0x10B56, "X"), + (0x10B58, "V"), + (0x10B73, "X"), + (0x10B78, "V"), + (0x10B92, "X"), + (0x10B99, "V"), + (0x10B9D, "X"), + (0x10BA9, "V"), + (0x10BB0, "X"), + (0x10C00, "V"), + (0x10C49, "X"), + (0x10C80, "M", "𐳀"), + (0x10C81, "M", "𐳁"), + (0x10C82, "M", "𐳂"), + (0x10C83, "M", "𐳃"), + (0x10C84, "M", "𐳄"), + (0x10C85, "M", "𐳅"), + (0x10C86, "M", "𐳆"), + (0x10C87, "M", "𐳇"), + (0x10C88, "M", "𐳈"), + (0x10C89, "M", "𐳉"), + (0x10C8A, "M", "𐳊"), + (0x10C8B, "M", "𐳋"), + (0x10C8C, "M", "𐳌"), + (0x10C8D, "M", "𐳍"), + (0x10C8E, "M", "𐳎"), + (0x10C8F, "M", "𐳏"), + (0x10C90, "M", "𐳐"), + (0x10C91, "M", "𐳑"), + (0x10C92, "M", "𐳒"), + (0x10C93, "M", "𐳓"), + (0x10C94, "M", "𐳔"), + (0x10C95, "M", "𐳕"), + (0x10C96, "M", "𐳖"), + (0x10C97, "M", "𐳗"), + (0x10C98, "M", "𐳘"), + (0x10C99, "M", "𐳙"), + (0x10C9A, "M", "𐳚"), + (0x10C9B, "M", "𐳛"), + (0x10C9C, "M", "𐳜"), + (0x10C9D, "M", "𐳝"), + (0x10C9E, "M", "𐳞"), + (0x10C9F, "M", "𐳟"), + (0x10CA0, "M", "𐳠"), + (0x10CA1, "M", "𐳡"), + (0x10CA2, "M", "𐳢"), + (0x10CA3, "M", "𐳣"), + (0x10CA4, "M", "𐳤"), + (0x10CA5, "M", "𐳥"), + (0x10CA6, "M", "𐳦"), + (0x10CA7, "M", "𐳧"), + (0x10CA8, "M", "𐳨"), + (0x10CA9, "M", "𐳩"), + (0x10CAA, "M", "𐳪"), + (0x10CAB, "M", "𐳫"), + (0x10CAC, "M", "𐳬"), + (0x10CAD, "M", "𐳭"), + (0x10CAE, "M", "𐳮"), + (0x10CAF, "M", "𐳯"), + (0x10CB0, "M", "𐳰"), + (0x10CB1, "M", "𐳱"), + (0x10CB2, "M", "𐳲"), + (0x10CB3, "X"), + (0x10CC0, "V"), + (0x10CF3, "X"), + (0x10CFA, "V"), + (0x10D28, "X"), + (0x10D30, "V"), + (0x10D3A, "X"), + (0x10E60, "V"), + (0x10E7F, "X"), + (0x10E80, "V"), + (0x10EAA, "X"), + (0x10EAB, "V"), + (0x10EAE, "X"), + (0x10EB0, "V"), + (0x10EB2, "X"), + (0x10EFD, "V"), + (0x10F28, "X"), + (0x10F30, "V"), + (0x10F5A, "X"), + (0x10F70, "V"), + (0x10F8A, "X"), + (0x10FB0, "V"), + (0x10FCC, "X"), + (0x10FE0, "V"), + (0x10FF7, "X"), + (0x11000, "V"), + (0x1104E, "X"), + (0x11052, "V"), + (0x11076, "X"), + (0x1107F, "V"), + (0x110BD, "X"), + (0x110BE, "V"), + (0x110C3, "X"), + (0x110D0, "V"), + (0x110E9, "X"), + (0x110F0, "V"), + ] + + +def _seg_57() -> List[Union[Tuple[int, str], Tuple[int, str, str]]]: + return [ + (0x110FA, "X"), + (0x11100, "V"), + (0x11135, "X"), + (0x11136, "V"), + (0x11148, "X"), + (0x11150, "V"), + (0x11177, "X"), + (0x11180, "V"), + (0x111E0, "X"), + (0x111E1, "V"), + (0x111F5, "X"), + (0x11200, "V"), + (0x11212, "X"), + (0x11213, "V"), + (0x11242, "X"), + (0x11280, "V"), + (0x11287, "X"), + (0x11288, "V"), + (0x11289, "X"), + (0x1128A, "V"), + (0x1128E, "X"), + (0x1128F, "V"), + (0x1129E, "X"), + (0x1129F, "V"), + (0x112AA, "X"), + (0x112B0, "V"), + (0x112EB, "X"), + (0x112F0, "V"), + (0x112FA, "X"), + (0x11300, "V"), + (0x11304, "X"), + (0x11305, "V"), + (0x1130D, "X"), + (0x1130F, "V"), + (0x11311, "X"), + (0x11313, "V"), + (0x11329, "X"), + (0x1132A, "V"), + (0x11331, "X"), + (0x11332, "V"), + (0x11334, "X"), + (0x11335, "V"), + (0x1133A, "X"), + (0x1133B, "V"), + (0x11345, "X"), + (0x11347, "V"), + (0x11349, "X"), + (0x1134B, "V"), + (0x1134E, "X"), + (0x11350, "V"), + (0x11351, "X"), + (0x11357, "V"), + (0x11358, "X"), + (0x1135D, "V"), + (0x11364, "X"), + (0x11366, "V"), + (0x1136D, "X"), + (0x11370, "V"), + (0x11375, "X"), + (0x11400, "V"), + (0x1145C, "X"), + (0x1145D, "V"), + (0x11462, "X"), + (0x11480, "V"), + (0x114C8, "X"), + (0x114D0, "V"), + (0x114DA, "X"), + (0x11580, "V"), + (0x115B6, "X"), + (0x115B8, "V"), + (0x115DE, "X"), + (0x11600, "V"), + (0x11645, "X"), + (0x11650, "V"), + (0x1165A, "X"), + (0x11660, "V"), + (0x1166D, "X"), + (0x11680, "V"), + (0x116BA, "X"), + (0x116C0, "V"), + (0x116CA, "X"), + (0x11700, "V"), + (0x1171B, "X"), + (0x1171D, "V"), + (0x1172C, "X"), + (0x11730, "V"), + (0x11747, "X"), + (0x11800, "V"), + (0x1183C, "X"), + (0x118A0, "M", "𑣀"), + (0x118A1, "M", "𑣁"), + (0x118A2, "M", "𑣂"), + (0x118A3, "M", "𑣃"), + (0x118A4, "M", "𑣄"), + (0x118A5, "M", "𑣅"), + (0x118A6, "M", "𑣆"), + (0x118A7, "M", "𑣇"), + (0x118A8, "M", "𑣈"), + (0x118A9, "M", "𑣉"), + (0x118AA, "M", "𑣊"), + ] + + +def _seg_58() -> List[Union[Tuple[int, str], Tuple[int, str, str]]]: + return [ + (0x118AB, "M", "𑣋"), + (0x118AC, "M", "𑣌"), + (0x118AD, "M", "𑣍"), + (0x118AE, "M", "𑣎"), + (0x118AF, "M", "𑣏"), + (0x118B0, "M", "𑣐"), + (0x118B1, "M", "𑣑"), + (0x118B2, "M", "𑣒"), + (0x118B3, "M", "𑣓"), + (0x118B4, "M", "𑣔"), + (0x118B5, "M", "𑣕"), + (0x118B6, "M", "𑣖"), + (0x118B7, "M", "𑣗"), + (0x118B8, "M", "𑣘"), + (0x118B9, "M", "𑣙"), + (0x118BA, "M", "𑣚"), + (0x118BB, "M", "𑣛"), + (0x118BC, "M", "𑣜"), + (0x118BD, "M", "𑣝"), + (0x118BE, "M", "𑣞"), + (0x118BF, "M", "𑣟"), + (0x118C0, "V"), + (0x118F3, "X"), + (0x118FF, "V"), + (0x11907, "X"), + (0x11909, "V"), + (0x1190A, "X"), + (0x1190C, "V"), + (0x11914, "X"), + (0x11915, "V"), + (0x11917, "X"), + (0x11918, "V"), + (0x11936, "X"), + (0x11937, "V"), + (0x11939, "X"), + (0x1193B, "V"), + (0x11947, "X"), + (0x11950, "V"), + (0x1195A, "X"), + (0x119A0, "V"), + (0x119A8, "X"), + (0x119AA, "V"), + (0x119D8, "X"), + (0x119DA, "V"), + (0x119E5, "X"), + (0x11A00, "V"), + (0x11A48, "X"), + (0x11A50, "V"), + (0x11AA3, "X"), + (0x11AB0, "V"), + (0x11AF9, "X"), + (0x11B00, "V"), + (0x11B0A, "X"), + (0x11C00, "V"), + (0x11C09, "X"), + (0x11C0A, "V"), + (0x11C37, "X"), + (0x11C38, "V"), + (0x11C46, "X"), + (0x11C50, "V"), + (0x11C6D, "X"), + (0x11C70, "V"), + (0x11C90, "X"), + (0x11C92, "V"), + (0x11CA8, "X"), + (0x11CA9, "V"), + (0x11CB7, "X"), + (0x11D00, "V"), + (0x11D07, "X"), + (0x11D08, "V"), + (0x11D0A, "X"), + (0x11D0B, "V"), + (0x11D37, "X"), + (0x11D3A, "V"), + (0x11D3B, "X"), + (0x11D3C, "V"), + (0x11D3E, "X"), + (0x11D3F, "V"), + (0x11D48, "X"), + (0x11D50, "V"), + (0x11D5A, "X"), + (0x11D60, "V"), + (0x11D66, "X"), + (0x11D67, "V"), + (0x11D69, "X"), + (0x11D6A, "V"), + (0x11D8F, "X"), + (0x11D90, "V"), + (0x11D92, "X"), + (0x11D93, "V"), + (0x11D99, "X"), + (0x11DA0, "V"), + (0x11DAA, "X"), + (0x11EE0, "V"), + (0x11EF9, "X"), + (0x11F00, "V"), + (0x11F11, "X"), + (0x11F12, "V"), + (0x11F3B, "X"), + (0x11F3E, "V"), + ] + + +def _seg_59() -> List[Union[Tuple[int, str], Tuple[int, str, str]]]: + return [ + (0x11F5A, "X"), + (0x11FB0, "V"), + (0x11FB1, "X"), + (0x11FC0, "V"), + (0x11FF2, "X"), + (0x11FFF, "V"), + (0x1239A, "X"), + (0x12400, "V"), + (0x1246F, "X"), + (0x12470, "V"), + (0x12475, "X"), + (0x12480, "V"), + (0x12544, "X"), + (0x12F90, "V"), + (0x12FF3, "X"), + (0x13000, "V"), + (0x13430, "X"), + (0x13440, "V"), + (0x13456, "X"), + (0x14400, "V"), + (0x14647, "X"), + (0x16800, "V"), + (0x16A39, "X"), + (0x16A40, "V"), + (0x16A5F, "X"), + (0x16A60, "V"), + (0x16A6A, "X"), + (0x16A6E, "V"), + (0x16ABF, "X"), + (0x16AC0, "V"), + (0x16ACA, "X"), + (0x16AD0, "V"), + (0x16AEE, "X"), + (0x16AF0, "V"), + (0x16AF6, "X"), + (0x16B00, "V"), + (0x16B46, "X"), + (0x16B50, "V"), + (0x16B5A, "X"), + (0x16B5B, "V"), + (0x16B62, "X"), + (0x16B63, "V"), + (0x16B78, "X"), + (0x16B7D, "V"), + (0x16B90, "X"), + (0x16E40, "M", "𖹠"), + (0x16E41, "M", "𖹡"), + (0x16E42, "M", "𖹢"), + (0x16E43, "M", "𖹣"), + (0x16E44, "M", "𖹤"), + (0x16E45, "M", "𖹥"), + (0x16E46, "M", "𖹦"), + (0x16E47, "M", "𖹧"), + (0x16E48, "M", "𖹨"), + (0x16E49, "M", "𖹩"), + (0x16E4A, "M", "𖹪"), + (0x16E4B, "M", "𖹫"), + (0x16E4C, "M", "𖹬"), + (0x16E4D, "M", "𖹭"), + (0x16E4E, "M", "𖹮"), + (0x16E4F, "M", "𖹯"), + (0x16E50, "M", "𖹰"), + (0x16E51, "M", "𖹱"), + (0x16E52, "M", "𖹲"), + (0x16E53, "M", "𖹳"), + (0x16E54, "M", "𖹴"), + (0x16E55, "M", "𖹵"), + (0x16E56, "M", "𖹶"), + (0x16E57, "M", "𖹷"), + (0x16E58, "M", "𖹸"), + (0x16E59, "M", "𖹹"), + (0x16E5A, "M", "𖹺"), + (0x16E5B, "M", "𖹻"), + (0x16E5C, "M", "𖹼"), + (0x16E5D, "M", "𖹽"), + (0x16E5E, "M", "𖹾"), + (0x16E5F, "M", "𖹿"), + (0x16E60, "V"), + (0x16E9B, "X"), + (0x16F00, "V"), + (0x16F4B, "X"), + (0x16F4F, "V"), + (0x16F88, "X"), + (0x16F8F, "V"), + (0x16FA0, "X"), + (0x16FE0, "V"), + (0x16FE5, "X"), + (0x16FF0, "V"), + (0x16FF2, "X"), + (0x17000, "V"), + (0x187F8, "X"), + (0x18800, "V"), + (0x18CD6, "X"), + (0x18D00, "V"), + (0x18D09, "X"), + (0x1AFF0, "V"), + (0x1AFF4, "X"), + (0x1AFF5, "V"), + (0x1AFFC, "X"), + (0x1AFFD, "V"), + ] + + +def _seg_60() -> List[Union[Tuple[int, str], Tuple[int, str, str]]]: + return [ + (0x1AFFF, "X"), + (0x1B000, "V"), + (0x1B123, "X"), + (0x1B132, "V"), + (0x1B133, "X"), + (0x1B150, "V"), + (0x1B153, "X"), + (0x1B155, "V"), + (0x1B156, "X"), + (0x1B164, "V"), + (0x1B168, "X"), + (0x1B170, "V"), + (0x1B2FC, "X"), + (0x1BC00, "V"), + (0x1BC6B, "X"), + (0x1BC70, "V"), + (0x1BC7D, "X"), + (0x1BC80, "V"), + (0x1BC89, "X"), + (0x1BC90, "V"), + (0x1BC9A, "X"), + (0x1BC9C, "V"), + (0x1BCA0, "I"), + (0x1BCA4, "X"), + (0x1CF00, "V"), + (0x1CF2E, "X"), + (0x1CF30, "V"), + (0x1CF47, "X"), + (0x1CF50, "V"), + (0x1CFC4, "X"), + (0x1D000, "V"), + (0x1D0F6, "X"), + (0x1D100, "V"), + (0x1D127, "X"), + (0x1D129, "V"), + (0x1D15E, "M", "𝅗𝅥"), + (0x1D15F, "M", "𝅘𝅥"), + (0x1D160, "M", "𝅘𝅥𝅮"), + (0x1D161, "M", "𝅘𝅥𝅯"), + (0x1D162, "M", "𝅘𝅥𝅰"), + (0x1D163, "M", "𝅘𝅥𝅱"), + (0x1D164, "M", "𝅘𝅥𝅲"), + (0x1D165, "V"), + (0x1D173, "X"), + (0x1D17B, "V"), + (0x1D1BB, "M", "𝆹𝅥"), + (0x1D1BC, "M", "𝆺𝅥"), + (0x1D1BD, "M", "𝆹𝅥𝅮"), + (0x1D1BE, "M", "𝆺𝅥𝅮"), + (0x1D1BF, "M", "𝆹𝅥𝅯"), + (0x1D1C0, "M", "𝆺𝅥𝅯"), + (0x1D1C1, "V"), + (0x1D1EB, "X"), + (0x1D200, "V"), + (0x1D246, "X"), + (0x1D2C0, "V"), + (0x1D2D4, "X"), + (0x1D2E0, "V"), + (0x1D2F4, "X"), + (0x1D300, "V"), + (0x1D357, "X"), + (0x1D360, "V"), + (0x1D379, "X"), + (0x1D400, "M", "a"), + (0x1D401, "M", "b"), + (0x1D402, "M", "c"), + (0x1D403, "M", "d"), + (0x1D404, "M", "e"), + (0x1D405, "M", "f"), + (0x1D406, "M", "g"), + (0x1D407, "M", "h"), + (0x1D408, "M", "i"), + (0x1D409, "M", "j"), + (0x1D40A, "M", "k"), + (0x1D40B, "M", "l"), + (0x1D40C, "M", "m"), + (0x1D40D, "M", "n"), + (0x1D40E, "M", "o"), + (0x1D40F, "M", "p"), + (0x1D410, "M", "q"), + (0x1D411, "M", "r"), + (0x1D412, "M", "s"), + (0x1D413, "M", "t"), + (0x1D414, "M", "u"), + (0x1D415, "M", "v"), + (0x1D416, "M", "w"), + (0x1D417, "M", "x"), + (0x1D418, "M", "y"), + (0x1D419, "M", "z"), + (0x1D41A, "M", "a"), + (0x1D41B, "M", "b"), + (0x1D41C, "M", "c"), + (0x1D41D, "M", "d"), + (0x1D41E, "M", "e"), + (0x1D41F, "M", "f"), + (0x1D420, "M", "g"), + (0x1D421, "M", "h"), + (0x1D422, "M", "i"), + (0x1D423, "M", "j"), + (0x1D424, "M", "k"), + ] + + +def _seg_61() -> List[Union[Tuple[int, str], Tuple[int, str, str]]]: + return [ + (0x1D425, "M", "l"), + (0x1D426, "M", "m"), + (0x1D427, "M", "n"), + (0x1D428, "M", "o"), + (0x1D429, "M", "p"), + (0x1D42A, "M", "q"), + (0x1D42B, "M", "r"), + (0x1D42C, "M", "s"), + (0x1D42D, "M", "t"), + (0x1D42E, "M", "u"), + (0x1D42F, "M", "v"), + (0x1D430, "M", "w"), + (0x1D431, "M", "x"), + (0x1D432, "M", "y"), + (0x1D433, "M", "z"), + (0x1D434, "M", "a"), + (0x1D435, "M", "b"), + (0x1D436, "M", "c"), + (0x1D437, "M", "d"), + (0x1D438, "M", "e"), + (0x1D439, "M", "f"), + (0x1D43A, "M", "g"), + (0x1D43B, "M", "h"), + (0x1D43C, "M", "i"), + (0x1D43D, "M", "j"), + (0x1D43E, "M", "k"), + (0x1D43F, "M", "l"), + (0x1D440, "M", "m"), + (0x1D441, "M", "n"), + (0x1D442, "M", "o"), + (0x1D443, "M", "p"), + (0x1D444, "M", "q"), + (0x1D445, "M", "r"), + (0x1D446, "M", "s"), + (0x1D447, "M", "t"), + (0x1D448, "M", "u"), + (0x1D449, "M", "v"), + (0x1D44A, "M", "w"), + (0x1D44B, "M", "x"), + (0x1D44C, "M", "y"), + (0x1D44D, "M", "z"), + (0x1D44E, "M", "a"), + (0x1D44F, "M", "b"), + (0x1D450, "M", "c"), + (0x1D451, "M", "d"), + (0x1D452, "M", "e"), + (0x1D453, "M", "f"), + (0x1D454, "M", "g"), + (0x1D455, "X"), + (0x1D456, "M", "i"), + (0x1D457, "M", "j"), + (0x1D458, "M", "k"), + (0x1D459, "M", "l"), + (0x1D45A, "M", "m"), + (0x1D45B, "M", "n"), + (0x1D45C, "M", "o"), + (0x1D45D, "M", "p"), + (0x1D45E, "M", "q"), + (0x1D45F, "M", "r"), + (0x1D460, "M", "s"), + (0x1D461, "M", "t"), + (0x1D462, "M", "u"), + (0x1D463, "M", "v"), + (0x1D464, "M", "w"), + (0x1D465, "M", "x"), + (0x1D466, "M", "y"), + (0x1D467, "M", "z"), + (0x1D468, "M", "a"), + (0x1D469, "M", "b"), + (0x1D46A, "M", "c"), + (0x1D46B, "M", "d"), + (0x1D46C, "M", "e"), + (0x1D46D, "M", "f"), + (0x1D46E, "M", "g"), + (0x1D46F, "M", "h"), + (0x1D470, "M", "i"), + (0x1D471, "M", "j"), + (0x1D472, "M", "k"), + (0x1D473, "M", "l"), + (0x1D474, "M", "m"), + (0x1D475, "M", "n"), + (0x1D476, "M", "o"), + (0x1D477, "M", "p"), + (0x1D478, "M", "q"), + (0x1D479, "M", "r"), + (0x1D47A, "M", "s"), + (0x1D47B, "M", "t"), + (0x1D47C, "M", "u"), + (0x1D47D, "M", "v"), + (0x1D47E, "M", "w"), + (0x1D47F, "M", "x"), + (0x1D480, "M", "y"), + (0x1D481, "M", "z"), + (0x1D482, "M", "a"), + (0x1D483, "M", "b"), + (0x1D484, "M", "c"), + (0x1D485, "M", "d"), + (0x1D486, "M", "e"), + (0x1D487, "M", "f"), + (0x1D488, "M", "g"), + ] + + +def _seg_62() -> List[Union[Tuple[int, str], Tuple[int, str, str]]]: + return [ + (0x1D489, "M", "h"), + (0x1D48A, "M", "i"), + (0x1D48B, "M", "j"), + (0x1D48C, "M", "k"), + (0x1D48D, "M", "l"), + (0x1D48E, "M", "m"), + (0x1D48F, "M", "n"), + (0x1D490, "M", "o"), + (0x1D491, "M", "p"), + (0x1D492, "M", "q"), + (0x1D493, "M", "r"), + (0x1D494, "M", "s"), + (0x1D495, "M", "t"), + (0x1D496, "M", "u"), + (0x1D497, "M", "v"), + (0x1D498, "M", "w"), + (0x1D499, "M", "x"), + (0x1D49A, "M", "y"), + (0x1D49B, "M", "z"), + (0x1D49C, "M", "a"), + (0x1D49D, "X"), + (0x1D49E, "M", "c"), + (0x1D49F, "M", "d"), + (0x1D4A0, "X"), + (0x1D4A2, "M", "g"), + (0x1D4A3, "X"), + (0x1D4A5, "M", "j"), + (0x1D4A6, "M", "k"), + (0x1D4A7, "X"), + (0x1D4A9, "M", "n"), + (0x1D4AA, "M", "o"), + (0x1D4AB, "M", "p"), + (0x1D4AC, "M", "q"), + (0x1D4AD, "X"), + (0x1D4AE, "M", "s"), + (0x1D4AF, "M", "t"), + (0x1D4B0, "M", "u"), + (0x1D4B1, "M", "v"), + (0x1D4B2, "M", "w"), + (0x1D4B3, "M", "x"), + (0x1D4B4, "M", "y"), + (0x1D4B5, "M", "z"), + (0x1D4B6, "M", "a"), + (0x1D4B7, "M", "b"), + (0x1D4B8, "M", "c"), + (0x1D4B9, "M", "d"), + (0x1D4BA, "X"), + (0x1D4BB, "M", "f"), + (0x1D4BC, "X"), + (0x1D4BD, "M", "h"), + (0x1D4BE, "M", "i"), + (0x1D4BF, "M", "j"), + (0x1D4C0, "M", "k"), + (0x1D4C1, "M", "l"), + (0x1D4C2, "M", "m"), + (0x1D4C3, "M", "n"), + (0x1D4C4, "X"), + (0x1D4C5, "M", "p"), + (0x1D4C6, "M", "q"), + (0x1D4C7, "M", "r"), + (0x1D4C8, "M", "s"), + (0x1D4C9, "M", "t"), + (0x1D4CA, "M", "u"), + (0x1D4CB, "M", "v"), + (0x1D4CC, "M", "w"), + (0x1D4CD, "M", "x"), + (0x1D4CE, "M", "y"), + (0x1D4CF, "M", "z"), + (0x1D4D0, "M", "a"), + (0x1D4D1, "M", "b"), + (0x1D4D2, "M", "c"), + (0x1D4D3, "M", "d"), + (0x1D4D4, "M", "e"), + (0x1D4D5, "M", "f"), + (0x1D4D6, "M", "g"), + (0x1D4D7, "M", "h"), + (0x1D4D8, "M", "i"), + (0x1D4D9, "M", "j"), + (0x1D4DA, "M", "k"), + (0x1D4DB, "M", "l"), + (0x1D4DC, "M", "m"), + (0x1D4DD, "M", "n"), + (0x1D4DE, "M", "o"), + (0x1D4DF, "M", "p"), + (0x1D4E0, "M", "q"), + (0x1D4E1, "M", "r"), + (0x1D4E2, "M", "s"), + (0x1D4E3, "M", "t"), + (0x1D4E4, "M", "u"), + (0x1D4E5, "M", "v"), + (0x1D4E6, "M", "w"), + (0x1D4E7, "M", "x"), + (0x1D4E8, "M", "y"), + (0x1D4E9, "M", "z"), + (0x1D4EA, "M", "a"), + (0x1D4EB, "M", "b"), + (0x1D4EC, "M", "c"), + (0x1D4ED, "M", "d"), + (0x1D4EE, "M", "e"), + (0x1D4EF, "M", "f"), + ] + + +def _seg_63() -> List[Union[Tuple[int, str], Tuple[int, str, str]]]: + return [ + (0x1D4F0, "M", "g"), + (0x1D4F1, "M", "h"), + (0x1D4F2, "M", "i"), + (0x1D4F3, "M", "j"), + (0x1D4F4, "M", "k"), + (0x1D4F5, "M", "l"), + (0x1D4F6, "M", "m"), + (0x1D4F7, "M", "n"), + (0x1D4F8, "M", "o"), + (0x1D4F9, "M", "p"), + (0x1D4FA, "M", "q"), + (0x1D4FB, "M", "r"), + (0x1D4FC, "M", "s"), + (0x1D4FD, "M", "t"), + (0x1D4FE, "M", "u"), + (0x1D4FF, "M", "v"), + (0x1D500, "M", "w"), + (0x1D501, "M", "x"), + (0x1D502, "M", "y"), + (0x1D503, "M", "z"), + (0x1D504, "M", "a"), + (0x1D505, "M", "b"), + (0x1D506, "X"), + (0x1D507, "M", "d"), + (0x1D508, "M", "e"), + (0x1D509, "M", "f"), + (0x1D50A, "M", "g"), + (0x1D50B, "X"), + (0x1D50D, "M", "j"), + (0x1D50E, "M", "k"), + (0x1D50F, "M", "l"), + (0x1D510, "M", "m"), + (0x1D511, "M", "n"), + (0x1D512, "M", "o"), + (0x1D513, "M", "p"), + (0x1D514, "M", "q"), + (0x1D515, "X"), + (0x1D516, "M", "s"), + (0x1D517, "M", "t"), + (0x1D518, "M", "u"), + (0x1D519, "M", "v"), + (0x1D51A, "M", "w"), + (0x1D51B, "M", "x"), + (0x1D51C, "M", "y"), + (0x1D51D, "X"), + (0x1D51E, "M", "a"), + (0x1D51F, "M", "b"), + (0x1D520, "M", "c"), + (0x1D521, "M", "d"), + (0x1D522, "M", "e"), + (0x1D523, "M", "f"), + (0x1D524, "M", "g"), + (0x1D525, "M", "h"), + (0x1D526, "M", "i"), + (0x1D527, "M", "j"), + (0x1D528, "M", "k"), + (0x1D529, "M", "l"), + (0x1D52A, "M", "m"), + (0x1D52B, "M", "n"), + (0x1D52C, "M", "o"), + (0x1D52D, "M", "p"), + (0x1D52E, "M", "q"), + (0x1D52F, "M", "r"), + (0x1D530, "M", "s"), + (0x1D531, "M", "t"), + (0x1D532, "M", "u"), + (0x1D533, "M", "v"), + (0x1D534, "M", "w"), + (0x1D535, "M", "x"), + (0x1D536, "M", "y"), + (0x1D537, "M", "z"), + (0x1D538, "M", "a"), + (0x1D539, "M", "b"), + (0x1D53A, "X"), + (0x1D53B, "M", "d"), + (0x1D53C, "M", "e"), + (0x1D53D, "M", "f"), + (0x1D53E, "M", "g"), + (0x1D53F, "X"), + (0x1D540, "M", "i"), + (0x1D541, "M", "j"), + (0x1D542, "M", "k"), + (0x1D543, "M", "l"), + (0x1D544, "M", "m"), + (0x1D545, "X"), + (0x1D546, "M", "o"), + (0x1D547, "X"), + (0x1D54A, "M", "s"), + (0x1D54B, "M", "t"), + (0x1D54C, "M", "u"), + (0x1D54D, "M", "v"), + (0x1D54E, "M", "w"), + (0x1D54F, "M", "x"), + (0x1D550, "M", "y"), + (0x1D551, "X"), + (0x1D552, "M", "a"), + (0x1D553, "M", "b"), + (0x1D554, "M", "c"), + (0x1D555, "M", "d"), + (0x1D556, "M", "e"), + ] + + +def _seg_64() -> List[Union[Tuple[int, str], Tuple[int, str, str]]]: + return [ + (0x1D557, "M", "f"), + (0x1D558, "M", "g"), + (0x1D559, "M", "h"), + (0x1D55A, "M", "i"), + (0x1D55B, "M", "j"), + (0x1D55C, "M", "k"), + (0x1D55D, "M", "l"), + (0x1D55E, "M", "m"), + (0x1D55F, "M", "n"), + (0x1D560, "M", "o"), + (0x1D561, "M", "p"), + (0x1D562, "M", "q"), + (0x1D563, "M", "r"), + (0x1D564, "M", "s"), + (0x1D565, "M", "t"), + (0x1D566, "M", "u"), + (0x1D567, "M", "v"), + (0x1D568, "M", "w"), + (0x1D569, "M", "x"), + (0x1D56A, "M", "y"), + (0x1D56B, "M", "z"), + (0x1D56C, "M", "a"), + (0x1D56D, "M", "b"), + (0x1D56E, "M", "c"), + (0x1D56F, "M", "d"), + (0x1D570, "M", "e"), + (0x1D571, "M", "f"), + (0x1D572, "M", "g"), + (0x1D573, "M", "h"), + (0x1D574, "M", "i"), + (0x1D575, "M", "j"), + (0x1D576, "M", "k"), + (0x1D577, "M", "l"), + (0x1D578, "M", "m"), + (0x1D579, "M", "n"), + (0x1D57A, "M", "o"), + (0x1D57B, "M", "p"), + (0x1D57C, "M", "q"), + (0x1D57D, "M", "r"), + (0x1D57E, "M", "s"), + (0x1D57F, "M", "t"), + (0x1D580, "M", "u"), + (0x1D581, "M", "v"), + (0x1D582, "M", "w"), + (0x1D583, "M", "x"), + (0x1D584, "M", "y"), + (0x1D585, "M", "z"), + (0x1D586, "M", "a"), + (0x1D587, "M", "b"), + (0x1D588, "M", "c"), + (0x1D589, "M", "d"), + (0x1D58A, "M", "e"), + (0x1D58B, "M", "f"), + (0x1D58C, "M", "g"), + (0x1D58D, "M", "h"), + (0x1D58E, "M", "i"), + (0x1D58F, "M", "j"), + (0x1D590, "M", "k"), + (0x1D591, "M", "l"), + (0x1D592, "M", "m"), + (0x1D593, "M", "n"), + (0x1D594, "M", "o"), + (0x1D595, "M", "p"), + (0x1D596, "M", "q"), + (0x1D597, "M", "r"), + (0x1D598, "M", "s"), + (0x1D599, "M", "t"), + (0x1D59A, "M", "u"), + (0x1D59B, "M", "v"), + (0x1D59C, "M", "w"), + (0x1D59D, "M", "x"), + (0x1D59E, "M", "y"), + (0x1D59F, "M", "z"), + (0x1D5A0, "M", "a"), + (0x1D5A1, "M", "b"), + (0x1D5A2, "M", "c"), + (0x1D5A3, "M", "d"), + (0x1D5A4, "M", "e"), + (0x1D5A5, "M", "f"), + (0x1D5A6, "M", "g"), + (0x1D5A7, "M", "h"), + (0x1D5A8, "M", "i"), + (0x1D5A9, "M", "j"), + (0x1D5AA, "M", "k"), + (0x1D5AB, "M", "l"), + (0x1D5AC, "M", "m"), + (0x1D5AD, "M", "n"), + (0x1D5AE, "M", "o"), + (0x1D5AF, "M", "p"), + (0x1D5B0, "M", "q"), + (0x1D5B1, "M", "r"), + (0x1D5B2, "M", "s"), + (0x1D5B3, "M", "t"), + (0x1D5B4, "M", "u"), + (0x1D5B5, "M", "v"), + (0x1D5B6, "M", "w"), + (0x1D5B7, "M", "x"), + (0x1D5B8, "M", "y"), + (0x1D5B9, "M", "z"), + (0x1D5BA, "M", "a"), + ] + + +def _seg_65() -> List[Union[Tuple[int, str], Tuple[int, str, str]]]: + return [ + (0x1D5BB, "M", "b"), + (0x1D5BC, "M", "c"), + (0x1D5BD, "M", "d"), + (0x1D5BE, "M", "e"), + (0x1D5BF, "M", "f"), + (0x1D5C0, "M", "g"), + (0x1D5C1, "M", "h"), + (0x1D5C2, "M", "i"), + (0x1D5C3, "M", "j"), + (0x1D5C4, "M", "k"), + (0x1D5C5, "M", "l"), + (0x1D5C6, "M", "m"), + (0x1D5C7, "M", "n"), + (0x1D5C8, "M", "o"), + (0x1D5C9, "M", "p"), + (0x1D5CA, "M", "q"), + (0x1D5CB, "M", "r"), + (0x1D5CC, "M", "s"), + (0x1D5CD, "M", "t"), + (0x1D5CE, "M", "u"), + (0x1D5CF, "M", "v"), + (0x1D5D0, "M", "w"), + (0x1D5D1, "M", "x"), + (0x1D5D2, "M", "y"), + (0x1D5D3, "M", "z"), + (0x1D5D4, "M", "a"), + (0x1D5D5, "M", "b"), + (0x1D5D6, "M", "c"), + (0x1D5D7, "M", "d"), + (0x1D5D8, "M", "e"), + (0x1D5D9, "M", "f"), + (0x1D5DA, "M", "g"), + (0x1D5DB, "M", "h"), + (0x1D5DC, "M", "i"), + (0x1D5DD, "M", "j"), + (0x1D5DE, "M", "k"), + (0x1D5DF, "M", "l"), + (0x1D5E0, "M", "m"), + (0x1D5E1, "M", "n"), + (0x1D5E2, "M", "o"), + (0x1D5E3, "M", "p"), + (0x1D5E4, "M", "q"), + (0x1D5E5, "M", "r"), + (0x1D5E6, "M", "s"), + (0x1D5E7, "M", "t"), + (0x1D5E8, "M", "u"), + (0x1D5E9, "M", "v"), + (0x1D5EA, "M", "w"), + (0x1D5EB, "M", "x"), + (0x1D5EC, "M", "y"), + (0x1D5ED, "M", "z"), + (0x1D5EE, "M", "a"), + (0x1D5EF, "M", "b"), + (0x1D5F0, "M", "c"), + (0x1D5F1, "M", "d"), + (0x1D5F2, "M", "e"), + (0x1D5F3, "M", "f"), + (0x1D5F4, "M", "g"), + (0x1D5F5, "M", "h"), + (0x1D5F6, "M", "i"), + (0x1D5F7, "M", "j"), + (0x1D5F8, "M", "k"), + (0x1D5F9, "M", "l"), + (0x1D5FA, "M", "m"), + (0x1D5FB, "M", "n"), + (0x1D5FC, "M", "o"), + (0x1D5FD, "M", "p"), + (0x1D5FE, "M", "q"), + (0x1D5FF, "M", "r"), + (0x1D600, "M", "s"), + (0x1D601, "M", "t"), + (0x1D602, "M", "u"), + (0x1D603, "M", "v"), + (0x1D604, "M", "w"), + (0x1D605, "M", "x"), + (0x1D606, "M", "y"), + (0x1D607, "M", "z"), + (0x1D608, "M", "a"), + (0x1D609, "M", "b"), + (0x1D60A, "M", "c"), + (0x1D60B, "M", "d"), + (0x1D60C, "M", "e"), + (0x1D60D, "M", "f"), + (0x1D60E, "M", "g"), + (0x1D60F, "M", "h"), + (0x1D610, "M", "i"), + (0x1D611, "M", "j"), + (0x1D612, "M", "k"), + (0x1D613, "M", "l"), + (0x1D614, "M", "m"), + (0x1D615, "M", "n"), + (0x1D616, "M", "o"), + (0x1D617, "M", "p"), + (0x1D618, "M", "q"), + (0x1D619, "M", "r"), + (0x1D61A, "M", "s"), + (0x1D61B, "M", "t"), + (0x1D61C, "M", "u"), + (0x1D61D, "M", "v"), + (0x1D61E, "M", "w"), + ] + + +def _seg_66() -> List[Union[Tuple[int, str], Tuple[int, str, str]]]: + return [ + (0x1D61F, "M", "x"), + (0x1D620, "M", "y"), + (0x1D621, "M", "z"), + (0x1D622, "M", "a"), + (0x1D623, "M", "b"), + (0x1D624, "M", "c"), + (0x1D625, "M", "d"), + (0x1D626, "M", "e"), + (0x1D627, "M", "f"), + (0x1D628, "M", "g"), + (0x1D629, "M", "h"), + (0x1D62A, "M", "i"), + (0x1D62B, "M", "j"), + (0x1D62C, "M", "k"), + (0x1D62D, "M", "l"), + (0x1D62E, "M", "m"), + (0x1D62F, "M", "n"), + (0x1D630, "M", "o"), + (0x1D631, "M", "p"), + (0x1D632, "M", "q"), + (0x1D633, "M", "r"), + (0x1D634, "M", "s"), + (0x1D635, "M", "t"), + (0x1D636, "M", "u"), + (0x1D637, "M", "v"), + (0x1D638, "M", "w"), + (0x1D639, "M", "x"), + (0x1D63A, "M", "y"), + (0x1D63B, "M", "z"), + (0x1D63C, "M", "a"), + (0x1D63D, "M", "b"), + (0x1D63E, "M", "c"), + (0x1D63F, "M", "d"), + (0x1D640, "M", "e"), + (0x1D641, "M", "f"), + (0x1D642, "M", "g"), + (0x1D643, "M", "h"), + (0x1D644, "M", "i"), + (0x1D645, "M", "j"), + (0x1D646, "M", "k"), + (0x1D647, "M", "l"), + (0x1D648, "M", "m"), + (0x1D649, "M", "n"), + (0x1D64A, "M", "o"), + (0x1D64B, "M", "p"), + (0x1D64C, "M", "q"), + (0x1D64D, "M", "r"), + (0x1D64E, "M", "s"), + (0x1D64F, "M", "t"), + (0x1D650, "M", "u"), + (0x1D651, "M", "v"), + (0x1D652, "M", "w"), + (0x1D653, "M", "x"), + (0x1D654, "M", "y"), + (0x1D655, "M", "z"), + (0x1D656, "M", "a"), + (0x1D657, "M", "b"), + (0x1D658, "M", "c"), + (0x1D659, "M", "d"), + (0x1D65A, "M", "e"), + (0x1D65B, "M", "f"), + (0x1D65C, "M", "g"), + (0x1D65D, "M", "h"), + (0x1D65E, "M", "i"), + (0x1D65F, "M", "j"), + (0x1D660, "M", "k"), + (0x1D661, "M", "l"), + (0x1D662, "M", "m"), + (0x1D663, "M", "n"), + (0x1D664, "M", "o"), + (0x1D665, "M", "p"), + (0x1D666, "M", "q"), + (0x1D667, "M", "r"), + (0x1D668, "M", "s"), + (0x1D669, "M", "t"), + (0x1D66A, "M", "u"), + (0x1D66B, "M", "v"), + (0x1D66C, "M", "w"), + (0x1D66D, "M", "x"), + (0x1D66E, "M", "y"), + (0x1D66F, "M", "z"), + (0x1D670, "M", "a"), + (0x1D671, "M", "b"), + (0x1D672, "M", "c"), + (0x1D673, "M", "d"), + (0x1D674, "M", "e"), + (0x1D675, "M", "f"), + (0x1D676, "M", "g"), + (0x1D677, "M", "h"), + (0x1D678, "M", "i"), + (0x1D679, "M", "j"), + (0x1D67A, "M", "k"), + (0x1D67B, "M", "l"), + (0x1D67C, "M", "m"), + (0x1D67D, "M", "n"), + (0x1D67E, "M", "o"), + (0x1D67F, "M", "p"), + (0x1D680, "M", "q"), + (0x1D681, "M", "r"), + (0x1D682, "M", "s"), + ] + + +def _seg_67() -> List[Union[Tuple[int, str], Tuple[int, str, str]]]: + return [ + (0x1D683, "M", "t"), + (0x1D684, "M", "u"), + (0x1D685, "M", "v"), + (0x1D686, "M", "w"), + (0x1D687, "M", "x"), + (0x1D688, "M", "y"), + (0x1D689, "M", "z"), + (0x1D68A, "M", "a"), + (0x1D68B, "M", "b"), + (0x1D68C, "M", "c"), + (0x1D68D, "M", "d"), + (0x1D68E, "M", "e"), + (0x1D68F, "M", "f"), + (0x1D690, "M", "g"), + (0x1D691, "M", "h"), + (0x1D692, "M", "i"), + (0x1D693, "M", "j"), + (0x1D694, "M", "k"), + (0x1D695, "M", "l"), + (0x1D696, "M", "m"), + (0x1D697, "M", "n"), + (0x1D698, "M", "o"), + (0x1D699, "M", "p"), + (0x1D69A, "M", "q"), + (0x1D69B, "M", "r"), + (0x1D69C, "M", "s"), + (0x1D69D, "M", "t"), + (0x1D69E, "M", "u"), + (0x1D69F, "M", "v"), + (0x1D6A0, "M", "w"), + (0x1D6A1, "M", "x"), + (0x1D6A2, "M", "y"), + (0x1D6A3, "M", "z"), + (0x1D6A4, "M", "ı"), + (0x1D6A5, "M", "ȷ"), + (0x1D6A6, "X"), + (0x1D6A8, "M", "α"), + (0x1D6A9, "M", "β"), + (0x1D6AA, "M", "γ"), + (0x1D6AB, "M", "δ"), + (0x1D6AC, "M", "ε"), + (0x1D6AD, "M", "ζ"), + (0x1D6AE, "M", "η"), + (0x1D6AF, "M", "θ"), + (0x1D6B0, "M", "ι"), + (0x1D6B1, "M", "κ"), + (0x1D6B2, "M", "λ"), + (0x1D6B3, "M", "μ"), + (0x1D6B4, "M", "ν"), + (0x1D6B5, "M", "ξ"), + (0x1D6B6, "M", "ο"), + (0x1D6B7, "M", "π"), + (0x1D6B8, "M", "ρ"), + (0x1D6B9, "M", "θ"), + (0x1D6BA, "M", "σ"), + (0x1D6BB, "M", "τ"), + (0x1D6BC, "M", "υ"), + (0x1D6BD, "M", "φ"), + (0x1D6BE, "M", "χ"), + (0x1D6BF, "M", "ψ"), + (0x1D6C0, "M", "ω"), + (0x1D6C1, "M", "∇"), + (0x1D6C2, "M", "α"), + (0x1D6C3, "M", "β"), + (0x1D6C4, "M", "γ"), + (0x1D6C5, "M", "δ"), + (0x1D6C6, "M", "ε"), + (0x1D6C7, "M", "ζ"), + (0x1D6C8, "M", "η"), + (0x1D6C9, "M", "θ"), + (0x1D6CA, "M", "ι"), + (0x1D6CB, "M", "κ"), + (0x1D6CC, "M", "λ"), + (0x1D6CD, "M", "μ"), + (0x1D6CE, "M", "ν"), + (0x1D6CF, "M", "ξ"), + (0x1D6D0, "M", "ο"), + (0x1D6D1, "M", "π"), + (0x1D6D2, "M", "ρ"), + (0x1D6D3, "M", "σ"), + (0x1D6D5, "M", "τ"), + (0x1D6D6, "M", "υ"), + (0x1D6D7, "M", "φ"), + (0x1D6D8, "M", "χ"), + (0x1D6D9, "M", "ψ"), + (0x1D6DA, "M", "ω"), + (0x1D6DB, "M", "∂"), + (0x1D6DC, "M", "ε"), + (0x1D6DD, "M", "θ"), + (0x1D6DE, "M", "κ"), + (0x1D6DF, "M", "φ"), + (0x1D6E0, "M", "ρ"), + (0x1D6E1, "M", "π"), + (0x1D6E2, "M", "α"), + (0x1D6E3, "M", "β"), + (0x1D6E4, "M", "γ"), + (0x1D6E5, "M", "δ"), + (0x1D6E6, "M", "ε"), + (0x1D6E7, "M", "ζ"), + (0x1D6E8, "M", "η"), + ] + + +def _seg_68() -> List[Union[Tuple[int, str], Tuple[int, str, str]]]: + return [ + (0x1D6E9, "M", "θ"), + (0x1D6EA, "M", "ι"), + (0x1D6EB, "M", "κ"), + (0x1D6EC, "M", "λ"), + (0x1D6ED, "M", "μ"), + (0x1D6EE, "M", "ν"), + (0x1D6EF, "M", "ξ"), + (0x1D6F0, "M", "ο"), + (0x1D6F1, "M", "π"), + (0x1D6F2, "M", "ρ"), + (0x1D6F3, "M", "θ"), + (0x1D6F4, "M", "σ"), + (0x1D6F5, "M", "τ"), + (0x1D6F6, "M", "υ"), + (0x1D6F7, "M", "φ"), + (0x1D6F8, "M", "χ"), + (0x1D6F9, "M", "ψ"), + (0x1D6FA, "M", "ω"), + (0x1D6FB, "M", "∇"), + (0x1D6FC, "M", "α"), + (0x1D6FD, "M", "β"), + (0x1D6FE, "M", "γ"), + (0x1D6FF, "M", "δ"), + (0x1D700, "M", "ε"), + (0x1D701, "M", "ζ"), + (0x1D702, "M", "η"), + (0x1D703, "M", "θ"), + (0x1D704, "M", "ι"), + (0x1D705, "M", "κ"), + (0x1D706, "M", "λ"), + (0x1D707, "M", "μ"), + (0x1D708, "M", "ν"), + (0x1D709, "M", "ξ"), + (0x1D70A, "M", "ο"), + (0x1D70B, "M", "π"), + (0x1D70C, "M", "ρ"), + (0x1D70D, "M", "σ"), + (0x1D70F, "M", "τ"), + (0x1D710, "M", "υ"), + (0x1D711, "M", "φ"), + (0x1D712, "M", "χ"), + (0x1D713, "M", "ψ"), + (0x1D714, "M", "ω"), + (0x1D715, "M", "∂"), + (0x1D716, "M", "ε"), + (0x1D717, "M", "θ"), + (0x1D718, "M", "κ"), + (0x1D719, "M", "φ"), + (0x1D71A, "M", "ρ"), + (0x1D71B, "M", "π"), + (0x1D71C, "M", "α"), + (0x1D71D, "M", "β"), + (0x1D71E, "M", "γ"), + (0x1D71F, "M", "δ"), + (0x1D720, "M", "ε"), + (0x1D721, "M", "ζ"), + (0x1D722, "M", "η"), + (0x1D723, "M", "θ"), + (0x1D724, "M", "ι"), + (0x1D725, "M", "κ"), + (0x1D726, "M", "λ"), + (0x1D727, "M", "μ"), + (0x1D728, "M", "ν"), + (0x1D729, "M", "ξ"), + (0x1D72A, "M", "ο"), + (0x1D72B, "M", "π"), + (0x1D72C, "M", "ρ"), + (0x1D72D, "M", "θ"), + (0x1D72E, "M", "σ"), + (0x1D72F, "M", "τ"), + (0x1D730, "M", "υ"), + (0x1D731, "M", "φ"), + (0x1D732, "M", "χ"), + (0x1D733, "M", "ψ"), + (0x1D734, "M", "ω"), + (0x1D735, "M", "∇"), + (0x1D736, "M", "α"), + (0x1D737, "M", "β"), + (0x1D738, "M", "γ"), + (0x1D739, "M", "δ"), + (0x1D73A, "M", "ε"), + (0x1D73B, "M", "ζ"), + (0x1D73C, "M", "η"), + (0x1D73D, "M", "θ"), + (0x1D73E, "M", "ι"), + (0x1D73F, "M", "κ"), + (0x1D740, "M", "λ"), + (0x1D741, "M", "μ"), + (0x1D742, "M", "ν"), + (0x1D743, "M", "ξ"), + (0x1D744, "M", "ο"), + (0x1D745, "M", "π"), + (0x1D746, "M", "ρ"), + (0x1D747, "M", "σ"), + (0x1D749, "M", "τ"), + (0x1D74A, "M", "υ"), + (0x1D74B, "M", "φ"), + (0x1D74C, "M", "χ"), + (0x1D74D, "M", "ψ"), + (0x1D74E, "M", "ω"), + ] + + +def _seg_69() -> List[Union[Tuple[int, str], Tuple[int, str, str]]]: + return [ + (0x1D74F, "M", "∂"), + (0x1D750, "M", "ε"), + (0x1D751, "M", "θ"), + (0x1D752, "M", "κ"), + (0x1D753, "M", "φ"), + (0x1D754, "M", "ρ"), + (0x1D755, "M", "π"), + (0x1D756, "M", "α"), + (0x1D757, "M", "β"), + (0x1D758, "M", "γ"), + (0x1D759, "M", "δ"), + (0x1D75A, "M", "ε"), + (0x1D75B, "M", "ζ"), + (0x1D75C, "M", "η"), + (0x1D75D, "M", "θ"), + (0x1D75E, "M", "ι"), + (0x1D75F, "M", "κ"), + (0x1D760, "M", "λ"), + (0x1D761, "M", "μ"), + (0x1D762, "M", "ν"), + (0x1D763, "M", "ξ"), + (0x1D764, "M", "ο"), + (0x1D765, "M", "π"), + (0x1D766, "M", "ρ"), + (0x1D767, "M", "θ"), + (0x1D768, "M", "σ"), + (0x1D769, "M", "τ"), + (0x1D76A, "M", "υ"), + (0x1D76B, "M", "φ"), + (0x1D76C, "M", "χ"), + (0x1D76D, "M", "ψ"), + (0x1D76E, "M", "ω"), + (0x1D76F, "M", "∇"), + (0x1D770, "M", "α"), + (0x1D771, "M", "β"), + (0x1D772, "M", "γ"), + (0x1D773, "M", "δ"), + (0x1D774, "M", "ε"), + (0x1D775, "M", "ζ"), + (0x1D776, "M", "η"), + (0x1D777, "M", "θ"), + (0x1D778, "M", "ι"), + (0x1D779, "M", "κ"), + (0x1D77A, "M", "λ"), + (0x1D77B, "M", "μ"), + (0x1D77C, "M", "ν"), + (0x1D77D, "M", "ξ"), + (0x1D77E, "M", "ο"), + (0x1D77F, "M", "π"), + (0x1D780, "M", "ρ"), + (0x1D781, "M", "σ"), + (0x1D783, "M", "τ"), + (0x1D784, "M", "υ"), + (0x1D785, "M", "φ"), + (0x1D786, "M", "χ"), + (0x1D787, "M", "ψ"), + (0x1D788, "M", "ω"), + (0x1D789, "M", "∂"), + (0x1D78A, "M", "ε"), + (0x1D78B, "M", "θ"), + (0x1D78C, "M", "κ"), + (0x1D78D, "M", "φ"), + (0x1D78E, "M", "ρ"), + (0x1D78F, "M", "π"), + (0x1D790, "M", "α"), + (0x1D791, "M", "β"), + (0x1D792, "M", "γ"), + (0x1D793, "M", "δ"), + (0x1D794, "M", "ε"), + (0x1D795, "M", "ζ"), + (0x1D796, "M", "η"), + (0x1D797, "M", "θ"), + (0x1D798, "M", "ι"), + (0x1D799, "M", "κ"), + (0x1D79A, "M", "λ"), + (0x1D79B, "M", "μ"), + (0x1D79C, "M", "ν"), + (0x1D79D, "M", "ξ"), + (0x1D79E, "M", "ο"), + (0x1D79F, "M", "π"), + (0x1D7A0, "M", "ρ"), + (0x1D7A1, "M", "θ"), + (0x1D7A2, "M", "σ"), + (0x1D7A3, "M", "τ"), + (0x1D7A4, "M", "υ"), + (0x1D7A5, "M", "φ"), + (0x1D7A6, "M", "χ"), + (0x1D7A7, "M", "ψ"), + (0x1D7A8, "M", "ω"), + (0x1D7A9, "M", "∇"), + (0x1D7AA, "M", "α"), + (0x1D7AB, "M", "β"), + (0x1D7AC, "M", "γ"), + (0x1D7AD, "M", "δ"), + (0x1D7AE, "M", "ε"), + (0x1D7AF, "M", "ζ"), + (0x1D7B0, "M", "η"), + (0x1D7B1, "M", "θ"), + (0x1D7B2, "M", "ι"), + (0x1D7B3, "M", "κ"), + ] + + +def _seg_70() -> List[Union[Tuple[int, str], Tuple[int, str, str]]]: + return [ + (0x1D7B4, "M", "λ"), + (0x1D7B5, "M", "μ"), + (0x1D7B6, "M", "ν"), + (0x1D7B7, "M", "ξ"), + (0x1D7B8, "M", "ο"), + (0x1D7B9, "M", "π"), + (0x1D7BA, "M", "ρ"), + (0x1D7BB, "M", "σ"), + (0x1D7BD, "M", "τ"), + (0x1D7BE, "M", "υ"), + (0x1D7BF, "M", "φ"), + (0x1D7C0, "M", "χ"), + (0x1D7C1, "M", "ψ"), + (0x1D7C2, "M", "ω"), + (0x1D7C3, "M", "∂"), + (0x1D7C4, "M", "ε"), + (0x1D7C5, "M", "θ"), + (0x1D7C6, "M", "κ"), + (0x1D7C7, "M", "φ"), + (0x1D7C8, "M", "ρ"), + (0x1D7C9, "M", "π"), + (0x1D7CA, "M", "ϝ"), + (0x1D7CC, "X"), + (0x1D7CE, "M", "0"), + (0x1D7CF, "M", "1"), + (0x1D7D0, "M", "2"), + (0x1D7D1, "M", "3"), + (0x1D7D2, "M", "4"), + (0x1D7D3, "M", "5"), + (0x1D7D4, "M", "6"), + (0x1D7D5, "M", "7"), + (0x1D7D6, "M", "8"), + (0x1D7D7, "M", "9"), + (0x1D7D8, "M", "0"), + (0x1D7D9, "M", "1"), + (0x1D7DA, "M", "2"), + (0x1D7DB, "M", "3"), + (0x1D7DC, "M", "4"), + (0x1D7DD, "M", "5"), + (0x1D7DE, "M", "6"), + (0x1D7DF, "M", "7"), + (0x1D7E0, "M", "8"), + (0x1D7E1, "M", "9"), + (0x1D7E2, "M", "0"), + (0x1D7E3, "M", "1"), + (0x1D7E4, "M", "2"), + (0x1D7E5, "M", "3"), + (0x1D7E6, "M", "4"), + (0x1D7E7, "M", "5"), + (0x1D7E8, "M", "6"), + (0x1D7E9, "M", "7"), + (0x1D7EA, "M", "8"), + (0x1D7EB, "M", "9"), + (0x1D7EC, "M", "0"), + (0x1D7ED, "M", "1"), + (0x1D7EE, "M", "2"), + (0x1D7EF, "M", "3"), + (0x1D7F0, "M", "4"), + (0x1D7F1, "M", "5"), + (0x1D7F2, "M", "6"), + (0x1D7F3, "M", "7"), + (0x1D7F4, "M", "8"), + (0x1D7F5, "M", "9"), + (0x1D7F6, "M", "0"), + (0x1D7F7, "M", "1"), + (0x1D7F8, "M", "2"), + (0x1D7F9, "M", "3"), + (0x1D7FA, "M", "4"), + (0x1D7FB, "M", "5"), + (0x1D7FC, "M", "6"), + (0x1D7FD, "M", "7"), + (0x1D7FE, "M", "8"), + (0x1D7FF, "M", "9"), + (0x1D800, "V"), + (0x1DA8C, "X"), + (0x1DA9B, "V"), + (0x1DAA0, "X"), + (0x1DAA1, "V"), + (0x1DAB0, "X"), + (0x1DF00, "V"), + (0x1DF1F, "X"), + (0x1DF25, "V"), + (0x1DF2B, "X"), + (0x1E000, "V"), + (0x1E007, "X"), + (0x1E008, "V"), + (0x1E019, "X"), + (0x1E01B, "V"), + (0x1E022, "X"), + (0x1E023, "V"), + (0x1E025, "X"), + (0x1E026, "V"), + (0x1E02B, "X"), + (0x1E030, "M", "а"), + (0x1E031, "M", "б"), + (0x1E032, "M", "в"), + (0x1E033, "M", "г"), + (0x1E034, "M", "д"), + (0x1E035, "M", "е"), + (0x1E036, "M", "ж"), + ] + + +def _seg_71() -> List[Union[Tuple[int, str], Tuple[int, str, str]]]: + return [ + (0x1E037, "M", "з"), + (0x1E038, "M", "и"), + (0x1E039, "M", "к"), + (0x1E03A, "M", "л"), + (0x1E03B, "M", "м"), + (0x1E03C, "M", "о"), + (0x1E03D, "M", "п"), + (0x1E03E, "M", "р"), + (0x1E03F, "M", "с"), + (0x1E040, "M", "т"), + (0x1E041, "M", "у"), + (0x1E042, "M", "ф"), + (0x1E043, "M", "х"), + (0x1E044, "M", "ц"), + (0x1E045, "M", "ч"), + (0x1E046, "M", "ш"), + (0x1E047, "M", "ы"), + (0x1E048, "M", "э"), + (0x1E049, "M", "ю"), + (0x1E04A, "M", "ꚉ"), + (0x1E04B, "M", "ә"), + (0x1E04C, "M", "і"), + (0x1E04D, "M", "ј"), + (0x1E04E, "M", "ө"), + (0x1E04F, "M", "ү"), + (0x1E050, "M", "ӏ"), + (0x1E051, "M", "а"), + (0x1E052, "M", "б"), + (0x1E053, "M", "в"), + (0x1E054, "M", "г"), + (0x1E055, "M", "д"), + (0x1E056, "M", "е"), + (0x1E057, "M", "ж"), + (0x1E058, "M", "з"), + (0x1E059, "M", "и"), + (0x1E05A, "M", "к"), + (0x1E05B, "M", "л"), + (0x1E05C, "M", "о"), + (0x1E05D, "M", "п"), + (0x1E05E, "M", "с"), + (0x1E05F, "M", "у"), + (0x1E060, "M", "ф"), + (0x1E061, "M", "х"), + (0x1E062, "M", "ц"), + (0x1E063, "M", "ч"), + (0x1E064, "M", "ш"), + (0x1E065, "M", "ъ"), + (0x1E066, "M", "ы"), + (0x1E067, "M", "ґ"), + (0x1E068, "M", "і"), + (0x1E069, "M", "ѕ"), + (0x1E06A, "M", "џ"), + (0x1E06B, "M", "ҫ"), + (0x1E06C, "M", "ꙑ"), + (0x1E06D, "M", "ұ"), + (0x1E06E, "X"), + (0x1E08F, "V"), + (0x1E090, "X"), + (0x1E100, "V"), + (0x1E12D, "X"), + (0x1E130, "V"), + (0x1E13E, "X"), + (0x1E140, "V"), + (0x1E14A, "X"), + (0x1E14E, "V"), + (0x1E150, "X"), + (0x1E290, "V"), + (0x1E2AF, "X"), + (0x1E2C0, "V"), + (0x1E2FA, "X"), + (0x1E2FF, "V"), + (0x1E300, "X"), + (0x1E4D0, "V"), + (0x1E4FA, "X"), + (0x1E7E0, "V"), + (0x1E7E7, "X"), + (0x1E7E8, "V"), + (0x1E7EC, "X"), + (0x1E7ED, "V"), + (0x1E7EF, "X"), + (0x1E7F0, "V"), + (0x1E7FF, "X"), + (0x1E800, "V"), + (0x1E8C5, "X"), + (0x1E8C7, "V"), + (0x1E8D7, "X"), + (0x1E900, "M", "𞤢"), + (0x1E901, "M", "𞤣"), + (0x1E902, "M", "𞤤"), + (0x1E903, "M", "𞤥"), + (0x1E904, "M", "𞤦"), + (0x1E905, "M", "𞤧"), + (0x1E906, "M", "𞤨"), + (0x1E907, "M", "𞤩"), + (0x1E908, "M", "𞤪"), + (0x1E909, "M", "𞤫"), + (0x1E90A, "M", "𞤬"), + (0x1E90B, "M", "𞤭"), + (0x1E90C, "M", "𞤮"), + (0x1E90D, "M", "𞤯"), + ] + + +def _seg_72() -> List[Union[Tuple[int, str], Tuple[int, str, str]]]: + return [ + (0x1E90E, "M", "𞤰"), + (0x1E90F, "M", "𞤱"), + (0x1E910, "M", "𞤲"), + (0x1E911, "M", "𞤳"), + (0x1E912, "M", "𞤴"), + (0x1E913, "M", "𞤵"), + (0x1E914, "M", "𞤶"), + (0x1E915, "M", "𞤷"), + (0x1E916, "M", "𞤸"), + (0x1E917, "M", "𞤹"), + (0x1E918, "M", "𞤺"), + (0x1E919, "M", "𞤻"), + (0x1E91A, "M", "𞤼"), + (0x1E91B, "M", "𞤽"), + (0x1E91C, "M", "𞤾"), + (0x1E91D, "M", "𞤿"), + (0x1E91E, "M", "𞥀"), + (0x1E91F, "M", "𞥁"), + (0x1E920, "M", "𞥂"), + (0x1E921, "M", "𞥃"), + (0x1E922, "V"), + (0x1E94C, "X"), + (0x1E950, "V"), + (0x1E95A, "X"), + (0x1E95E, "V"), + (0x1E960, "X"), + (0x1EC71, "V"), + (0x1ECB5, "X"), + (0x1ED01, "V"), + (0x1ED3E, "X"), + (0x1EE00, "M", "ا"), + (0x1EE01, "M", "ب"), + (0x1EE02, "M", "ج"), + (0x1EE03, "M", "د"), + (0x1EE04, "X"), + (0x1EE05, "M", "و"), + (0x1EE06, "M", "ز"), + (0x1EE07, "M", "ح"), + (0x1EE08, "M", "ط"), + (0x1EE09, "M", "ي"), + (0x1EE0A, "M", "ك"), + (0x1EE0B, "M", "ل"), + (0x1EE0C, "M", "م"), + (0x1EE0D, "M", "ن"), + (0x1EE0E, "M", "س"), + (0x1EE0F, "M", "ع"), + (0x1EE10, "M", "ف"), + (0x1EE11, "M", "ص"), + (0x1EE12, "M", "ق"), + (0x1EE13, "M", "ر"), + (0x1EE14, "M", "ش"), + (0x1EE15, "M", "ت"), + (0x1EE16, "M", "ث"), + (0x1EE17, "M", "خ"), + (0x1EE18, "M", "ذ"), + (0x1EE19, "M", "ض"), + (0x1EE1A, "M", "ظ"), + (0x1EE1B, "M", "غ"), + (0x1EE1C, "M", "ٮ"), + (0x1EE1D, "M", "ں"), + (0x1EE1E, "M", "ڡ"), + (0x1EE1F, "M", "ٯ"), + (0x1EE20, "X"), + (0x1EE21, "M", "ب"), + (0x1EE22, "M", "ج"), + (0x1EE23, "X"), + (0x1EE24, "M", "ه"), + (0x1EE25, "X"), + (0x1EE27, "M", "ح"), + (0x1EE28, "X"), + (0x1EE29, "M", "ي"), + (0x1EE2A, "M", "ك"), + (0x1EE2B, "M", "ل"), + (0x1EE2C, "M", "م"), + (0x1EE2D, "M", "ن"), + (0x1EE2E, "M", "س"), + (0x1EE2F, "M", "ع"), + (0x1EE30, "M", "ف"), + (0x1EE31, "M", "ص"), + (0x1EE32, "M", "ق"), + (0x1EE33, "X"), + (0x1EE34, "M", "ش"), + (0x1EE35, "M", "ت"), + (0x1EE36, "M", "ث"), + (0x1EE37, "M", "خ"), + (0x1EE38, "X"), + (0x1EE39, "M", "ض"), + (0x1EE3A, "X"), + (0x1EE3B, "M", "غ"), + (0x1EE3C, "X"), + (0x1EE42, "M", "ج"), + (0x1EE43, "X"), + (0x1EE47, "M", "ح"), + (0x1EE48, "X"), + (0x1EE49, "M", "ي"), + (0x1EE4A, "X"), + (0x1EE4B, "M", "ل"), + (0x1EE4C, "X"), + (0x1EE4D, "M", "ن"), + (0x1EE4E, "M", "س"), + ] + + +def _seg_73() -> List[Union[Tuple[int, str], Tuple[int, str, str]]]: + return [ + (0x1EE4F, "M", "ع"), + (0x1EE50, "X"), + (0x1EE51, "M", "ص"), + (0x1EE52, "M", "ق"), + (0x1EE53, "X"), + (0x1EE54, "M", "ش"), + (0x1EE55, "X"), + (0x1EE57, "M", "خ"), + (0x1EE58, "X"), + (0x1EE59, "M", "ض"), + (0x1EE5A, "X"), + (0x1EE5B, "M", "غ"), + (0x1EE5C, "X"), + (0x1EE5D, "M", "ں"), + (0x1EE5E, "X"), + (0x1EE5F, "M", "ٯ"), + (0x1EE60, "X"), + (0x1EE61, "M", "ب"), + (0x1EE62, "M", "ج"), + (0x1EE63, "X"), + (0x1EE64, "M", "ه"), + (0x1EE65, "X"), + (0x1EE67, "M", "ح"), + (0x1EE68, "M", "ط"), + (0x1EE69, "M", "ي"), + (0x1EE6A, "M", "ك"), + (0x1EE6B, "X"), + (0x1EE6C, "M", "م"), + (0x1EE6D, "M", "ن"), + (0x1EE6E, "M", "س"), + (0x1EE6F, "M", "ع"), + (0x1EE70, "M", "ف"), + (0x1EE71, "M", "ص"), + (0x1EE72, "M", "ق"), + (0x1EE73, "X"), + (0x1EE74, "M", "ش"), + (0x1EE75, "M", "ت"), + (0x1EE76, "M", "ث"), + (0x1EE77, "M", "خ"), + (0x1EE78, "X"), + (0x1EE79, "M", "ض"), + (0x1EE7A, "M", "ظ"), + (0x1EE7B, "M", "غ"), + (0x1EE7C, "M", "ٮ"), + (0x1EE7D, "X"), + (0x1EE7E, "M", "ڡ"), + (0x1EE7F, "X"), + (0x1EE80, "M", "ا"), + (0x1EE81, "M", "ب"), + (0x1EE82, "M", "ج"), + (0x1EE83, "M", "د"), + (0x1EE84, "M", "ه"), + (0x1EE85, "M", "و"), + (0x1EE86, "M", "ز"), + (0x1EE87, "M", "ح"), + (0x1EE88, "M", "ط"), + (0x1EE89, "M", "ي"), + (0x1EE8A, "X"), + (0x1EE8B, "M", "ل"), + (0x1EE8C, "M", "م"), + (0x1EE8D, "M", "ن"), + (0x1EE8E, "M", "س"), + (0x1EE8F, "M", "ع"), + (0x1EE90, "M", "ف"), + (0x1EE91, "M", "ص"), + (0x1EE92, "M", "ق"), + (0x1EE93, "M", "ر"), + (0x1EE94, "M", "ش"), + (0x1EE95, "M", "ت"), + (0x1EE96, "M", "ث"), + (0x1EE97, "M", "خ"), + (0x1EE98, "M", "ذ"), + (0x1EE99, "M", "ض"), + (0x1EE9A, "M", "ظ"), + (0x1EE9B, "M", "غ"), + (0x1EE9C, "X"), + (0x1EEA1, "M", "ب"), + (0x1EEA2, "M", "ج"), + (0x1EEA3, "M", "د"), + (0x1EEA4, "X"), + (0x1EEA5, "M", "و"), + (0x1EEA6, "M", "ز"), + (0x1EEA7, "M", "ح"), + (0x1EEA8, "M", "ط"), + (0x1EEA9, "M", "ي"), + (0x1EEAA, "X"), + (0x1EEAB, "M", "ل"), + (0x1EEAC, "M", "م"), + (0x1EEAD, "M", "ن"), + (0x1EEAE, "M", "س"), + (0x1EEAF, "M", "ع"), + (0x1EEB0, "M", "ف"), + (0x1EEB1, "M", "ص"), + (0x1EEB2, "M", "ق"), + (0x1EEB3, "M", "ر"), + (0x1EEB4, "M", "ش"), + (0x1EEB5, "M", "ت"), + (0x1EEB6, "M", "ث"), + (0x1EEB7, "M", "خ"), + (0x1EEB8, "M", "ذ"), + ] + + +def _seg_74() -> List[Union[Tuple[int, str], Tuple[int, str, str]]]: + return [ + (0x1EEB9, "M", "ض"), + (0x1EEBA, "M", "ظ"), + (0x1EEBB, "M", "غ"), + (0x1EEBC, "X"), + (0x1EEF0, "V"), + (0x1EEF2, "X"), + (0x1F000, "V"), + (0x1F02C, "X"), + (0x1F030, "V"), + (0x1F094, "X"), + (0x1F0A0, "V"), + (0x1F0AF, "X"), + (0x1F0B1, "V"), + (0x1F0C0, "X"), + (0x1F0C1, "V"), + (0x1F0D0, "X"), + (0x1F0D1, "V"), + (0x1F0F6, "X"), + (0x1F101, "3", "0,"), + (0x1F102, "3", "1,"), + (0x1F103, "3", "2,"), + (0x1F104, "3", "3,"), + (0x1F105, "3", "4,"), + (0x1F106, "3", "5,"), + (0x1F107, "3", "6,"), + (0x1F108, "3", "7,"), + (0x1F109, "3", "8,"), + (0x1F10A, "3", "9,"), + (0x1F10B, "V"), + (0x1F110, "3", "(a)"), + (0x1F111, "3", "(b)"), + (0x1F112, "3", "(c)"), + (0x1F113, "3", "(d)"), + (0x1F114, "3", "(e)"), + (0x1F115, "3", "(f)"), + (0x1F116, "3", "(g)"), + (0x1F117, "3", "(h)"), + (0x1F118, "3", "(i)"), + (0x1F119, "3", "(j)"), + (0x1F11A, "3", "(k)"), + (0x1F11B, "3", "(l)"), + (0x1F11C, "3", "(m)"), + (0x1F11D, "3", "(n)"), + (0x1F11E, "3", "(o)"), + (0x1F11F, "3", "(p)"), + (0x1F120, "3", "(q)"), + (0x1F121, "3", "(r)"), + (0x1F122, "3", "(s)"), + (0x1F123, "3", "(t)"), + (0x1F124, "3", "(u)"), + (0x1F125, "3", "(v)"), + (0x1F126, "3", "(w)"), + (0x1F127, "3", "(x)"), + (0x1F128, "3", "(y)"), + (0x1F129, "3", "(z)"), + (0x1F12A, "M", "〔s〕"), + (0x1F12B, "M", "c"), + (0x1F12C, "M", "r"), + (0x1F12D, "M", "cd"), + (0x1F12E, "M", "wz"), + (0x1F12F, "V"), + (0x1F130, "M", "a"), + (0x1F131, "M", "b"), + (0x1F132, "M", "c"), + (0x1F133, "M", "d"), + (0x1F134, "M", "e"), + (0x1F135, "M", "f"), + (0x1F136, "M", "g"), + (0x1F137, "M", "h"), + (0x1F138, "M", "i"), + (0x1F139, "M", "j"), + (0x1F13A, "M", "k"), + (0x1F13B, "M", "l"), + (0x1F13C, "M", "m"), + (0x1F13D, "M", "n"), + (0x1F13E, "M", "o"), + (0x1F13F, "M", "p"), + (0x1F140, "M", "q"), + (0x1F141, "M", "r"), + (0x1F142, "M", "s"), + (0x1F143, "M", "t"), + (0x1F144, "M", "u"), + (0x1F145, "M", "v"), + (0x1F146, "M", "w"), + (0x1F147, "M", "x"), + (0x1F148, "M", "y"), + (0x1F149, "M", "z"), + (0x1F14A, "M", "hv"), + (0x1F14B, "M", "mv"), + (0x1F14C, "M", "sd"), + (0x1F14D, "M", "ss"), + (0x1F14E, "M", "ppv"), + (0x1F14F, "M", "wc"), + (0x1F150, "V"), + (0x1F16A, "M", "mc"), + (0x1F16B, "M", "md"), + (0x1F16C, "M", "mr"), + (0x1F16D, "V"), + (0x1F190, "M", "dj"), + (0x1F191, "V"), + ] + + +def _seg_75() -> List[Union[Tuple[int, str], Tuple[int, str, str]]]: + return [ + (0x1F1AE, "X"), + (0x1F1E6, "V"), + (0x1F200, "M", "ほか"), + (0x1F201, "M", "ココ"), + (0x1F202, "M", "サ"), + (0x1F203, "X"), + (0x1F210, "M", "手"), + (0x1F211, "M", "字"), + (0x1F212, "M", "双"), + (0x1F213, "M", "デ"), + (0x1F214, "M", "二"), + (0x1F215, "M", "多"), + (0x1F216, "M", "解"), + (0x1F217, "M", "天"), + (0x1F218, "M", "交"), + (0x1F219, "M", "映"), + (0x1F21A, "M", "無"), + (0x1F21B, "M", "料"), + (0x1F21C, "M", "前"), + (0x1F21D, "M", "後"), + (0x1F21E, "M", "再"), + (0x1F21F, "M", "新"), + (0x1F220, "M", "初"), + (0x1F221, "M", "終"), + (0x1F222, "M", "生"), + (0x1F223, "M", "販"), + (0x1F224, "M", "声"), + (0x1F225, "M", "吹"), + (0x1F226, "M", "演"), + (0x1F227, "M", "投"), + (0x1F228, "M", "捕"), + (0x1F229, "M", "一"), + (0x1F22A, "M", "三"), + (0x1F22B, "M", "遊"), + (0x1F22C, "M", "左"), + (0x1F22D, "M", "中"), + (0x1F22E, "M", "右"), + (0x1F22F, "M", "指"), + (0x1F230, "M", "走"), + (0x1F231, "M", "打"), + (0x1F232, "M", "禁"), + (0x1F233, "M", "空"), + (0x1F234, "M", "合"), + (0x1F235, "M", "満"), + (0x1F236, "M", "有"), + (0x1F237, "M", "月"), + (0x1F238, "M", "申"), + (0x1F239, "M", "割"), + (0x1F23A, "M", "営"), + (0x1F23B, "M", "配"), + (0x1F23C, "X"), + (0x1F240, "M", "〔本〕"), + (0x1F241, "M", "〔三〕"), + (0x1F242, "M", "〔二〕"), + (0x1F243, "M", "〔安〕"), + (0x1F244, "M", "〔点〕"), + (0x1F245, "M", "〔打〕"), + (0x1F246, "M", "〔盗〕"), + (0x1F247, "M", "〔勝〕"), + (0x1F248, "M", "〔敗〕"), + (0x1F249, "X"), + (0x1F250, "M", "得"), + (0x1F251, "M", "可"), + (0x1F252, "X"), + (0x1F260, "V"), + (0x1F266, "X"), + (0x1F300, "V"), + (0x1F6D8, "X"), + (0x1F6DC, "V"), + (0x1F6ED, "X"), + (0x1F6F0, "V"), + (0x1F6FD, "X"), + (0x1F700, "V"), + (0x1F777, "X"), + (0x1F77B, "V"), + (0x1F7DA, "X"), + (0x1F7E0, "V"), + (0x1F7EC, "X"), + (0x1F7F0, "V"), + (0x1F7F1, "X"), + (0x1F800, "V"), + (0x1F80C, "X"), + (0x1F810, "V"), + (0x1F848, "X"), + (0x1F850, "V"), + (0x1F85A, "X"), + (0x1F860, "V"), + (0x1F888, "X"), + (0x1F890, "V"), + (0x1F8AE, "X"), + (0x1F8B0, "V"), + (0x1F8B2, "X"), + (0x1F900, "V"), + (0x1FA54, "X"), + (0x1FA60, "V"), + (0x1FA6E, "X"), + (0x1FA70, "V"), + (0x1FA7D, "X"), + (0x1FA80, "V"), + (0x1FA89, "X"), + ] + + +def _seg_76() -> List[Union[Tuple[int, str], Tuple[int, str, str]]]: + return [ + (0x1FA90, "V"), + (0x1FABE, "X"), + (0x1FABF, "V"), + (0x1FAC6, "X"), + (0x1FACE, "V"), + (0x1FADC, "X"), + (0x1FAE0, "V"), + (0x1FAE9, "X"), + (0x1FAF0, "V"), + (0x1FAF9, "X"), + (0x1FB00, "V"), + (0x1FB93, "X"), + (0x1FB94, "V"), + (0x1FBCB, "X"), + (0x1FBF0, "M", "0"), + (0x1FBF1, "M", "1"), + (0x1FBF2, "M", "2"), + (0x1FBF3, "M", "3"), + (0x1FBF4, "M", "4"), + (0x1FBF5, "M", "5"), + (0x1FBF6, "M", "6"), + (0x1FBF7, "M", "7"), + (0x1FBF8, "M", "8"), + (0x1FBF9, "M", "9"), + (0x1FBFA, "X"), + (0x20000, "V"), + (0x2A6E0, "X"), + (0x2A700, "V"), + (0x2B73A, "X"), + (0x2B740, "V"), + (0x2B81E, "X"), + (0x2B820, "V"), + (0x2CEA2, "X"), + (0x2CEB0, "V"), + (0x2EBE1, "X"), + (0x2EBF0, "V"), + (0x2EE5E, "X"), + (0x2F800, "M", "丽"), + (0x2F801, "M", "丸"), + (0x2F802, "M", "乁"), + (0x2F803, "M", "𠄢"), + (0x2F804, "M", "你"), + (0x2F805, "M", "侮"), + (0x2F806, "M", "侻"), + (0x2F807, "M", "倂"), + (0x2F808, "M", "偺"), + (0x2F809, "M", "備"), + (0x2F80A, "M", "僧"), + (0x2F80B, "M", "像"), + (0x2F80C, "M", "㒞"), + (0x2F80D, "M", "𠘺"), + (0x2F80E, "M", "免"), + (0x2F80F, "M", "兔"), + (0x2F810, "M", "兤"), + (0x2F811, "M", "具"), + (0x2F812, "M", "𠔜"), + (0x2F813, "M", "㒹"), + (0x2F814, "M", "內"), + (0x2F815, "M", "再"), + (0x2F816, "M", "𠕋"), + (0x2F817, "M", "冗"), + (0x2F818, "M", "冤"), + (0x2F819, "M", "仌"), + (0x2F81A, "M", "冬"), + (0x2F81B, "M", "况"), + (0x2F81C, "M", "𩇟"), + (0x2F81D, "M", "凵"), + (0x2F81E, "M", "刃"), + (0x2F81F, "M", "㓟"), + (0x2F820, "M", "刻"), + (0x2F821, "M", "剆"), + (0x2F822, "M", "割"), + (0x2F823, "M", "剷"), + (0x2F824, "M", "㔕"), + (0x2F825, "M", "勇"), + (0x2F826, "M", "勉"), + (0x2F827, "M", "勤"), + (0x2F828, "M", "勺"), + (0x2F829, "M", "包"), + (0x2F82A, "M", "匆"), + (0x2F82B, "M", "北"), + (0x2F82C, "M", "卉"), + (0x2F82D, "M", "卑"), + (0x2F82E, "M", "博"), + (0x2F82F, "M", "即"), + (0x2F830, "M", "卽"), + (0x2F831, "M", "卿"), + (0x2F834, "M", "𠨬"), + (0x2F835, "M", "灰"), + (0x2F836, "M", "及"), + (0x2F837, "M", "叟"), + (0x2F838, "M", "𠭣"), + (0x2F839, "M", "叫"), + (0x2F83A, "M", "叱"), + (0x2F83B, "M", "吆"), + (0x2F83C, "M", "咞"), + (0x2F83D, "M", "吸"), + (0x2F83E, "M", "呈"), + (0x2F83F, "M", "周"), + (0x2F840, "M", "咢"), + ] + + +def _seg_77() -> List[Union[Tuple[int, str], Tuple[int, str, str]]]: + return [ + (0x2F841, "M", "哶"), + (0x2F842, "M", "唐"), + (0x2F843, "M", "啓"), + (0x2F844, "M", "啣"), + (0x2F845, "M", "善"), + (0x2F847, "M", "喙"), + (0x2F848, "M", "喫"), + (0x2F849, "M", "喳"), + (0x2F84A, "M", "嗂"), + (0x2F84B, "M", "圖"), + (0x2F84C, "M", "嘆"), + (0x2F84D, "M", "圗"), + (0x2F84E, "M", "噑"), + (0x2F84F, "M", "噴"), + (0x2F850, "M", "切"), + (0x2F851, "M", "壮"), + (0x2F852, "M", "城"), + (0x2F853, "M", "埴"), + (0x2F854, "M", "堍"), + (0x2F855, "M", "型"), + (0x2F856, "M", "堲"), + (0x2F857, "M", "報"), + (0x2F858, "M", "墬"), + (0x2F859, "M", "𡓤"), + (0x2F85A, "M", "売"), + (0x2F85B, "M", "壷"), + (0x2F85C, "M", "夆"), + (0x2F85D, "M", "多"), + (0x2F85E, "M", "夢"), + (0x2F85F, "M", "奢"), + (0x2F860, "M", "𡚨"), + (0x2F861, "M", "𡛪"), + (0x2F862, "M", "姬"), + (0x2F863, "M", "娛"), + (0x2F864, "M", "娧"), + (0x2F865, "M", "姘"), + (0x2F866, "M", "婦"), + (0x2F867, "M", "㛮"), + (0x2F868, "X"), + (0x2F869, "M", "嬈"), + (0x2F86A, "M", "嬾"), + (0x2F86C, "M", "𡧈"), + (0x2F86D, "M", "寃"), + (0x2F86E, "M", "寘"), + (0x2F86F, "M", "寧"), + (0x2F870, "M", "寳"), + (0x2F871, "M", "𡬘"), + (0x2F872, "M", "寿"), + (0x2F873, "M", "将"), + (0x2F874, "X"), + (0x2F875, "M", "尢"), + (0x2F876, "M", "㞁"), + (0x2F877, "M", "屠"), + (0x2F878, "M", "屮"), + (0x2F879, "M", "峀"), + (0x2F87A, "M", "岍"), + (0x2F87B, "M", "𡷤"), + (0x2F87C, "M", "嵃"), + (0x2F87D, "M", "𡷦"), + (0x2F87E, "M", "嵮"), + (0x2F87F, "M", "嵫"), + (0x2F880, "M", "嵼"), + (0x2F881, "M", "巡"), + (0x2F882, "M", "巢"), + (0x2F883, "M", "㠯"), + (0x2F884, "M", "巽"), + (0x2F885, "M", "帨"), + (0x2F886, "M", "帽"), + (0x2F887, "M", "幩"), + (0x2F888, "M", "㡢"), + (0x2F889, "M", "𢆃"), + (0x2F88A, "M", "㡼"), + (0x2F88B, "M", "庰"), + (0x2F88C, "M", "庳"), + (0x2F88D, "M", "庶"), + (0x2F88E, "M", "廊"), + (0x2F88F, "M", "𪎒"), + (0x2F890, "M", "廾"), + (0x2F891, "M", "𢌱"), + (0x2F893, "M", "舁"), + (0x2F894, "M", "弢"), + (0x2F896, "M", "㣇"), + (0x2F897, "M", "𣊸"), + (0x2F898, "M", "𦇚"), + (0x2F899, "M", "形"), + (0x2F89A, "M", "彫"), + (0x2F89B, "M", "㣣"), + (0x2F89C, "M", "徚"), + (0x2F89D, "M", "忍"), + (0x2F89E, "M", "志"), + (0x2F89F, "M", "忹"), + (0x2F8A0, "M", "悁"), + (0x2F8A1, "M", "㤺"), + (0x2F8A2, "M", "㤜"), + (0x2F8A3, "M", "悔"), + (0x2F8A4, "M", "𢛔"), + (0x2F8A5, "M", "惇"), + (0x2F8A6, "M", "慈"), + (0x2F8A7, "M", "慌"), + (0x2F8A8, "M", "慎"), + ] + + +def _seg_78() -> List[Union[Tuple[int, str], Tuple[int, str, str]]]: + return [ + (0x2F8A9, "M", "慌"), + (0x2F8AA, "M", "慺"), + (0x2F8AB, "M", "憎"), + (0x2F8AC, "M", "憲"), + (0x2F8AD, "M", "憤"), + (0x2F8AE, "M", "憯"), + (0x2F8AF, "M", "懞"), + (0x2F8B0, "M", "懲"), + (0x2F8B1, "M", "懶"), + (0x2F8B2, "M", "成"), + (0x2F8B3, "M", "戛"), + (0x2F8B4, "M", "扝"), + (0x2F8B5, "M", "抱"), + (0x2F8B6, "M", "拔"), + (0x2F8B7, "M", "捐"), + (0x2F8B8, "M", "𢬌"), + (0x2F8B9, "M", "挽"), + (0x2F8BA, "M", "拼"), + (0x2F8BB, "M", "捨"), + (0x2F8BC, "M", "掃"), + (0x2F8BD, "M", "揤"), + (0x2F8BE, "M", "𢯱"), + (0x2F8BF, "M", "搢"), + (0x2F8C0, "M", "揅"), + (0x2F8C1, "M", "掩"), + (0x2F8C2, "M", "㨮"), + (0x2F8C3, "M", "摩"), + (0x2F8C4, "M", "摾"), + (0x2F8C5, "M", "撝"), + (0x2F8C6, "M", "摷"), + (0x2F8C7, "M", "㩬"), + (0x2F8C8, "M", "敏"), + (0x2F8C9, "M", "敬"), + (0x2F8CA, "M", "𣀊"), + (0x2F8CB, "M", "旣"), + (0x2F8CC, "M", "書"), + (0x2F8CD, "M", "晉"), + (0x2F8CE, "M", "㬙"), + (0x2F8CF, "M", "暑"), + (0x2F8D0, "M", "㬈"), + (0x2F8D1, "M", "㫤"), + (0x2F8D2, "M", "冒"), + (0x2F8D3, "M", "冕"), + (0x2F8D4, "M", "最"), + (0x2F8D5, "M", "暜"), + (0x2F8D6, "M", "肭"), + (0x2F8D7, "M", "䏙"), + (0x2F8D8, "M", "朗"), + (0x2F8D9, "M", "望"), + (0x2F8DA, "M", "朡"), + (0x2F8DB, "M", "杞"), + (0x2F8DC, "M", "杓"), + (0x2F8DD, "M", "𣏃"), + (0x2F8DE, "M", "㭉"), + (0x2F8DF, "M", "柺"), + (0x2F8E0, "M", "枅"), + (0x2F8E1, "M", "桒"), + (0x2F8E2, "M", "梅"), + (0x2F8E3, "M", "𣑭"), + (0x2F8E4, "M", "梎"), + (0x2F8E5, "M", "栟"), + (0x2F8E6, "M", "椔"), + (0x2F8E7, "M", "㮝"), + (0x2F8E8, "M", "楂"), + (0x2F8E9, "M", "榣"), + (0x2F8EA, "M", "槪"), + (0x2F8EB, "M", "檨"), + (0x2F8EC, "M", "𣚣"), + (0x2F8ED, "M", "櫛"), + (0x2F8EE, "M", "㰘"), + (0x2F8EF, "M", "次"), + (0x2F8F0, "M", "𣢧"), + (0x2F8F1, "M", "歔"), + (0x2F8F2, "M", "㱎"), + (0x2F8F3, "M", "歲"), + (0x2F8F4, "M", "殟"), + (0x2F8F5, "M", "殺"), + (0x2F8F6, "M", "殻"), + (0x2F8F7, "M", "𣪍"), + (0x2F8F8, "M", "𡴋"), + (0x2F8F9, "M", "𣫺"), + (0x2F8FA, "M", "汎"), + (0x2F8FB, "M", "𣲼"), + (0x2F8FC, "M", "沿"), + (0x2F8FD, "M", "泍"), + (0x2F8FE, "M", "汧"), + (0x2F8FF, "M", "洖"), + (0x2F900, "M", "派"), + (0x2F901, "M", "海"), + (0x2F902, "M", "流"), + (0x2F903, "M", "浩"), + (0x2F904, "M", "浸"), + (0x2F905, "M", "涅"), + (0x2F906, "M", "𣴞"), + (0x2F907, "M", "洴"), + (0x2F908, "M", "港"), + (0x2F909, "M", "湮"), + (0x2F90A, "M", "㴳"), + (0x2F90B, "M", "滋"), + (0x2F90C, "M", "滇"), + ] + + +def _seg_79() -> List[Union[Tuple[int, str], Tuple[int, str, str]]]: + return [ + (0x2F90D, "M", "𣻑"), + (0x2F90E, "M", "淹"), + (0x2F90F, "M", "潮"), + (0x2F910, "M", "𣽞"), + (0x2F911, "M", "𣾎"), + (0x2F912, "M", "濆"), + (0x2F913, "M", "瀹"), + (0x2F914, "M", "瀞"), + (0x2F915, "M", "瀛"), + (0x2F916, "M", "㶖"), + (0x2F917, "M", "灊"), + (0x2F918, "M", "災"), + (0x2F919, "M", "灷"), + (0x2F91A, "M", "炭"), + (0x2F91B, "M", "𠔥"), + (0x2F91C, "M", "煅"), + (0x2F91D, "M", "𤉣"), + (0x2F91E, "M", "熜"), + (0x2F91F, "X"), + (0x2F920, "M", "爨"), + (0x2F921, "M", "爵"), + (0x2F922, "M", "牐"), + (0x2F923, "M", "𤘈"), + (0x2F924, "M", "犀"), + (0x2F925, "M", "犕"), + (0x2F926, "M", "𤜵"), + (0x2F927, "M", "𤠔"), + (0x2F928, "M", "獺"), + (0x2F929, "M", "王"), + (0x2F92A, "M", "㺬"), + (0x2F92B, "M", "玥"), + (0x2F92C, "M", "㺸"), + (0x2F92E, "M", "瑇"), + (0x2F92F, "M", "瑜"), + (0x2F930, "M", "瑱"), + (0x2F931, "M", "璅"), + (0x2F932, "M", "瓊"), + (0x2F933, "M", "㼛"), + (0x2F934, "M", "甤"), + (0x2F935, "M", "𤰶"), + (0x2F936, "M", "甾"), + (0x2F937, "M", "𤲒"), + (0x2F938, "M", "異"), + (0x2F939, "M", "𢆟"), + (0x2F93A, "M", "瘐"), + (0x2F93B, "M", "𤾡"), + (0x2F93C, "M", "𤾸"), + (0x2F93D, "M", "𥁄"), + (0x2F93E, "M", "㿼"), + (0x2F93F, "M", "䀈"), + (0x2F940, "M", "直"), + (0x2F941, "M", "𥃳"), + (0x2F942, "M", "𥃲"), + (0x2F943, "M", "𥄙"), + (0x2F944, "M", "𥄳"), + (0x2F945, "M", "眞"), + (0x2F946, "M", "真"), + (0x2F948, "M", "睊"), + (0x2F949, "M", "䀹"), + (0x2F94A, "M", "瞋"), + (0x2F94B, "M", "䁆"), + (0x2F94C, "M", "䂖"), + (0x2F94D, "M", "𥐝"), + (0x2F94E, "M", "硎"), + (0x2F94F, "M", "碌"), + (0x2F950, "M", "磌"), + (0x2F951, "M", "䃣"), + (0x2F952, "M", "𥘦"), + (0x2F953, "M", "祖"), + (0x2F954, "M", "𥚚"), + (0x2F955, "M", "𥛅"), + (0x2F956, "M", "福"), + (0x2F957, "M", "秫"), + (0x2F958, "M", "䄯"), + (0x2F959, "M", "穀"), + (0x2F95A, "M", "穊"), + (0x2F95B, "M", "穏"), + (0x2F95C, "M", "𥥼"), + (0x2F95D, "M", "𥪧"), + (0x2F95F, "X"), + (0x2F960, "M", "䈂"), + (0x2F961, "M", "𥮫"), + (0x2F962, "M", "篆"), + (0x2F963, "M", "築"), + (0x2F964, "M", "䈧"), + (0x2F965, "M", "𥲀"), + (0x2F966, "M", "糒"), + (0x2F967, "M", "䊠"), + (0x2F968, "M", "糨"), + (0x2F969, "M", "糣"), + (0x2F96A, "M", "紀"), + (0x2F96B, "M", "𥾆"), + (0x2F96C, "M", "絣"), + (0x2F96D, "M", "䌁"), + (0x2F96E, "M", "緇"), + (0x2F96F, "M", "縂"), + (0x2F970, "M", "繅"), + (0x2F971, "M", "䌴"), + (0x2F972, "M", "𦈨"), + (0x2F973, "M", "𦉇"), + ] + + +def _seg_80() -> List[Union[Tuple[int, str], Tuple[int, str, str]]]: + return [ + (0x2F974, "M", "䍙"), + (0x2F975, "M", "𦋙"), + (0x2F976, "M", "罺"), + (0x2F977, "M", "𦌾"), + (0x2F978, "M", "羕"), + (0x2F979, "M", "翺"), + (0x2F97A, "M", "者"), + (0x2F97B, "M", "𦓚"), + (0x2F97C, "M", "𦔣"), + (0x2F97D, "M", "聠"), + (0x2F97E, "M", "𦖨"), + (0x2F97F, "M", "聰"), + (0x2F980, "M", "𣍟"), + (0x2F981, "M", "䏕"), + (0x2F982, "M", "育"), + (0x2F983, "M", "脃"), + (0x2F984, "M", "䐋"), + (0x2F985, "M", "脾"), + (0x2F986, "M", "媵"), + (0x2F987, "M", "𦞧"), + (0x2F988, "M", "𦞵"), + (0x2F989, "M", "𣎓"), + (0x2F98A, "M", "𣎜"), + (0x2F98B, "M", "舁"), + (0x2F98C, "M", "舄"), + (0x2F98D, "M", "辞"), + (0x2F98E, "M", "䑫"), + (0x2F98F, "M", "芑"), + (0x2F990, "M", "芋"), + (0x2F991, "M", "芝"), + (0x2F992, "M", "劳"), + (0x2F993, "M", "花"), + (0x2F994, "M", "芳"), + (0x2F995, "M", "芽"), + (0x2F996, "M", "苦"), + (0x2F997, "M", "𦬼"), + (0x2F998, "M", "若"), + (0x2F999, "M", "茝"), + (0x2F99A, "M", "荣"), + (0x2F99B, "M", "莭"), + (0x2F99C, "M", "茣"), + (0x2F99D, "M", "莽"), + (0x2F99E, "M", "菧"), + (0x2F99F, "M", "著"), + (0x2F9A0, "M", "荓"), + (0x2F9A1, "M", "菊"), + (0x2F9A2, "M", "菌"), + (0x2F9A3, "M", "菜"), + (0x2F9A4, "M", "𦰶"), + (0x2F9A5, "M", "𦵫"), + (0x2F9A6, "M", "𦳕"), + (0x2F9A7, "M", "䔫"), + (0x2F9A8, "M", "蓱"), + (0x2F9A9, "M", "蓳"), + (0x2F9AA, "M", "蔖"), + (0x2F9AB, "M", "𧏊"), + (0x2F9AC, "M", "蕤"), + (0x2F9AD, "M", "𦼬"), + (0x2F9AE, "M", "䕝"), + (0x2F9AF, "M", "䕡"), + (0x2F9B0, "M", "𦾱"), + (0x2F9B1, "M", "𧃒"), + (0x2F9B2, "M", "䕫"), + (0x2F9B3, "M", "虐"), + (0x2F9B4, "M", "虜"), + (0x2F9B5, "M", "虧"), + (0x2F9B6, "M", "虩"), + (0x2F9B7, "M", "蚩"), + (0x2F9B8, "M", "蚈"), + (0x2F9B9, "M", "蜎"), + (0x2F9BA, "M", "蛢"), + (0x2F9BB, "M", "蝹"), + (0x2F9BC, "M", "蜨"), + (0x2F9BD, "M", "蝫"), + (0x2F9BE, "M", "螆"), + (0x2F9BF, "X"), + (0x2F9C0, "M", "蟡"), + (0x2F9C1, "M", "蠁"), + (0x2F9C2, "M", "䗹"), + (0x2F9C3, "M", "衠"), + (0x2F9C4, "M", "衣"), + (0x2F9C5, "M", "𧙧"), + (0x2F9C6, "M", "裗"), + (0x2F9C7, "M", "裞"), + (0x2F9C8, "M", "䘵"), + (0x2F9C9, "M", "裺"), + (0x2F9CA, "M", "㒻"), + (0x2F9CB, "M", "𧢮"), + (0x2F9CC, "M", "𧥦"), + (0x2F9CD, "M", "䚾"), + (0x2F9CE, "M", "䛇"), + (0x2F9CF, "M", "誠"), + (0x2F9D0, "M", "諭"), + (0x2F9D1, "M", "變"), + (0x2F9D2, "M", "豕"), + (0x2F9D3, "M", "𧲨"), + (0x2F9D4, "M", "貫"), + (0x2F9D5, "M", "賁"), + (0x2F9D6, "M", "贛"), + (0x2F9D7, "M", "起"), + ] + + +def _seg_81() -> List[Union[Tuple[int, str], Tuple[int, str, str]]]: + return [ + (0x2F9D8, "M", "𧼯"), + (0x2F9D9, "M", "𠠄"), + (0x2F9DA, "M", "跋"), + (0x2F9DB, "M", "趼"), + (0x2F9DC, "M", "跰"), + (0x2F9DD, "M", "𠣞"), + (0x2F9DE, "M", "軔"), + (0x2F9DF, "M", "輸"), + (0x2F9E0, "M", "𨗒"), + (0x2F9E1, "M", "𨗭"), + (0x2F9E2, "M", "邔"), + (0x2F9E3, "M", "郱"), + (0x2F9E4, "M", "鄑"), + (0x2F9E5, "M", "𨜮"), + (0x2F9E6, "M", "鄛"), + (0x2F9E7, "M", "鈸"), + (0x2F9E8, "M", "鋗"), + (0x2F9E9, "M", "鋘"), + (0x2F9EA, "M", "鉼"), + (0x2F9EB, "M", "鏹"), + (0x2F9EC, "M", "鐕"), + (0x2F9ED, "M", "𨯺"), + (0x2F9EE, "M", "開"), + (0x2F9EF, "M", "䦕"), + (0x2F9F0, "M", "閷"), + (0x2F9F1, "M", "𨵷"), + (0x2F9F2, "M", "䧦"), + (0x2F9F3, "M", "雃"), + (0x2F9F4, "M", "嶲"), + (0x2F9F5, "M", "霣"), + (0x2F9F6, "M", "𩅅"), + (0x2F9F7, "M", "𩈚"), + (0x2F9F8, "M", "䩮"), + (0x2F9F9, "M", "䩶"), + (0x2F9FA, "M", "韠"), + (0x2F9FB, "M", "𩐊"), + (0x2F9FC, "M", "䪲"), + (0x2F9FD, "M", "𩒖"), + (0x2F9FE, "M", "頋"), + (0x2FA00, "M", "頩"), + (0x2FA01, "M", "𩖶"), + (0x2FA02, "M", "飢"), + (0x2FA03, "M", "䬳"), + (0x2FA04, "M", "餩"), + (0x2FA05, "M", "馧"), + (0x2FA06, "M", "駂"), + (0x2FA07, "M", "駾"), + (0x2FA08, "M", "䯎"), + (0x2FA09, "M", "𩬰"), + (0x2FA0A, "M", "鬒"), + (0x2FA0B, "M", "鱀"), + (0x2FA0C, "M", "鳽"), + (0x2FA0D, "M", "䳎"), + (0x2FA0E, "M", "䳭"), + (0x2FA0F, "M", "鵧"), + (0x2FA10, "M", "𪃎"), + (0x2FA11, "M", "䳸"), + (0x2FA12, "M", "𪄅"), + (0x2FA13, "M", "𪈎"), + (0x2FA14, "M", "𪊑"), + (0x2FA15, "M", "麻"), + (0x2FA16, "M", "䵖"), + (0x2FA17, "M", "黹"), + (0x2FA18, "M", "黾"), + (0x2FA19, "M", "鼅"), + (0x2FA1A, "M", "鼏"), + (0x2FA1B, "M", "鼖"), + (0x2FA1C, "M", "鼻"), + (0x2FA1D, "M", "𪘀"), + (0x2FA1E, "X"), + (0x30000, "V"), + (0x3134B, "X"), + (0x31350, "V"), + (0x323B0, "X"), + (0xE0100, "I"), + (0xE01F0, "X"), + ] + + +uts46data = tuple( + _seg_0() + + _seg_1() + + _seg_2() + + _seg_3() + + _seg_4() + + _seg_5() + + _seg_6() + + _seg_7() + + _seg_8() + + _seg_9() + + _seg_10() + + _seg_11() + + _seg_12() + + _seg_13() + + _seg_14() + + _seg_15() + + _seg_16() + + _seg_17() + + _seg_18() + + _seg_19() + + _seg_20() + + _seg_21() + + _seg_22() + + _seg_23() + + _seg_24() + + _seg_25() + + _seg_26() + + _seg_27() + + _seg_28() + + _seg_29() + + _seg_30() + + _seg_31() + + _seg_32() + + _seg_33() + + _seg_34() + + _seg_35() + + _seg_36() + + _seg_37() + + _seg_38() + + _seg_39() + + _seg_40() + + _seg_41() + + _seg_42() + + _seg_43() + + _seg_44() + + _seg_45() + + _seg_46() + + _seg_47() + + _seg_48() + + _seg_49() + + _seg_50() + + _seg_51() + + _seg_52() + + _seg_53() + + _seg_54() + + _seg_55() + + _seg_56() + + _seg_57() + + _seg_58() + + _seg_59() + + _seg_60() + + _seg_61() + + _seg_62() + + _seg_63() + + _seg_64() + + _seg_65() + + _seg_66() + + _seg_67() + + _seg_68() + + _seg_69() + + _seg_70() + + _seg_71() + + _seg_72() + + _seg_73() + + _seg_74() + + _seg_75() + + _seg_76() + + _seg_77() + + _seg_78() + + _seg_79() + + _seg_80() + + _seg_81() +) # type: Tuple[Union[Tuple[int, str], Tuple[int, str, str]], ...] diff --git a/psets/9/finance/env/lib/python3.12/site-packages/itsdangerous-2.2.0.dist-info/INSTALLER b/psets/9/finance/env/lib/python3.12/site-packages/itsdangerous-2.2.0.dist-info/INSTALLER new file mode 100644 index 0000000..a1b589e --- /dev/null +++ b/psets/9/finance/env/lib/python3.12/site-packages/itsdangerous-2.2.0.dist-info/INSTALLER @@ -0,0 +1 @@ +pip diff --git a/psets/9/finance/env/lib/python3.12/site-packages/itsdangerous-2.2.0.dist-info/LICENSE.txt b/psets/9/finance/env/lib/python3.12/site-packages/itsdangerous-2.2.0.dist-info/LICENSE.txt new file mode 100644 index 0000000..7b190ca --- /dev/null +++ b/psets/9/finance/env/lib/python3.12/site-packages/itsdangerous-2.2.0.dist-info/LICENSE.txt @@ -0,0 +1,28 @@ +Copyright 2011 Pallets + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met: + +1. Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + +2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + +3. Neither the name of the copyright holder nor the names of its + contributors may be used to endorse or promote products derived from + this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A +PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED +TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR +PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF +LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING +NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/psets/9/finance/env/lib/python3.12/site-packages/itsdangerous-2.2.0.dist-info/METADATA b/psets/9/finance/env/lib/python3.12/site-packages/itsdangerous-2.2.0.dist-info/METADATA new file mode 100644 index 0000000..ddf5464 --- /dev/null +++ b/psets/9/finance/env/lib/python3.12/site-packages/itsdangerous-2.2.0.dist-info/METADATA @@ -0,0 +1,60 @@ +Metadata-Version: 2.1 +Name: itsdangerous +Version: 2.2.0 +Summary: Safely pass data to untrusted environments and back. +Maintainer-email: Pallets +Requires-Python: >=3.8 +Description-Content-Type: text/markdown +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 +Classifier: Typing :: Typed +Project-URL: Changes, https://itsdangerous.palletsprojects.com/changes/ +Project-URL: Chat, https://discord.gg/pallets +Project-URL: Documentation, https://itsdangerous.palletsprojects.com/ +Project-URL: Donate, https://palletsprojects.com/donate +Project-URL: Source, https://github.com/pallets/itsdangerous/ + +# ItsDangerous + +... so better sign this + +Various helpers to pass data to untrusted environments and to get it +back safe and sound. Data is cryptographically signed to ensure that a +token has not been tampered with. + +It's possible to customize how data is serialized. Data is compressed as +needed. A timestamp can be added and verified automatically while +loading a token. + + +## A Simple Example + +Here's how you could generate a token for transmitting a user's id and +name between web requests. + +```python +from itsdangerous import URLSafeSerializer +auth_s = URLSafeSerializer("secret key", "auth") +token = auth_s.dumps({"id": 5, "name": "itsdangerous"}) + +print(token) +# eyJpZCI6NSwibmFtZSI6Iml0c2Rhbmdlcm91cyJ9.6YP6T0BaO67XP--9UzTrmurXSmg + +data = auth_s.loads(token) +print(data["name"]) +# itsdangerous +``` + + +## Donate + +The Pallets organization develops and supports ItsDangerous and other +popular packages. In order to grow the community of contributors and +users, and allow the maintainers to devote more time to the projects, +[please donate today][]. + +[please donate today]: https://palletsprojects.com/donate + diff --git a/psets/9/finance/env/lib/python3.12/site-packages/itsdangerous-2.2.0.dist-info/RECORD b/psets/9/finance/env/lib/python3.12/site-packages/itsdangerous-2.2.0.dist-info/RECORD new file mode 100644 index 0000000..1394876 --- /dev/null +++ b/psets/9/finance/env/lib/python3.12/site-packages/itsdangerous-2.2.0.dist-info/RECORD @@ -0,0 +1,22 @@ +itsdangerous-2.2.0.dist-info/INSTALLER,sha256=zuuue4knoyJ-UwPPXg8fezS7VCrXJQrAP7zeNuwvFQg,4 +itsdangerous-2.2.0.dist-info/LICENSE.txt,sha256=Y68JiRtr6K0aQlLtQ68PTvun_JSOIoNnvtfzxa4LCdc,1475 +itsdangerous-2.2.0.dist-info/METADATA,sha256=0rk0-1ZwihuU5DnwJVwPWoEI4yWOyCexih3JyZHblhE,1924 +itsdangerous-2.2.0.dist-info/RECORD,, +itsdangerous-2.2.0.dist-info/WHEEL,sha256=EZbGkh7Ie4PoZfRQ8I0ZuP9VklN_TvcZ6DSE5Uar4z4,81 +itsdangerous/__init__.py,sha256=4SK75sCe29xbRgQE1ZQtMHnKUuZYAf3bSpZOrff1IAY,1427 +itsdangerous/__pycache__/__init__.cpython-312.pyc,, +itsdangerous/__pycache__/_json.cpython-312.pyc,, +itsdangerous/__pycache__/encoding.cpython-312.pyc,, +itsdangerous/__pycache__/exc.cpython-312.pyc,, +itsdangerous/__pycache__/serializer.cpython-312.pyc,, +itsdangerous/__pycache__/signer.cpython-312.pyc,, +itsdangerous/__pycache__/timed.cpython-312.pyc,, +itsdangerous/__pycache__/url_safe.cpython-312.pyc,, +itsdangerous/_json.py,sha256=wPQGmge2yZ9328EHKF6gadGeyGYCJQKxtU-iLKE6UnA,473 +itsdangerous/encoding.py,sha256=wwTz5q_3zLcaAdunk6_vSoStwGqYWe307Zl_U87aRFM,1409 +itsdangerous/exc.py,sha256=Rr3exo0MRFEcPZltwecyK16VV1bE2K9_F1-d-ljcUn4,3201 +itsdangerous/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0 +itsdangerous/serializer.py,sha256=PmdwADLqkSyQLZ0jOKAgDsAW4k_H0TlA71Ei3z0C5aI,15601 +itsdangerous/signer.py,sha256=YO0CV7NBvHA6j549REHJFUjUojw2pHqwcUpQnU7yNYQ,9647 +itsdangerous/timed.py,sha256=6RvDMqNumGMxf0-HlpaZdN9PUQQmRvrQGplKhxuivUs,8083 +itsdangerous/url_safe.py,sha256=az4e5fXi_vs-YbWj8YZwn4wiVKfeD--GEKRT5Ueu4P4,2505 diff --git a/psets/9/finance/env/lib/python3.12/site-packages/itsdangerous-2.2.0.dist-info/WHEEL b/psets/9/finance/env/lib/python3.12/site-packages/itsdangerous-2.2.0.dist-info/WHEEL new file mode 100644 index 0000000..3b5e64b --- /dev/null +++ b/psets/9/finance/env/lib/python3.12/site-packages/itsdangerous-2.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/psets/9/finance/env/lib/python3.12/site-packages/itsdangerous/__init__.py b/psets/9/finance/env/lib/python3.12/site-packages/itsdangerous/__init__.py new file mode 100644 index 0000000..ea55256 --- /dev/null +++ b/psets/9/finance/env/lib/python3.12/site-packages/itsdangerous/__init__.py @@ -0,0 +1,38 @@ +from __future__ import annotations + +import typing as t + +from .encoding import base64_decode as base64_decode +from .encoding import base64_encode as base64_encode +from .encoding import want_bytes as want_bytes +from .exc import BadData as BadData +from .exc import BadHeader as BadHeader +from .exc import BadPayload as BadPayload +from .exc import BadSignature as BadSignature +from .exc import BadTimeSignature as BadTimeSignature +from .exc import SignatureExpired as SignatureExpired +from .serializer import Serializer as Serializer +from .signer import HMACAlgorithm as HMACAlgorithm +from .signer import NoneAlgorithm as NoneAlgorithm +from .signer import Signer as Signer +from .timed import TimedSerializer as TimedSerializer +from .timed import TimestampSigner as TimestampSigner +from .url_safe import URLSafeSerializer as URLSafeSerializer +from .url_safe import URLSafeTimedSerializer as URLSafeTimedSerializer + + +def __getattr__(name: str) -> t.Any: + if name == "__version__": + import importlib.metadata + import warnings + + warnings.warn( + "The '__version__' attribute is deprecated and will be removed in" + " ItsDangerous 2.3. Use feature detection or" + " 'importlib.metadata.version(\"itsdangerous\")' instead.", + DeprecationWarning, + stacklevel=2, + ) + return importlib.metadata.version("itsdangerous") + + raise AttributeError(name) diff --git a/psets/9/finance/env/lib/python3.12/site-packages/itsdangerous/__pycache__/__init__.cpython-312.pyc b/psets/9/finance/env/lib/python3.12/site-packages/itsdangerous/__pycache__/__init__.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..6fa7cd2e7fca91f3e1bcd53948c0998bdf4754ce GIT binary patch literal 1631 zcmZXU&u`pB6vxN=!|U~~cQ>2gC2E~eNPXzKBrQ@zg%p}Xksv~BD}*m*vNPE@wa2UR zY|@Pq2_X(};=rN3as!pWgA13I9$L9t38`?1#3530;>4TDZnP;QYy5fN8NYcm?~Q-A zEE7TdZU4*mk9mY%Nn_YDr=T7G1MmMre0i|Sro zaTR#n8&_Ndp716VkA;)blsBcg4m|BmD;^JLqFHZN@dWS%?*i}?nfx~Az0u1!(}!~F zj+T}%W3j*@h*`3JsGW+|22SX^*L^};F`+PPC{Q*K%w5ccztIykf#Jdjn5a87Q_A}dZ?rV)?g+7!>?$`Wd@Fkmu_O)%} zlt=sR(x`RHM1MSpsELF%9N$Mn^&8D8tfwX4-=RE#9Q!_(MZfpc-7RV_j>wBP7J>&G zT|w<2u?g*P+QNbo8#7|>24QG#P@B^z-T^IO_QxVw!>mnt+)eDI#&W~Hmr#3?s_eq| zg0^H)*)g{lgQyd85e6HLhzd-gQW}GJt}Fy1Awxe4&LX%@1k_LCP{t{<56NoX59tmK z)AHzKr;yhF?>IGfF=qj5CuvSnT3;J%1%mnFbSO23VWfpY9BE~Bxc%Fl$K1)LIff&e z7SER8a}ZD>b7b50zhAi#6D|}zWiH$aSkP@HH?Fyzgo?ynaW?~oS&O=q?YOXUx6>0_ zFD{2L;V=Q;IhuSENfm+uIPgnm$l4`vXj4JF3XsgWhV<35`1>Oc|{6( zqV6xR$|*J3jY&B#7%QCbVEJY`e;c#mxs#DKKk%PuV|Ol GBL4vegu}!D literal 0 HcmV?d00001 diff --git a/psets/9/finance/env/lib/python3.12/site-packages/itsdangerous/__pycache__/_json.cpython-312.pyc b/psets/9/finance/env/lib/python3.12/site-packages/itsdangerous/__pycache__/_json.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..f38788423fda5800dcfb7ddbd566536a30ee1f26 GIT binary patch literal 1185 zcmZ`&y=xRf6rb6zTQAYz8AS_WF)D0~w`%-A5kV9Mi?gs04`i9_OfGxg&8{64XWkeChE!4(!j5Rh|M%~PJt8N?UCZgsNqSl&Gc-5V*;oIN!!N=JM z;XF}9#R-?SsIVxcS!{zK4An73b%Wx%$t-G9W64_U+t+Q-I1pw><8&>*l#Pbhl6FcW zb?eUU+WeWjf}|-E9uY~0Q?Dr#?zI!zX)#aD5#>oG;#7K%=VHYqxUp&kr4N_R2tK?$ z1z;Je;a#&|+Rzd}53Tj@??9b3-^lDx2h8kNLa2n&ODXB*SlfBO?gwqIg6l*v9z+R^ zc_WDAxl=(ZnUcZ9U^eE2M=W6cQP7HKg0!pV5R}{vyBz#fT>05rAdX z!_6TD+O}8}Q)AF;{68CWXC5$8{Z=E?>`&IP3C)72 zfcS@^+-DEy<#`Z`Xv5v}-aYijJ+x9?J@(E$^^s$S(?-x2%3L>$m!e2De~%1m&Bfp)`?lQs*( ztQ>~L=mH)M!-pNx>fe;YkS38=@|`e#BB!#c(WV1v%P{T9T=zqx;vMY`sX;=s9jFG96S|?9rN_PC-cj8Y20Ftk uk0lPn{Z0~@d$}m(iZ}undZy$-5Su2(_zODn6^(yFm7mTCp4>tpa?jtsa1{~& literal 0 HcmV?d00001 diff --git a/psets/9/finance/env/lib/python3.12/site-packages/itsdangerous/__pycache__/encoding.cpython-312.pyc b/psets/9/finance/env/lib/python3.12/site-packages/itsdangerous/__pycache__/encoding.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..e2bf4aae73037fb964eb2db1795b39340219e27e GIT binary patch literal 2685 zcma(SOKcNIbjG{hINmsM67qqPvLuw$Kw>^24HPI)h-g)UDD;C7H5<<)*xjt%nK2MI zsnV(kdTLOSNQJ6$sT4$|BK3kel}j(Z*fLVkmP$yd2X0Zrp`w?*nY9xPJ#_4SZ|1!> zGw(mYMIvDYzjM6%ju5vfkZ%IEukr_Cv=5_ z34>@vcj_iWi4aEhh&0v%T=|hE68tils3%cke5ohGfa?I8RLgW$FJHme5YX4GtgEwY zh=jh=GF{d63MTb8L1Q@*O#wvpjHMPefP|N2nrU-pLk&|c60NY;$h`U@hnTQq(~I<* z0iTv=C(Wb*Eb1UFBm%f|G7xKhESWLvnYQa@g)P!qmybM_iUP6jpiK_h!cJ-a5emux zz#1>T4U?-#RE$Ds3W>^92vsj-EmJ51A$)#J;i*7XW*T;$fa^wLnio#I8O`Om$OqJ+vAkS(}EM*9j7dt=OFE$)t{U6!WV2; zBu6I&<*X5IHR0nu0A|n=1BF^<*IzktuWt4IhRD}PzB)4d;oSLh!^TVaq1iBVWC_Gj zYS~e+ka{a8o`p%R6RR08jf9j^BU8!x>RRF{RF%xsJxllJ1XsD>+Cbr>gEpsw1D5Yi z%eKI`;3O+MW+{`bEVBf?DEh6F=cvUf&pSf$eWuN57`$w8dyHBlYvnn$(ysO1yYKLR z#aNQI?TzWmGoCT3F7ul6%#mA?qk{wf#h$_B#W~0=!`FbzofeA#^dkPgq%X_bfwl@h zE|VI(972tqb4EF`Zf5v_*}P!(l+2#%!)0^xg1Nn9Zof59HiwG(5NiVQ8fVM=Q_j8v zlUipJOaeb@H!F^onMm{%x39R^L?l=+5Gue~1yFVx8i!cU>kM$7A1ixLpdKVbRlZQI zO|HfQ8xU)r#zGpe1~IBZo5EiNNZmC43}3((&_(SOx`1P$!m&yi36(_wVT2I$si^#q zcv@+$f~8{W$IT1cJe5v+Mta=MG8zjonbxd9f@T1ZW!@EDddod;J85G1@#*v9Lo5QV zVI)@P2VHZh%UVFZChWeVUj50*96c;c)(gLHJ9&T3qyyp3Hn|H^F1v^ITrT(rFbh~~ z;o}s*axTnw-0r*=IXE+XUk_g*SNPoEH=oWr*N>OlHsYykd zXet#4VN#ol)zD`u$p`|=qqdqyRJnoYyhswRNQ$iAmpsF%R+r}HC!Q^>hG*s2MmTsI zd|VnagC3ZjbFF2wYr))5GB;fRpltRP^}ZMDNM^ZGejiL~mH%(0$#Rdc8b`F%uoqgA zKJr+W1nZVS23}dC+$Ze;b-f_VrEwu0imm$=S`U|65C1Y=ZXGG2=)-8&tZ_AR zIWkAe(Vm&e{b<)hw7V4TmeclGeAT#Y6g!4)_bu!mDeWF9M~}@!mJE#hpM)@eO&Rqs D8_r#9 literal 0 HcmV?d00001 diff --git a/psets/9/finance/env/lib/python3.12/site-packages/itsdangerous/__pycache__/exc.cpython-312.pyc b/psets/9/finance/env/lib/python3.12/site-packages/itsdangerous/__pycache__/exc.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..df2ff599b47d0cbfafad8ce643e939dc26f05557 GIT binary patch literal 3945 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 literal 0 HcmV?d00001 diff --git a/psets/9/finance/env/lib/python3.12/site-packages/itsdangerous/__pycache__/signer.cpython-312.pyc b/psets/9/finance/env/lib/python3.12/site-packages/itsdangerous/__pycache__/signer.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..22db6d5918b6290f6026322684c6a8ab22bd376d GIT binary patch literal 11290 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 a=F=NaJl9>#n=U;6-14r2hi#^u5%k|9A*SvC literal 0 HcmV?d00001 diff --git a/psets/9/finance/env/lib/python3.12/site-packages/itsdangerous/__pycache__/timed.cpython-312.pyc b/psets/9/finance/env/lib/python3.12/site-packages/itsdangerous/__pycache__/timed.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..1f602e5a3b43c26e5501b0cbde8bf074a517e9d0 GIT binary patch literal 8734 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 literal 0 HcmV?d00001 diff --git a/psets/9/finance/env/lib/python3.12/site-packages/itsdangerous/_json.py b/psets/9/finance/env/lib/python3.12/site-packages/itsdangerous/_json.py new file mode 100644 index 0000000..fc23fea --- /dev/null +++ b/psets/9/finance/env/lib/python3.12/site-packages/itsdangerous/_json.py @@ -0,0 +1,18 @@ +from __future__ import annotations + +import json as _json +import typing as t + + +class _CompactJSON: + """Wrapper around json module that strips whitespace.""" + + @staticmethod + def loads(payload: str | bytes) -> t.Any: + return _json.loads(payload) + + @staticmethod + def dumps(obj: t.Any, **kwargs: t.Any) -> str: + kwargs.setdefault("ensure_ascii", False) + kwargs.setdefault("separators", (",", ":")) + return _json.dumps(obj, **kwargs) diff --git a/psets/9/finance/env/lib/python3.12/site-packages/itsdangerous/encoding.py b/psets/9/finance/env/lib/python3.12/site-packages/itsdangerous/encoding.py new file mode 100644 index 0000000..f5ca80f --- /dev/null +++ b/psets/9/finance/env/lib/python3.12/site-packages/itsdangerous/encoding.py @@ -0,0 +1,54 @@ +from __future__ import annotations + +import base64 +import string +import struct +import typing as t + +from .exc import BadData + + +def want_bytes( + s: str | bytes, encoding: str = "utf-8", errors: str = "strict" +) -> bytes: + if isinstance(s, str): + s = s.encode(encoding, errors) + + return s + + +def base64_encode(string: str | bytes) -> bytes: + """Base64 encode a string of bytes or text. The resulting bytes are + safe to use in URLs. + """ + string = want_bytes(string) + return base64.urlsafe_b64encode(string).rstrip(b"=") + + +def base64_decode(string: str | bytes) -> bytes: + """Base64 decode a URL-safe string of bytes or text. The result is + bytes. + """ + string = want_bytes(string, encoding="ascii", errors="ignore") + string += b"=" * (-len(string) % 4) + + try: + return base64.urlsafe_b64decode(string) + except (TypeError, ValueError) as e: + raise BadData("Invalid base64-encoded data") from e + + +# The alphabet used by base64.urlsafe_* +_base64_alphabet = f"{string.ascii_letters}{string.digits}-_=".encode("ascii") + +_int64_struct = struct.Struct(">Q") +_int_to_bytes = _int64_struct.pack +_bytes_to_int = t.cast("t.Callable[[bytes], tuple[int]]", _int64_struct.unpack) + + +def int_to_bytes(num: int) -> bytes: + return _int_to_bytes(num).lstrip(b"\x00") + + +def bytes_to_int(bytestr: bytes) -> int: + return _bytes_to_int(bytestr.rjust(8, b"\x00"))[0] diff --git a/psets/9/finance/env/lib/python3.12/site-packages/itsdangerous/exc.py b/psets/9/finance/env/lib/python3.12/site-packages/itsdangerous/exc.py new file mode 100644 index 0000000..a75adcd --- /dev/null +++ b/psets/9/finance/env/lib/python3.12/site-packages/itsdangerous/exc.py @@ -0,0 +1,106 @@ +from __future__ import annotations + +import typing as t +from datetime import datetime + + +class BadData(Exception): + """Raised if bad data of any sort was encountered. This is the base + for all exceptions that ItsDangerous defines. + + .. versionadded:: 0.15 + """ + + def __init__(self, message: str): + super().__init__(message) + self.message = message + + def __str__(self) -> str: + return self.message + + +class BadSignature(BadData): + """Raised if a signature does not match.""" + + def __init__(self, message: str, payload: t.Any | None = None): + super().__init__(message) + + #: The payload that failed the signature test. In some + #: situations you might still want to inspect this, even if + #: you know it was tampered with. + #: + #: .. versionadded:: 0.14 + self.payload: t.Any | None = payload + + +class BadTimeSignature(BadSignature): + """Raised if a time-based signature is invalid. This is a subclass + of :class:`BadSignature`. + """ + + def __init__( + self, + message: str, + payload: t.Any | None = None, + date_signed: datetime | None = None, + ): + super().__init__(message, payload) + + #: If the signature expired this exposes the date of when the + #: signature was created. This can be helpful in order to + #: tell the user how long a link has been gone stale. + #: + #: .. versionchanged:: 2.0 + #: The datetime value is timezone-aware rather than naive. + #: + #: .. versionadded:: 0.14 + self.date_signed = date_signed + + +class SignatureExpired(BadTimeSignature): + """Raised if a signature timestamp is older than ``max_age``. This + is a subclass of :exc:`BadTimeSignature`. + """ + + +class BadHeader(BadSignature): + """Raised if a signed header is invalid in some form. This only + happens for serializers that have a header that goes with the + signature. + + .. versionadded:: 0.24 + """ + + def __init__( + self, + message: str, + payload: t.Any | None = None, + header: t.Any | None = None, + original_error: Exception | None = None, + ): + super().__init__(message, payload) + + #: If the header is actually available but just malformed it + #: might be stored here. + self.header: t.Any | None = header + + #: If available, the error that indicates why the payload was + #: not valid. This might be ``None``. + self.original_error: Exception | None = original_error + + +class BadPayload(BadData): + """Raised if a payload is invalid. This could happen if the payload + is loaded despite an invalid signature, or if there is a mismatch + between the serializer and deserializer. The original exception + that occurred during loading is stored on as :attr:`original_error`. + + .. versionadded:: 0.15 + """ + + def __init__(self, message: str, original_error: Exception | None = None): + super().__init__(message) + + #: If available, the error that indicates why the payload was + #: not valid. This might be ``None``. + self.original_error: Exception | None = original_error diff --git a/psets/9/finance/env/lib/python3.12/site-packages/itsdangerous/py.typed b/psets/9/finance/env/lib/python3.12/site-packages/itsdangerous/py.typed new file mode 100644 index 0000000..e69de29 diff --git a/psets/9/finance/env/lib/python3.12/site-packages/itsdangerous/serializer.py b/psets/9/finance/env/lib/python3.12/site-packages/itsdangerous/serializer.py new file mode 100644 index 0000000..5ddf387 --- /dev/null +++ b/psets/9/finance/env/lib/python3.12/site-packages/itsdangerous/serializer.py @@ -0,0 +1,406 @@ +from __future__ import annotations + +import collections.abc as cabc +import json +import typing as t + +from .encoding import want_bytes +from .exc import BadPayload +from .exc import BadSignature +from .signer import _make_keys_list +from .signer import Signer + +if t.TYPE_CHECKING: + import typing_extensions as te + + # This should be either be str or bytes. To avoid having to specify the + # bound type, it falls back to a union if structural matching fails. + _TSerialized = te.TypeVar( + "_TSerialized", bound=t.Union[str, bytes], default=t.Union[str, bytes] + ) +else: + # Still available at runtime on Python < 3.13, but without the default. + _TSerialized = t.TypeVar("_TSerialized", bound=t.Union[str, bytes]) + + +class _PDataSerializer(t.Protocol[_TSerialized]): + def loads(self, payload: _TSerialized, /) -> t.Any: ... + # A signature with additional arguments is not handled correctly by type + # checkers right now, so an overload is used below for serializers that + # don't match this strict protocol. + def dumps(self, obj: t.Any, /) -> _TSerialized: ... + + +# Use TypeIs once it's available in typing_extensions or 3.13. +def is_text_serializer( + serializer: _PDataSerializer[t.Any], +) -> te.TypeGuard[_PDataSerializer[str]]: + """Checks whether a serializer generates text or binary.""" + return isinstance(serializer.dumps({}), str) + + +class Serializer(t.Generic[_TSerialized]): + """A serializer wraps a :class:`~itsdangerous.signer.Signer` to + enable serializing and securely signing data other than bytes. It + can unsign to verify that the data hasn't been changed. + + The serializer provides :meth:`dumps` and :meth:`loads`, similar to + :mod:`json`, and by default uses :mod:`json` internally to serialize + the data to bytes. + + The secret key should be a random string of ``bytes`` and should not + be saved to code or version control. Different salts should be used + to distinguish signing in different contexts. See :doc:`/concepts` + for information about the security of the secret key and salt. + + :param secret_key: The secret key to sign and verify with. Can be a + list of keys, oldest to newest, to support key rotation. + :param salt: Extra key to combine with ``secret_key`` to distinguish + signatures in different contexts. + :param serializer: An object that provides ``dumps`` and ``loads`` + methods for serializing data to a string. Defaults to + :attr:`default_serializer`, which defaults to :mod:`json`. + :param serializer_kwargs: Keyword arguments to pass when calling + ``serializer.dumps``. + :param signer: A ``Signer`` class to instantiate when signing data. + Defaults to :attr:`default_signer`, which defaults to + :class:`~itsdangerous.signer.Signer`. + :param signer_kwargs: Keyword arguments to pass when instantiating + the ``Signer`` class. + :param fallback_signers: List of signer parameters to try when + unsigning with the default signer fails. Each item can be a dict + of ``signer_kwargs``, a ``Signer`` class, or a tuple of + ``(signer, signer_kwargs)``. Defaults to + :attr:`default_fallback_signers`. + + .. versionchanged:: 2.0 + Added support for key rotation by passing a list to + ``secret_key``. + + .. versionchanged:: 2.0 + Removed the default SHA-512 fallback signer from + ``default_fallback_signers``. + + .. versionchanged:: 1.1 + Added support for ``fallback_signers`` and configured a default + SHA-512 fallback. This fallback is for users who used the yanked + 1.0.0 release which defaulted to SHA-512. + + .. versionchanged:: 0.14 + The ``signer`` and ``signer_kwargs`` parameters were added to + the constructor. + """ + + #: The default serialization module to use to serialize data to a + #: string internally. The default is :mod:`json`, but can be changed + #: to any object that provides ``dumps`` and ``loads`` methods. + default_serializer: _PDataSerializer[t.Any] = json + + #: The default ``Signer`` class to instantiate when signing data. + #: The default is :class:`itsdangerous.signer.Signer`. + default_signer: type[Signer] = Signer + + #: The default fallback signers to try when unsigning fails. + default_fallback_signers: list[ + dict[str, t.Any] | tuple[type[Signer], dict[str, t.Any]] | type[Signer] + ] = [] + + # Serializer[str] if no data serializer is provided, or if it returns str. + @t.overload + def __init__( + self: Serializer[str], + secret_key: str | bytes | cabc.Iterable[str] | cabc.Iterable[bytes], + salt: str | bytes | None = b"itsdangerous", + serializer: None | _PDataSerializer[str] = None, + serializer_kwargs: dict[str, t.Any] | None = None, + signer: type[Signer] | None = None, + signer_kwargs: dict[str, t.Any] | None = None, + fallback_signers: list[ + dict[str, t.Any] | tuple[type[Signer], dict[str, t.Any]] | type[Signer] + ] + | None = None, + ): ... + + # Serializer[bytes] with a bytes data serializer positional argument. + @t.overload + def __init__( + self: Serializer[bytes], + secret_key: str | bytes | cabc.Iterable[str] | cabc.Iterable[bytes], + salt: str | bytes | None, + serializer: _PDataSerializer[bytes], + serializer_kwargs: dict[str, t.Any] | None = None, + signer: type[Signer] | None = None, + signer_kwargs: dict[str, t.Any] | None = None, + fallback_signers: list[ + dict[str, t.Any] | tuple[type[Signer], dict[str, t.Any]] | type[Signer] + ] + | None = None, + ): ... + + # Serializer[bytes] with a bytes data serializer keyword argument. + @t.overload + def __init__( + self: Serializer[bytes], + secret_key: str | bytes | cabc.Iterable[str] | cabc.Iterable[bytes], + salt: str | bytes | None = b"itsdangerous", + *, + serializer: _PDataSerializer[bytes], + serializer_kwargs: dict[str, t.Any] | None = None, + signer: type[Signer] | None = None, + signer_kwargs: dict[str, t.Any] | None = None, + fallback_signers: list[ + dict[str, t.Any] | tuple[type[Signer], dict[str, t.Any]] | type[Signer] + ] + | None = None, + ): ... + + # Fall back with a positional argument. If the strict signature of + # _PDataSerializer doesn't match, fall back to a union, requiring the user + # to specify the type. + @t.overload + def __init__( + self, + secret_key: str | bytes | cabc.Iterable[str] | cabc.Iterable[bytes], + salt: str | bytes | None, + serializer: t.Any, + serializer_kwargs: dict[str, t.Any] | None = None, + signer: type[Signer] | None = None, + signer_kwargs: dict[str, t.Any] | None = None, + fallback_signers: list[ + dict[str, t.Any] | tuple[type[Signer], dict[str, t.Any]] | type[Signer] + ] + | None = None, + ): ... + + # Fall back with a keyword argument. + @t.overload + def __init__( + self, + secret_key: str | bytes | cabc.Iterable[str] | cabc.Iterable[bytes], + salt: str | bytes | None = b"itsdangerous", + *, + serializer: t.Any, + serializer_kwargs: dict[str, t.Any] | None = None, + signer: type[Signer] | None = None, + signer_kwargs: dict[str, t.Any] | None = None, + fallback_signers: list[ + dict[str, t.Any] | tuple[type[Signer], dict[str, t.Any]] | type[Signer] + ] + | None = None, + ): ... + + def __init__( + self, + secret_key: str | bytes | cabc.Iterable[str] | cabc.Iterable[bytes], + salt: str | bytes | None = b"itsdangerous", + serializer: t.Any | None = None, + serializer_kwargs: dict[str, t.Any] | None = None, + signer: type[Signer] | None = None, + signer_kwargs: dict[str, t.Any] | None = None, + fallback_signers: list[ + dict[str, t.Any] | tuple[type[Signer], dict[str, t.Any]] | type[Signer] + ] + | None = None, + ): + #: The list of secret keys to try for verifying signatures, from + #: oldest to newest. The newest (last) key is used for signing. + #: + #: This allows a key rotation system to keep a list of allowed + #: keys and remove expired ones. + self.secret_keys: list[bytes] = _make_keys_list(secret_key) + + if salt is not None: + salt = want_bytes(salt) + # if salt is None then the signer's default is used + + self.salt = salt + + if serializer is None: + serializer = self.default_serializer + + self.serializer: _PDataSerializer[_TSerialized] = serializer + self.is_text_serializer: bool = is_text_serializer(serializer) + + if signer is None: + signer = self.default_signer + + self.signer: type[Signer] = signer + self.signer_kwargs: dict[str, t.Any] = signer_kwargs or {} + + if fallback_signers is None: + fallback_signers = list(self.default_fallback_signers) + + self.fallback_signers: list[ + dict[str, t.Any] | tuple[type[Signer], dict[str, t.Any]] | type[Signer] + ] = fallback_signers + self.serializer_kwargs: dict[str, t.Any] = serializer_kwargs or {} + + @property + def secret_key(self) -> bytes: + """The newest (last) entry in the :attr:`secret_keys` list. This + is for compatibility from before key rotation support was added. + """ + return self.secret_keys[-1] + + def load_payload( + self, payload: bytes, serializer: _PDataSerializer[t.Any] | None = None + ) -> t.Any: + """Loads the encoded object. This function raises + :class:`.BadPayload` if the payload is not valid. The + ``serializer`` parameter can be used to override the serializer + stored on the class. The encoded ``payload`` should always be + bytes. + """ + if serializer is None: + use_serializer = self.serializer + is_text = self.is_text_serializer + else: + use_serializer = serializer + is_text = is_text_serializer(serializer) + + try: + if is_text: + return use_serializer.loads(payload.decode("utf-8")) # type: ignore[arg-type] + + return use_serializer.loads(payload) # type: ignore[arg-type] + except Exception as e: + raise BadPayload( + "Could not load the payload because an exception" + " occurred on unserializing the data.", + original_error=e, + ) from e + + def dump_payload(self, obj: t.Any) -> bytes: + """Dumps the encoded object. The return value is always bytes. + If the internal serializer returns text, the value will be + encoded as UTF-8. + """ + return want_bytes(self.serializer.dumps(obj, **self.serializer_kwargs)) + + def make_signer(self, salt: str | bytes | None = None) -> Signer: + """Creates a new instance of the signer to be used. The default + implementation uses the :class:`.Signer` base class. + """ + if salt is None: + salt = self.salt + + return self.signer(self.secret_keys, salt=salt, **self.signer_kwargs) + + def iter_unsigners(self, salt: str | bytes | None = None) -> cabc.Iterator[Signer]: + """Iterates over all signers to be tried for unsigning. Starts + with the configured signer, then constructs each signer + specified in ``fallback_signers``. + """ + if salt is None: + salt = self.salt + + yield self.make_signer(salt) + + for fallback in self.fallback_signers: + if isinstance(fallback, dict): + kwargs = fallback + fallback = self.signer + elif isinstance(fallback, tuple): + fallback, kwargs = fallback + else: + kwargs = self.signer_kwargs + + for secret_key in self.secret_keys: + yield fallback(secret_key, salt=salt, **kwargs) + + def dumps(self, obj: t.Any, salt: str | bytes | None = None) -> _TSerialized: + """Returns a signed string serialized with the internal + serializer. The return value can be either a byte or unicode + string depending on the format of the internal serializer. + """ + payload = want_bytes(self.dump_payload(obj)) + rv = self.make_signer(salt).sign(payload) + + if self.is_text_serializer: + return rv.decode("utf-8") # type: ignore[return-value] + + return rv # type: ignore[return-value] + + def dump(self, obj: t.Any, f: t.IO[t.Any], salt: str | bytes | None = None) -> None: + """Like :meth:`dumps` but dumps into a file. The file handle has + to be compatible with what the internal serializer expects. + """ + f.write(self.dumps(obj, salt)) + + def loads( + self, s: str | bytes, salt: str | bytes | None = None, **kwargs: t.Any + ) -> t.Any: + """Reverse of :meth:`dumps`. Raises :exc:`.BadSignature` if the + signature validation fails. + """ + s = want_bytes(s) + last_exception = None + + for signer in self.iter_unsigners(salt): + try: + return self.load_payload(signer.unsign(s)) + except BadSignature as err: + last_exception = err + + raise t.cast(BadSignature, last_exception) + + def load(self, f: t.IO[t.Any], salt: str | bytes | None = None) -> t.Any: + """Like :meth:`loads` but loads from a file.""" + return self.loads(f.read(), salt) + + def loads_unsafe( + self, s: str | bytes, salt: str | bytes | None = None + ) -> tuple[bool, t.Any]: + """Like :meth:`loads` but without verifying the signature. This + is potentially very dangerous to use depending on how your + serializer works. The return value is ``(signature_valid, + payload)`` instead of just the payload. The first item will be a + boolean that indicates if the signature is valid. This function + never fails. + + Use it for debugging only and if you know that your serializer + module is not exploitable (for example, do not use it with a + pickle serializer). + + .. versionadded:: 0.15 + """ + return self._loads_unsafe_impl(s, salt) + + def _loads_unsafe_impl( + self, + s: str | bytes, + salt: str | bytes | None, + load_kwargs: dict[str, t.Any] | None = None, + load_payload_kwargs: dict[str, t.Any] | None = None, + ) -> tuple[bool, t.Any]: + """Low level helper function to implement :meth:`loads_unsafe` + in serializer subclasses. + """ + if load_kwargs is None: + load_kwargs = {} + + try: + return True, self.loads(s, salt=salt, **load_kwargs) + except BadSignature as e: + if e.payload is None: + return False, None + + if load_payload_kwargs is None: + load_payload_kwargs = {} + + try: + return ( + False, + self.load_payload(e.payload, **load_payload_kwargs), + ) + except BadPayload: + return False, None + + def load_unsafe( + self, f: t.IO[t.Any], salt: str | bytes | None = None + ) -> tuple[bool, t.Any]: + """Like :meth:`loads_unsafe` but loads from a file. + + .. versionadded:: 0.15 + """ + return self.loads_unsafe(f.read(), salt=salt) diff --git a/psets/9/finance/env/lib/python3.12/site-packages/itsdangerous/signer.py b/psets/9/finance/env/lib/python3.12/site-packages/itsdangerous/signer.py new file mode 100644 index 0000000..e324dc0 --- /dev/null +++ b/psets/9/finance/env/lib/python3.12/site-packages/itsdangerous/signer.py @@ -0,0 +1,266 @@ +from __future__ import annotations + +import collections.abc as cabc +import hashlib +import hmac +import typing as t + +from .encoding import _base64_alphabet +from .encoding import base64_decode +from .encoding import base64_encode +from .encoding import want_bytes +from .exc import BadSignature + + +class SigningAlgorithm: + """Subclasses must implement :meth:`get_signature` to provide + signature generation functionality. + """ + + def get_signature(self, key: bytes, value: bytes) -> bytes: + """Returns the signature for the given key and value.""" + raise NotImplementedError() + + def verify_signature(self, key: bytes, value: bytes, sig: bytes) -> bool: + """Verifies the given signature matches the expected + signature. + """ + return hmac.compare_digest(sig, self.get_signature(key, value)) + + +class NoneAlgorithm(SigningAlgorithm): + """Provides an algorithm that does not perform any signing and + returns an empty signature. + """ + + def get_signature(self, key: bytes, value: bytes) -> bytes: + return b"" + + +def _lazy_sha1(string: bytes = b"") -> t.Any: + """Don't access ``hashlib.sha1`` until runtime. FIPS builds may not include + SHA-1, in which case the import and use as a default would fail before the + developer can configure something else. + """ + return hashlib.sha1(string) + + +class HMACAlgorithm(SigningAlgorithm): + """Provides signature generation using HMACs.""" + + #: The digest method to use with the MAC algorithm. This defaults to + #: SHA1, but can be changed to any other function in the hashlib + #: module. + default_digest_method: t.Any = staticmethod(_lazy_sha1) + + def __init__(self, digest_method: t.Any = None): + if digest_method is None: + digest_method = self.default_digest_method + + self.digest_method: t.Any = digest_method + + def get_signature(self, key: bytes, value: bytes) -> bytes: + mac = hmac.new(key, msg=value, digestmod=self.digest_method) + return mac.digest() + + +def _make_keys_list( + secret_key: str | bytes | cabc.Iterable[str] | cabc.Iterable[bytes], +) -> list[bytes]: + if isinstance(secret_key, (str, bytes)): + return [want_bytes(secret_key)] + + return [want_bytes(s) for s in secret_key] # pyright: ignore + + +class Signer: + """A signer securely signs bytes, then unsigns them to verify that + the value hasn't been changed. + + The secret key should be a random string of ``bytes`` and should not + be saved to code or version control. Different salts should be used + to distinguish signing in different contexts. See :doc:`/concepts` + for information about the security of the secret key and salt. + + :param secret_key: The secret key to sign and verify with. Can be a + list of keys, oldest to newest, to support key rotation. + :param salt: Extra key to combine with ``secret_key`` to distinguish + signatures in different contexts. + :param sep: Separator between the signature and value. + :param key_derivation: How to derive the signing key from the secret + key and salt. Possible values are ``concat``, ``django-concat``, + or ``hmac``. Defaults to :attr:`default_key_derivation`, which + defaults to ``django-concat``. + :param digest_method: Hash function to use when generating the HMAC + signature. Defaults to :attr:`default_digest_method`, which + defaults to :func:`hashlib.sha1`. Note that the security of the + hash alone doesn't apply when used intermediately in HMAC. + :param algorithm: A :class:`SigningAlgorithm` instance to use + instead of building a default :class:`HMACAlgorithm` with the + ``digest_method``. + + .. versionchanged:: 2.0 + Added support for key rotation by passing a list to + ``secret_key``. + + .. versionchanged:: 0.18 + ``algorithm`` was added as an argument to the class constructor. + + .. versionchanged:: 0.14 + ``key_derivation`` and ``digest_method`` were added as arguments + to the class constructor. + """ + + #: The default digest method to use for the signer. The default is + #: :func:`hashlib.sha1`, but can be changed to any :mod:`hashlib` or + #: compatible object. Note that the security of the hash alone + #: doesn't apply when used intermediately in HMAC. + #: + #: .. versionadded:: 0.14 + default_digest_method: t.Any = staticmethod(_lazy_sha1) + + #: The default scheme to use to derive the signing key from the + #: secret key and salt. The default is ``django-concat``. Possible + #: values are ``concat``, ``django-concat``, and ``hmac``. + #: + #: .. versionadded:: 0.14 + default_key_derivation: str = "django-concat" + + def __init__( + self, + secret_key: str | bytes | cabc.Iterable[str] | cabc.Iterable[bytes], + salt: str | bytes | None = b"itsdangerous.Signer", + sep: str | bytes = b".", + key_derivation: str | None = None, + digest_method: t.Any | None = None, + algorithm: SigningAlgorithm | None = None, + ): + #: The list of secret keys to try for verifying signatures, from + #: oldest to newest. The newest (last) key is used for signing. + #: + #: This allows a key rotation system to keep a list of allowed + #: keys and remove expired ones. + self.secret_keys: list[bytes] = _make_keys_list(secret_key) + self.sep: bytes = want_bytes(sep) + + if self.sep in _base64_alphabet: + raise ValueError( + "The given separator cannot be used because it may be" + " contained in the signature itself. ASCII letters," + " digits, and '-_=' must not be used." + ) + + if salt is not None: + salt = want_bytes(salt) + else: + salt = b"itsdangerous.Signer" + + self.salt = salt + + if key_derivation is None: + key_derivation = self.default_key_derivation + + self.key_derivation: str = key_derivation + + if digest_method is None: + digest_method = self.default_digest_method + + self.digest_method: t.Any = digest_method + + if algorithm is None: + algorithm = HMACAlgorithm(self.digest_method) + + self.algorithm: SigningAlgorithm = algorithm + + @property + def secret_key(self) -> bytes: + """The newest (last) entry in the :attr:`secret_keys` list. This + is for compatibility from before key rotation support was added. + """ + return self.secret_keys[-1] + + def derive_key(self, secret_key: str | bytes | None = None) -> bytes: + """This method is called to derive the key. The default key + derivation choices can be overridden here. Key derivation is not + intended to be used as a security method to make a complex key + out of a short password. Instead you should use large random + secret keys. + + :param secret_key: A specific secret key to derive from. + Defaults to the last item in :attr:`secret_keys`. + + .. versionchanged:: 2.0 + Added the ``secret_key`` parameter. + """ + if secret_key is None: + secret_key = self.secret_keys[-1] + else: + secret_key = want_bytes(secret_key) + + if self.key_derivation == "concat": + return t.cast(bytes, self.digest_method(self.salt + secret_key).digest()) + elif self.key_derivation == "django-concat": + return t.cast( + bytes, self.digest_method(self.salt + b"signer" + secret_key).digest() + ) + elif self.key_derivation == "hmac": + mac = hmac.new(secret_key, digestmod=self.digest_method) + mac.update(self.salt) + return mac.digest() + elif self.key_derivation == "none": + return secret_key + else: + raise TypeError("Unknown key derivation method") + + def get_signature(self, value: str | bytes) -> bytes: + """Returns the signature for the given value.""" + value = want_bytes(value) + key = self.derive_key() + sig = self.algorithm.get_signature(key, value) + return base64_encode(sig) + + def sign(self, value: str | bytes) -> bytes: + """Signs the given string.""" + value = want_bytes(value) + return value + self.sep + self.get_signature(value) + + def verify_signature(self, value: str | bytes, sig: str | bytes) -> bool: + """Verifies the signature for the given value.""" + try: + sig = base64_decode(sig) + except Exception: + return False + + value = want_bytes(value) + + for secret_key in reversed(self.secret_keys): + key = self.derive_key(secret_key) + + if self.algorithm.verify_signature(key, value, sig): + return True + + return False + + def unsign(self, signed_value: str | bytes) -> bytes: + """Unsigns the given string.""" + signed_value = want_bytes(signed_value) + + if self.sep not in signed_value: + raise BadSignature(f"No {self.sep!r} found in value") + + value, sig = signed_value.rsplit(self.sep, 1) + + if self.verify_signature(value, sig): + return value + + raise BadSignature(f"Signature {sig!r} does not match", payload=value) + + def validate(self, signed_value: str | bytes) -> bool: + """Only validates the given signed value. Returns ``True`` if + the signature exists and is valid. + """ + try: + self.unsign(signed_value) + return True + except BadSignature: + return False diff --git a/psets/9/finance/env/lib/python3.12/site-packages/itsdangerous/timed.py b/psets/9/finance/env/lib/python3.12/site-packages/itsdangerous/timed.py new file mode 100644 index 0000000..7384375 --- /dev/null +++ b/psets/9/finance/env/lib/python3.12/site-packages/itsdangerous/timed.py @@ -0,0 +1,228 @@ +from __future__ import annotations + +import collections.abc as cabc +import time +import typing as t +from datetime import datetime +from datetime import timezone + +from .encoding import base64_decode +from .encoding import base64_encode +from .encoding import bytes_to_int +from .encoding import int_to_bytes +from .encoding import want_bytes +from .exc import BadSignature +from .exc import BadTimeSignature +from .exc import SignatureExpired +from .serializer import _TSerialized +from .serializer import Serializer +from .signer import Signer + + +class TimestampSigner(Signer): + """Works like the regular :class:`.Signer` but also records the time + of the signing and can be used to expire signatures. The + :meth:`unsign` method can raise :exc:`.SignatureExpired` if the + unsigning failed because the signature is expired. + """ + + def get_timestamp(self) -> int: + """Returns the current timestamp. The function must return an + integer. + """ + return int(time.time()) + + def timestamp_to_datetime(self, ts: int) -> datetime: + """Convert the timestamp from :meth:`get_timestamp` into an + aware :class`datetime.datetime` in UTC. + + .. versionchanged:: 2.0 + The timestamp is returned as a timezone-aware ``datetime`` + in UTC rather than a naive ``datetime`` assumed to be UTC. + """ + return datetime.fromtimestamp(ts, tz=timezone.utc) + + def sign(self, value: str | bytes) -> bytes: + """Signs the given string and also attaches time information.""" + value = want_bytes(value) + timestamp = base64_encode(int_to_bytes(self.get_timestamp())) + sep = want_bytes(self.sep) + value = value + sep + timestamp + return value + sep + self.get_signature(value) + + # Ignore overlapping signatures check, return_timestamp is the only + # parameter that affects the return type. + + @t.overload + def unsign( # type: ignore[overload-overlap] + self, + signed_value: str | bytes, + max_age: int | None = None, + return_timestamp: t.Literal[False] = False, + ) -> bytes: ... + + @t.overload + def unsign( + self, + signed_value: str | bytes, + max_age: int | None = None, + return_timestamp: t.Literal[True] = True, + ) -> tuple[bytes, datetime]: ... + + def unsign( + self, + signed_value: str | bytes, + max_age: int | None = None, + return_timestamp: bool = False, + ) -> tuple[bytes, datetime] | bytes: + """Works like the regular :meth:`.Signer.unsign` but can also + validate the time. See the base docstring of the class for + the general behavior. If ``return_timestamp`` is ``True`` the + timestamp of the signature will be returned as an aware + :class:`datetime.datetime` object in UTC. + + .. versionchanged:: 2.0 + The timestamp is returned as a timezone-aware ``datetime`` + in UTC rather than a naive ``datetime`` assumed to be UTC. + """ + try: + result = super().unsign(signed_value) + sig_error = None + except BadSignature as e: + sig_error = e + result = e.payload or b"" + + sep = want_bytes(self.sep) + + # If there is no timestamp in the result there is something + # seriously wrong. In case there was a signature error, we raise + # that one directly, otherwise we have a weird situation in + # which we shouldn't have come except someone uses a time-based + # serializer on non-timestamp data, so catch that. + if sep not in result: + if sig_error: + raise sig_error + + raise BadTimeSignature("timestamp missing", payload=result) + + value, ts_bytes = result.rsplit(sep, 1) + ts_int: int | None = None + ts_dt: datetime | None = None + + try: + ts_int = bytes_to_int(base64_decode(ts_bytes)) + except Exception: + pass + + # Signature is *not* okay. Raise a proper error now that we have + # split the value and the timestamp. + if sig_error is not None: + if ts_int is not None: + try: + ts_dt = self.timestamp_to_datetime(ts_int) + except (ValueError, OSError, OverflowError) as exc: + # Windows raises OSError + # 32-bit raises OverflowError + raise BadTimeSignature( + "Malformed timestamp", payload=value + ) from exc + + raise BadTimeSignature(str(sig_error), payload=value, date_signed=ts_dt) + + # Signature was okay but the timestamp is actually not there or + # malformed. Should not happen, but we handle it anyway. + if ts_int is None: + raise BadTimeSignature("Malformed timestamp", payload=value) + + # Check timestamp is not older than max_age + if max_age is not None: + age = self.get_timestamp() - ts_int + + if age > max_age: + raise SignatureExpired( + f"Signature age {age} > {max_age} seconds", + payload=value, + date_signed=self.timestamp_to_datetime(ts_int), + ) + + if age < 0: + raise SignatureExpired( + f"Signature age {age} < 0 seconds", + payload=value, + date_signed=self.timestamp_to_datetime(ts_int), + ) + + if return_timestamp: + return value, self.timestamp_to_datetime(ts_int) + + return value + + def validate(self, signed_value: str | bytes, max_age: int | None = None) -> bool: + """Only validates the given signed value. Returns ``True`` if + the signature exists and is valid.""" + try: + self.unsign(signed_value, max_age=max_age) + return True + except BadSignature: + return False + + +class TimedSerializer(Serializer[_TSerialized]): + """Uses :class:`TimestampSigner` instead of the default + :class:`.Signer`. + """ + + default_signer: type[TimestampSigner] = TimestampSigner + + def iter_unsigners( + self, salt: str | bytes | None = None + ) -> cabc.Iterator[TimestampSigner]: + return t.cast("cabc.Iterator[TimestampSigner]", super().iter_unsigners(salt)) + + # TODO: Signature is incompatible because parameters were added + # before salt. + + def loads( # type: ignore[override] + self, + s: str | bytes, + max_age: int | None = None, + return_timestamp: bool = False, + salt: str | bytes | None = None, + ) -> t.Any: + """Reverse of :meth:`dumps`, raises :exc:`.BadSignature` if the + signature validation fails. If a ``max_age`` is provided it will + ensure the signature is not older than that time in seconds. In + case the signature is outdated, :exc:`.SignatureExpired` is + raised. All arguments are forwarded to the signer's + :meth:`~TimestampSigner.unsign` method. + """ + s = want_bytes(s) + last_exception = None + + for signer in self.iter_unsigners(salt): + try: + base64d, timestamp = signer.unsign( + s, max_age=max_age, return_timestamp=True + ) + payload = self.load_payload(base64d) + + if return_timestamp: + return payload, timestamp + + return payload + except SignatureExpired: + # The signature was unsigned successfully but was + # expired. Do not try the next signer. + raise + except BadSignature as err: + last_exception = err + + raise t.cast(BadSignature, last_exception) + + def loads_unsafe( # type: ignore[override] + self, + s: str | bytes, + max_age: int | None = None, + salt: str | bytes | None = None, + ) -> tuple[bool, t.Any]: + return self._loads_unsafe_impl(s, salt, load_kwargs={"max_age": max_age}) diff --git a/psets/9/finance/env/lib/python3.12/site-packages/itsdangerous/url_safe.py b/psets/9/finance/env/lib/python3.12/site-packages/itsdangerous/url_safe.py new file mode 100644 index 0000000..56a0793 --- /dev/null +++ b/psets/9/finance/env/lib/python3.12/site-packages/itsdangerous/url_safe.py @@ -0,0 +1,83 @@ +from __future__ import annotations + +import typing as t +import zlib + +from ._json import _CompactJSON +from .encoding import base64_decode +from .encoding import base64_encode +from .exc import BadPayload +from .serializer import _PDataSerializer +from .serializer import Serializer +from .timed import TimedSerializer + + +class URLSafeSerializerMixin(Serializer[str]): + """Mixed in with a regular serializer it will attempt to zlib + compress the string to make it shorter if necessary. It will also + base64 encode the string so that it can safely be placed in a URL. + """ + + default_serializer: _PDataSerializer[str] = _CompactJSON + + def load_payload( + self, + payload: bytes, + *args: t.Any, + serializer: t.Any | None = None, + **kwargs: t.Any, + ) -> t.Any: + decompress = False + + if payload.startswith(b"."): + payload = payload[1:] + decompress = True + + try: + json = base64_decode(payload) + except Exception as e: + raise BadPayload( + "Could not base64 decode the payload because of an exception", + original_error=e, + ) from e + + if decompress: + try: + json = zlib.decompress(json) + except Exception as e: + raise BadPayload( + "Could not zlib decompress the payload before decoding the payload", + original_error=e, + ) from e + + return super().load_payload(json, *args, **kwargs) + + def dump_payload(self, obj: t.Any) -> bytes: + json = super().dump_payload(obj) + is_compressed = False + compressed = zlib.compress(json) + + if len(compressed) < (len(json) - 1): + json = compressed + is_compressed = True + + base64d = base64_encode(json) + + if is_compressed: + base64d = b"." + base64d + + return base64d + + +class URLSafeSerializer(URLSafeSerializerMixin, Serializer[str]): + """Works like :class:`.Serializer` but dumps and loads into a URL + safe string consisting of the upper and lowercase character of the + alphabet as well as ``'_'``, ``'-'`` and ``'.'``. + """ + + +class URLSafeTimedSerializer(URLSafeSerializerMixin, TimedSerializer[str]): + """Works like :class:`.TimedSerializer` but dumps and loads into a + URL safe string consisting of the upper and lowercase character of + the alphabet as well as ``'_'``, ``'-'`` and ``'.'``. + """ diff --git a/psets/9/finance/env/lib/python3.12/site-packages/jinja2-3.1.4.dist-info/INSTALLER b/psets/9/finance/env/lib/python3.12/site-packages/jinja2-3.1.4.dist-info/INSTALLER new file mode 100644 index 0000000..a1b589e --- /dev/null +++ b/psets/9/finance/env/lib/python3.12/site-packages/jinja2-3.1.4.dist-info/INSTALLER @@ -0,0 +1 @@ +pip diff --git a/psets/9/finance/env/lib/python3.12/site-packages/jinja2-3.1.4.dist-info/LICENSE.txt b/psets/9/finance/env/lib/python3.12/site-packages/jinja2-3.1.4.dist-info/LICENSE.txt new file mode 100644 index 0000000..c37cae4 --- /dev/null +++ b/psets/9/finance/env/lib/python3.12/site-packages/jinja2-3.1.4.dist-info/LICENSE.txt @@ -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/psets/9/finance/env/lib/python3.12/site-packages/jinja2-3.1.4.dist-info/METADATA b/psets/9/finance/env/lib/python3.12/site-packages/jinja2-3.1.4.dist-info/METADATA new file mode 100644 index 0000000..265cc32 --- /dev/null +++ b/psets/9/finance/env/lib/python3.12/site-packages/jinja2-3.1.4.dist-info/METADATA @@ -0,0 +1,76 @@ +Metadata-Version: 2.1 +Name: Jinja2 +Version: 3.1.4 +Summary: A very fast and expressive template engine. +Maintainer-email: Pallets +Requires-Python: >=3.7 +Description-Content-Type: text/markdown +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 +Classifier: Typing :: Typed +Requires-Dist: MarkupSafe>=2.0 +Requires-Dist: Babel>=2.7 ; extra == "i18n" +Project-URL: Changes, https://jinja.palletsprojects.com/changes/ +Project-URL: Chat, https://discord.gg/pallets +Project-URL: Documentation, https://jinja.palletsprojects.com/ +Project-URL: Donate, https://palletsprojects.com/donate +Project-URL: Source, https://github.com/pallets/jinja/ +Provides-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. + + +## 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 + diff --git a/psets/9/finance/env/lib/python3.12/site-packages/jinja2-3.1.4.dist-info/RECORD b/psets/9/finance/env/lib/python3.12/site-packages/jinja2-3.1.4.dist-info/RECORD new file mode 100644 index 0000000..b1a27b1 --- /dev/null +++ b/psets/9/finance/env/lib/python3.12/site-packages/jinja2-3.1.4.dist-info/RECORD @@ -0,0 +1,57 @@ +jinja2-3.1.4.dist-info/INSTALLER,sha256=zuuue4knoyJ-UwPPXg8fezS7VCrXJQrAP7zeNuwvFQg,4 +jinja2-3.1.4.dist-info/LICENSE.txt,sha256=O0nc7kEF6ze6wQ-vG-JgQI_oXSUrjp3y4JefweCUQ3s,1475 +jinja2-3.1.4.dist-info/METADATA,sha256=R_brzpPQVBvpGcsm-WbrtgotO7suQ1D0F-qkhTzeEfY,2640 +jinja2-3.1.4.dist-info/RECORD,, +jinja2-3.1.4.dist-info/WHEEL,sha256=EZbGkh7Ie4PoZfRQ8I0ZuP9VklN_TvcZ6DSE5Uar4z4,81 +jinja2-3.1.4.dist-info/entry_points.txt,sha256=OL85gYU1eD8cuPlikifFngXpeBjaxl6rIJ8KkC_3r-I,58 +jinja2/__init__.py,sha256=wIl45IM20KGw-kfr7jJhaBxxX5g4-kihlBYjxopX7Pw,1928 +jinja2/__pycache__/__init__.cpython-312.pyc,, +jinja2/__pycache__/_identifier.cpython-312.pyc,, +jinja2/__pycache__/async_utils.cpython-312.pyc,, +jinja2/__pycache__/bccache.cpython-312.pyc,, +jinja2/__pycache__/compiler.cpython-312.pyc,, +jinja2/__pycache__/constants.cpython-312.pyc,, +jinja2/__pycache__/debug.cpython-312.pyc,, +jinja2/__pycache__/defaults.cpython-312.pyc,, +jinja2/__pycache__/environment.cpython-312.pyc,, +jinja2/__pycache__/exceptions.cpython-312.pyc,, +jinja2/__pycache__/ext.cpython-312.pyc,, +jinja2/__pycache__/filters.cpython-312.pyc,, +jinja2/__pycache__/idtracking.cpython-312.pyc,, +jinja2/__pycache__/lexer.cpython-312.pyc,, +jinja2/__pycache__/loaders.cpython-312.pyc,, +jinja2/__pycache__/meta.cpython-312.pyc,, +jinja2/__pycache__/nativetypes.cpython-312.pyc,, +jinja2/__pycache__/nodes.cpython-312.pyc,, +jinja2/__pycache__/optimizer.cpython-312.pyc,, +jinja2/__pycache__/parser.cpython-312.pyc,, +jinja2/__pycache__/runtime.cpython-312.pyc,, +jinja2/__pycache__/sandbox.cpython-312.pyc,, +jinja2/__pycache__/tests.cpython-312.pyc,, +jinja2/__pycache__/utils.cpython-312.pyc,, +jinja2/__pycache__/visitor.cpython-312.pyc,, +jinja2/_identifier.py,sha256=_zYctNKzRqlk_murTNlzrju1FFJL7Va_Ijqqd7ii2lU,1958 +jinja2/async_utils.py,sha256=JXKWCAXmTx0iZB4-hAsF50vgjxw_RJTjiLOlGGTBso0,2477 +jinja2/bccache.py,sha256=gh0qs9rulnXo0PhX5jTJy2UHzI8wFnQ63o_vw7nhzRg,14061 +jinja2/compiler.py,sha256=dpV-n6_iQUP4uSwlXwGUavJmwjvXdyxKzJ-AonFjPBk,72271 +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=xhFkmxO0CESA76Ki5tz4XWq9yzGu-t0p93JCCVBVNps,61538 +jinja2/exceptions.py,sha256=ioHeHrWwCWNaXX1inHmHVblvc4haO7AXsjCp3GfWvx0,5071 +jinja2/ext.py,sha256=igsBH7c6C0byHaOtMbE-ugpt4GjLGgR-ywskyXtKgq8,31877 +jinja2/filters.py,sha256=bKeqjFjjz88TkHVLSyyMIEB75CzAN6b3Airgx0phJDg,54611 +jinja2/idtracking.py,sha256=GfNmadir4oDALVxzn3DL9YInhJDr69ebXeA2ygfuCGA,10704 +jinja2/lexer.py,sha256=xnWWXhPndHFsoqzpc5VTjheDE9JuKk9MUo9DZkrM8Os,29754 +jinja2/loaders.py,sha256=ru0GIWHo5KiHJi7_MoI_LvGDoBBvP6rd0hiC1ReaTwk,23167 +jinja2/meta.py,sha256=OTDPkaFvU2Hgvx-6akz7154F8BIWaRmvJcBFvwopHww,4397 +jinja2/nativetypes.py,sha256=7GIGALVJgdyL80oZJdQUaUfwSt5q2lSSZbXt0dNf_M4,4210 +jinja2/nodes.py,sha256=m1Duzcr6qhZI8JQ6VyJgUNinjAf5bQzijSmDnMsvUx8,34579 +jinja2/optimizer.py,sha256=rJnCRlQ7pZsEEmMhsQDgC_pKyDHxP5TPS6zVPGsgcu8,1651 +jinja2/parser.py,sha256=DV1iF1FR2Rsaj_5zl8rmx7j6Bj4S8iLHoYsvJ0bfEis,39890 +jinja2/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0 +jinja2/runtime.py,sha256=POXT3tKNKJRENx2CymwUsOOXH2JwGPjW702njB5__cQ,33435 +jinja2/sandbox.py,sha256=TJjBNS9qRJ2ZgBMWdAgRBpyDLOHea2kT-2mk4PrjYx0,14616 +jinja2/tests.py,sha256=VLsBhVFnWg-PxSBz1MhRnNWgP1ovXk3neO1FLQMeC9Q,5926 +jinja2/utils.py,sha256=nV7IpWLvRCMyHW1irBAK8CIPAnOFfkb2ukggDBjbBEY,23952 +jinja2/visitor.py,sha256=EcnL1PIwf_4RVCOMxsRNuR8AXHbS1qfAdMOE2ngKJz4,3557 diff --git a/psets/9/finance/env/lib/python3.12/site-packages/jinja2-3.1.4.dist-info/WHEEL b/psets/9/finance/env/lib/python3.12/site-packages/jinja2-3.1.4.dist-info/WHEEL new file mode 100644 index 0000000..3b5e64b --- /dev/null +++ b/psets/9/finance/env/lib/python3.12/site-packages/jinja2-3.1.4.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/psets/9/finance/env/lib/python3.12/site-packages/jinja2-3.1.4.dist-info/entry_points.txt b/psets/9/finance/env/lib/python3.12/site-packages/jinja2-3.1.4.dist-info/entry_points.txt new file mode 100644 index 0000000..abc3eae --- /dev/null +++ b/psets/9/finance/env/lib/python3.12/site-packages/jinja2-3.1.4.dist-info/entry_points.txt @@ -0,0 +1,3 @@ +[babel.extractors] +jinja2=jinja2.ext:babel_extract[i18n] + diff --git a/psets/9/finance/env/lib/python3.12/site-packages/jinja2/__init__.py b/psets/9/finance/env/lib/python3.12/site-packages/jinja2/__init__.py new file mode 100644 index 0000000..2f0b5b2 --- /dev/null +++ b/psets/9/finance/env/lib/python3.12/site-packages/jinja2/__init__.py @@ -0,0 +1,38 @@ +"""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.4" diff --git a/psets/9/finance/env/lib/python3.12/site-packages/jinja2/__pycache__/__init__.cpython-312.pyc b/psets/9/finance/env/lib/python3.12/site-packages/jinja2/__pycache__/__init__.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..57a02696ac88373376cb990ee74f4ad210c26413 GIT binary patch literal 1656 zcmZ9MTaVjB6vxN8Y!c^w-}`!ZThOZ7nBIVuN+tGIK;3H9EfUO&<=8{w)*f3klO?Hm zfH%GYdM6K7`YB-Bd&`knurx%!NMt5$Uc&#&KoJ^HbL&>u2L zpUhi$^Sy@9Psl|Wxtg2twIG8tn&d2S7H1XbfO9yfIPd3!6}+N&1-O6h?U*YTs?@U68<$Y3{o%<+H`uFh=pk+pPlkQvQ^4 z!sMdP7z>%4I&DdfMru3@#d$cPE+lnQ@A-rZFCb}dGxhmWayvDz)M2H$wJ)hlzJY^s zQ%66xIe8k|E|CkVoQy-yS;YFO=ZJZ0V{ssJuXaA6j@--Ksa%Ba#9xe2y|kTI_Gn>L zE*Y$0I`7ar8QUJUhd!CF4wh0oCBw;R+35xLD`NTK2x?|z!J*vj1aj+Fg26(UlS|7% z#qo*FEcM2?+@{C>*S`|koLf#v1(^zHZ>V^wO2BL0c-OYSl-T6NCyub}i3kaI?1;S1 z-yhr^Ja~5Seq69DH*_p3E({$tHOoS!v7D4VNL*f;fvrdzK4K`=$g{n>msUecQ%XxpTS`YtS4s~gF0h*dVtr|?N?DV#E@cBG&QFBr zbG9jsEh*blcBB|mc0uB@WnB{{ubO53g5H3I{>5fMg?S2Bo0@Qy;60fRfB1nJaU!^R zWJ2lL)FCEp-1NPn8L5j7Cw9-|o*;+OO{sA6rTkdjGcC)bp0KPzG>eOm0##U#*&$3N zFD<7ae`PgI`#Y1>a{uT^dyt?f2|7#A{RAB*=(7ZUn4m`qI!(~y1RW>nW98pfdX%7t i2?B;>&`(qdeLqUjodlWb4?@U1`n}fuq0H{Ul>Y&``Q}vs literal 0 HcmV?d00001 diff --git a/psets/9/finance/env/lib/python3.12/site-packages/jinja2/__pycache__/_identifier.cpython-312.pyc b/psets/9/finance/env/lib/python3.12/site-packages/jinja2/__pycache__/_identifier.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..2f4fd40ded0af43265bae17723a16ef2f160dfca GIT binary patch literal 2137 zcmYL~O>84c8HSxiFf6M*a^rxw?V?&Qix5IWoH%o5VTD5C9Wu;#qDdAs5)%Hm^V1u5 zGGoU{>~!4z>uz`2cDH{Lw{3|77uY@QVX`w>cD`~>)FmzD#)-ECD=a)RoG{`Tiz-EZ6rg>K~F>(A2v%-wr1#n5VKb>U&?gV16q5_+)sb?E=Px@ax@ zcl5#H(}lN}{v`*${P-tW_Se7p(_e@Gh_O$d&$6E<+2`38Dtj?`F}sRiC9YCe>8tD) zdG^K8%N_Re^kwI|z^+fOPuX?tx_RBYHrciPrTS%u{d4=P2K%b>+G4NW*AvnTjIK3S5rLImrY}QLs&!--u zZi-w)-5j}yx(d0^$t{puC08d8OL|H2#^m|rA>B_=AL)LM`bhT`>KCbBrM^ys1Pzij z+@|3kqv10e7HD_~cS^$^4P6>_Y2+~)UD5^a!^J0b*`-SqE-&bEOqV{5bBx9c`G@3} z$nTRsB>#f^Dfu&+bQw)kG|kX7OH&1dB2Dp(r#{UxJZ3Q-oAP*p@py^HD-eyxtB@Lx zHz78UcOf26Bp6R9Jh8_UM{s4Xlo?k}`N=-xC(rmv590CiJ})2ea*vl?Uhx<|J>aKh zuI(_cDZHBI)eNs1yrwZ;vv{oo8S_?=@zyano-=M#xPdvt=f;eim^LT89b>$m;%%&E zr?`!VZI_>;c%It~hwIE!hx63=+;!O8?auqN`A}o?;p`@6vYVK5lPKLJ zjzq~3C69^HL>yJb(WyA@h~uu%5<<%eZAWN26IxSLW1<=tRRs04&^1U`=rd7kFj2Eb zJKr~`ZG?Jp>GSQ5QW?i%lCRzhwB!#gn3`H1YCX9(NJHqTSVS2(G3UegPsW4~4 ziVMqP!g7Sw7uG;H*x50K(-w|>+pgS>V(fObcRSJ`&h5y(9eKAG3cJ17yY**5K068W zJ6e!e1`L`Orx`96$_Hq=U>?#t={RxLO% zg+7ocDx#m_2`C5Zp^TJJII>`l(AP;B=EMqAO?Il`tn!Act!*Gr)4Bj-X>b4o-5Dwd z#&MvU+c0J+P&;zF&H%{mIo%0UKhrb20M5-u{QzoKKF4W`&f4%mm7Qn z@Jt3OIFJP#e=PeL4}yY)?hBR|6x!0XQJJ8b!ekm0rh72c{ouG)29=AcUBpP0Myt)>>A70t`@q6L*jmYLk_^08I)}qVN zl}I=e{bTsy+V8^aPd9)6IQpY^fB1fQV{J3S)|XfQuzWwV5q_{1eX#s~__u4Tk?7{y zM{AKM@2)?6^{t;hdc6Aa!^qE{yn)^1yM5z(xCBcJ3k%nwH-c}5-uzDP`+M(fy%Q{k VzVVmu-YqS@xfs9q1TXy1e*l%*0$l(A literal 0 HcmV?d00001 diff --git a/psets/9/finance/env/lib/python3.12/site-packages/jinja2/__pycache__/async_utils.cpython-312.pyc b/psets/9/finance/env/lib/python3.12/site-packages/jinja2/__pycache__/async_utils.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..a9dd2a04cc06874588c03e91c54b02c392e8e2b1 GIT binary patch literal 4081 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 literal 0 HcmV?d00001 diff --git a/psets/9/finance/env/lib/python3.12/site-packages/jinja2/__pycache__/compiler.cpython-312.pyc b/psets/9/finance/env/lib/python3.12/site-packages/jinja2/__pycache__/compiler.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..fc4e5f1cf50b725a629e2fee5b6e7d88b26895e1 GIT binary patch literal 102261 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

ovFdnny(608Z|J{7JBy*;>A;W8L*W}B_J^f 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 literal 0 HcmV?d00001 diff --git a/psets/9/finance/env/lib/python3.12/site-packages/jinja2/__pycache__/constants.cpython-312.pyc b/psets/9/finance/env/lib/python3.12/site-packages/jinja2/__pycache__/constants.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..33f91665d68ca4fc228754923e3eaabc0dc1bc5e GIT binary patch literal 1559 zcmX|>y{;TZ5QTTaAZsKCMj}O>I=}-)1Rz9Y0wfzFTL=Mx)!S1$TbG{hx&1TJm3R-t zBk&?5M5Io60ZYz^_-gmUYPRZ3Pj&U_Q`PZuhsn{P)}6f;V>o zzwV~pkGq@wgSY(W1bXKKPv}ea$@z&#SFJ(Q?7Sqg!Kl~WFBdP(`Nd3X;{4hqflKJl zx54+&a&f-TUEDzrlBT}6L-c9V=0fzfx{#M8PZ`hP!fYbIHUn2BG-+MRaDHJ~=H=86 z>dkLHMkPn_7zU#aTY_HvL0d0pM5bP9uWs_I9(o-nh5e+#*1EXb0CUn>)rJVo5$01) z65Q0){?*AWwXqbwIf9mk+r#7DZTDhDdJ^zIX|cGB789wuCG`O6{IaE%b=lW-}Mxi#a+1t8U4J zHI)Hi+gUQS&6NWmiAiWq^1y@wX!)A9vXUmbAWM|=aKcauOmr!yfq!3?8*ptX8i+qtG_?bZ_$EG?iC289(V&n*LJ z!WWdf*k*G^{*M*cRA%m z>4u_oe>VciYPPpRvg&6&>s>i7k{tR)8t6Q=%H*mLBi1)K)HD&RwxQ;rtYR(`44ABr zc&ZaPjuYfqCvc%O1L(q8qfZ+h#kSf-jYjTV26JR?G^I`*VNnA17htM1I5n;!=J&!K z<*ZCg$iZl0DJ z@KPw=mSb-#$8qa%?Txa1^I-q#{*!0Vzk2%e>u+Ct_w?oW&z?Vi@%!$L-M0VyG%l%) zkBLiTpncLjhWhD8<65QF@w4$r#W;PVq;2Hk&z}2dywY^# xACV(*7o}Dot~amle!-Q}qkLK3Wi7kj>pjftxA*(~>pSng|G{6o`{fQJ{{n?fH?sf$ literal 0 HcmV?d00001 diff --git a/psets/9/finance/env/lib/python3.12/site-packages/jinja2/__pycache__/debug.cpython-312.pyc b/psets/9/finance/env/lib/python3.12/site-packages/jinja2/__pycache__/debug.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..94bc461018665449ecf46ebe4996a813971e0025 GIT binary patch literal 6569 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 literal 0 HcmV?d00001 diff --git a/psets/9/finance/env/lib/python3.12/site-packages/jinja2/__pycache__/defaults.cpython-312.pyc b/psets/9/finance/env/lib/python3.12/site-packages/jinja2/__pycache__/defaults.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..564722843173581805c92fd05a2e78196115c537 GIT binary patch literal 1609 zcmah}&2Jk;6rc51{1H3;%!iYbvCW3F9|1h*E7HQz2BSn=FNm*cfQy5AxEYZn zE)D^X%25{&0FKEq7l#24%7X$T!dBi3cGlB?8z&(T;fS2XQ8|TUavBfH8620hI3ee- zAP<9Y@yy3VWONK58N)+2p$A?5e{@M#my*YEN}j-J`2x;>cec-7B$vn}iIND3kwKh$ z8ImvKVLXBbct_zkhKDr)r*QsdSe}ANi(VdQJsAc5-r3kg8@_&~<2+VZC`=r2Q|$<9 zjS2!ASgcg*(&`$(U|m|Pa}X+b8#gBNv$v zwJ%zvSk)|utA9NE$e6u0Is1ru{p=?!S(83Iol<(RF4f9XA;f}IH8u$gV69=XknZNm zLJfBvEVSij%OZxCYn_FSR;$eycNBy|u!z~Bmhyyj%|h5tH(JfM1{El(W<%2y)1r2? zLv_t2MM`u#-p7_oH;H9u`$O`jMODRYJSI>Pd&r_4qXDHW>V!O1yLM*FY#Bw|X|_#e z15B3IGVIhj^2t+}&$N>;Pf@%6u2Hn8)@%~Yk_*yeX}t=STdr2h6=|(7!$MZKtr?q4 zu-L$crbD$%3Kt8pAy3@jSQfO1X_?erX52HnTg`$UOVdpn0zW#yn=o(qePr?a!xc#> z-;>JsE48~UbsA2A+=yX9<|gx5gr)CPm&^D0-mcc6UFFi`DJRtyJSO)+X|+Q)nb_`Hk6Xr@ z#q0B;31@x|ZqgHVlbGU`W^AeRA|@MZN4LykyUW5in=RbY$$RuI2*oe3`6o2TenAj^ zMd?3~c!&yzXzUQpy6wbo{=m1lzq$QOVCp!8hVwm?b}}P9lypWXdMM{`CgY5Z_fXc! zjd5#X4)_&W&3zTQB|2 z0lMXkUI5?YC`x3U!K9OzauQkorSh-h136z0rH+Tu_$4Pj0kNEkNoQo#fnk1T-|CHB o1MgR<$m<|WzPP-5W#`IXW>5W|d`I^3Kc`>&3q=GUorksl1B~I#ivR!s literal 0 HcmV?d00001 diff --git a/psets/9/finance/env/lib/python3.12/site-packages/jinja2/__pycache__/environment.cpython-312.pyc b/psets/9/finance/env/lib/python3.12/site-packages/jinja2/__pycache__/environment.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..45f1051759df17e556702522a7fb6461cfc6e0f8 GIT binary patch literal 76705 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 literal 0 HcmV?d00001 diff --git a/psets/9/finance/env/lib/python3.12/site-packages/jinja2/__pycache__/exceptions.cpython-312.pyc b/psets/9/finance/env/lib/python3.12/site-packages/jinja2/__pycache__/exceptions.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..128a2f456882c39799ad02f3fc0e11bff842a494 GIT binary patch literal 7718 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 P!rSPfyZ1|a;K%-dp;n*< literal 0 HcmV?d00001 diff --git a/psets/9/finance/env/lib/python3.12/site-packages/jinja2/__pycache__/ext.cpython-312.pyc b/psets/9/finance/env/lib/python3.12/site-packages/jinja2/__pycache__/ext.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..5a5cd39d516bbd22ca11e9e9d55818564b6ed568 GIT binary patch literal 41871 zcmd75dw5$%b|-l8eiPsed{ZDPK0ryNDC$YQEKzUClx#iPrtKyn+)Ifx39v6fNuah!I(6#QsXubL>>QrokG*>7pT;=uFX)Hzl*pcy zeP)ik#hvGPuAk#|yna;IuVZh0zn;Af{YJbEqoy%)zgfreM&2}P8MF3Vncob*t>4D{ zmQnkdqu;^&)=}q}tKY@^Hu#JBiK^m-dzjw=e{p{?^E=@$=`Ue^*J$ZjS$`Sx z7r|fNU#{Z>kwTE*Hi3p+WNXuVXRG5VKrZr-u3f!$Bo(?k%hnd_(#w1oSuZ-u@=UI+pvY z_=IM@LW(7{@Rd}!o)h#VeaiRTo3Hv%C;jSgV{lXhj+zhka+qHz=WB&xz7FM_%cW9$ zeEk~X>(+o?GZ&#mf_2Es``$5rC}-Zkfp0)AuP9~Z-a_*wozN_$;i)8zIDCZ?W5~!i zzGLj)w03Snv(RzLpv3=1IW{53&S&L#N&l_#TaWxUKPx{5qw!ni*^E59Sf93_Pg@1Q zid$P)Xd6QPd7<4bv>l-v@Ld<7LPd{`@JjKjRK@c;8RMZLaXSSyZ` z`fJFjwzr+%1?+u6*wTMM=AxdH8ANg`vR2 zXfy)9DHP@f@;DBMt_+Le(3lX4;-~kVFg89KhzbWH5kZWi*u$b27V)K2`EqtL6b)Qc zg3ZBjC>WrmmfmnEDqJJ4?R*Gj4Tl6CKU~9O<6$v65Q&Na8v)MoKqNANbaHIdx$v7p z2p=5Gb2cgpfie6vp9zQnBADNTR{6)uR(Ni40*5J;qv=#I@Or@j@@GI(8hImroA75A zOf1~WTM%xZwEAtCl7Vw#AQV9@QN75)Kx8L_s%Mco&_&(o1obMb9MLQ3n0Yja^F!fVsFtTlP=XgYjMml$O zqEP~&pwKCVu5^wLU+f&8j9w0hx;whIbVi1w!lv;+@J)ab=^PmjjRdxIqCGptCo`5y zLX=u-s`_czJLGS*1O`EPom(=j;LT;M5dbhT8W1z)@zDt}Fq+YYf)pkHSyeN!0-wZ6 zIDVr@2rAZ*Q%}x1III949NSB= zzpqEZGTtnglr!*vHzENoHjzUS#Ab3fkkdlWCUOXYrRorxifxKR_!Bt*hfw6;LT}u9 zaH$E-{idY#VAiO&dDAuZSp&V>H%aduJ<@ysLH1sDd7hZ?UCNy@_M0-g0fwUzdNNQ5 zijGY2(ZlD?9e(B9z>)KPz2}af?mIhWeLd3tdI(MsG1SK``&KrheRHUWwS%tTfLTOA zMKu9t5i<=>!NThaJ^4D`1Z1;<^R=lwr5!1~c}Zlin$pZtTKb*5RdDeJ-U#w(LoP+~ zZw|lh`0ciFd_C_F%)Aph`qs*kcRll~K`?`}C<13u%)5CHhKO;5I05&ZTAqAbEVV@G_W!WCh(!{_Uj_%Gxr@n_(| zM8S74JON&eN(=cg$t$cC%kJVt)HfEG^o7DvA9y#!&WquTj0?fxq2Zv94@3h#@Oy*A zT@0e6bAS#!Q3PS&|5#Sh%fk^L{zoqZI4VkkLaB5f9AVT>Tvb$?l1=!EAdUtmBYxk- zNna3UM2WKu_=4f_Nyb!Cv610RAqu8O8q9-u5Df#K4z&_G>

{ksKgWbFe(o{K%e? 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 G%KsnbxAMLK literal 0 HcmV?d00001 diff --git a/psets/9/finance/env/lib/python3.12/site-packages/jinja2/__pycache__/filters.cpython-312.pyc b/psets/9/finance/env/lib/python3.12/site-packages/jinja2/__pycache__/filters.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..e652cdb8352270444c59bb15a888de68663e127d GIT binary patch literal 72023 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πobD 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 literal 0 HcmV?d00001 diff --git a/psets/9/finance/env/lib/python3.12/site-packages/jinja2/__pycache__/loaders.cpython-312.pyc b/psets/9/finance/env/lib/python3.12/site-packages/jinja2/__pycache__/loaders.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..f9622001ede58b94cffc6dea8c4294c786f46646 GIT binary patch literal 30966 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�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 I_P}KR0>g?#a{vGU literal 0 HcmV?d00001 diff --git a/psets/9/finance/env/lib/python3.12/site-packages/jinja2/__pycache__/nodes.cpython-312.pyc b/psets/9/finance/env/lib/python3.12/site-packages/jinja2/__pycache__/nodes.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..961cfae359b2c4dacd10894977a353ac6e5bc337 GIT binary patch literal 58222 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 b@^|`K?b8}W8IL~b?#G2|J^w?nD0M#qVtR&Z literal 0 HcmV?d00001 diff --git a/psets/9/finance/env/lib/python3.12/site-packages/jinja2/__pycache__/parser.cpython-312.pyc b/psets/9/finance/env/lib/python3.12/site-packages/jinja2/__pycache__/parser.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..be9ff8b22601a83c3d6b6c72a26fe2aa3daf865c GIT binary patch literal 60814 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 literal 0 HcmV?d00001 diff --git a/psets/9/finance/env/lib/python3.12/site-packages/jinja2/__pycache__/tests.cpython-312.pyc b/psets/9/finance/env/lib/python3.12/site-packages/jinja2/__pycache__/tests.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..84475adf7c885d23e118529f32d160e78230f729 GIT binary patch literal 9053 zcmcgwU2Gi5ah};9?jK1}lqm6E!~eh2Qj|oUj{3PDin^1};l(EDM08?uxzm)E+MS_# zW+joLf%C;kDA>qRFlY|IQ^Wg0d0^*fK}FeAbY)i2 zRo$0XXH`-AX8oxB=|Cnp8&nAwNLOV-vmwAiy(%5fL}nub4yB`+*lbKyn189!o4#1{ zD$s}1HJRGkTF^(>5k1Q476W?hhk@CnCGBdo>qWaJPgAAWqVE{`{7e1C89gXJ&k@ix zRG_H?%?TFMkLt9-NiniYKla1Ghxy578~0(4mtdPJ%-?|dn=8Q)(^Y}y6ll6D&}g9PDNECF zh>cX~ofz9&cC56=F3|Kupe_5Iy@bGQVI*aweoHc2@bugvqeeCE@RK1_o zqa0wzP!6&Nltb(U%9mIp%G0a~Wt=sm9A+&j&#+dMBdiVOS=Ns796N>bJkwB)vJR9N zSSQMtS=UcgtaFidqxA~wK{>|yP+np~C@-^Klvh|k%ByS;<*Q6x`pcpu9t6y5WihXp z#k>K`tT#uo#%$wdG1q|kt0JujVa!BX%=NOEH-Y({H%GC?Y;Tpre4qj|U!?V*ui3lc zjVsoe;ecNK#xH^&sIzBRd;{NDz3@ghm9|f(49#Yl<#fVk04&?mvKG^|`ziajX5VJo z{CvuqpV!P~#uK*5<6qDslLM;bPb?%+RZV6y3ygoEq8rV~jG?o|l)-c~>Xs9hHOGv5 zDQ+4WX4vS9O%$6>@LnRFWlj}mc9t7Sn#22i0Q~rO>QQVeYX}poRWNJc9k}Z$Wx&7M z^=&aqvw42nyKsYFK8N$Fr++Jo~t|pz@k;OKmEmU#;}L4L2P3< zY3eEC)^O4qJu|#)G20q`Wf(Ffj3gTd_rvMb!tnBnecLq7#YfH#TPd5JUQQ(MByKTl zcqwHpCC(0uy^AleIAMb3usE;7LPzlL5b&<@d8}?@Z7ZjqcLj;r zJ!ZstH74dl?izw>QAn9NG2=u8e?-cUqfI|QN(F7S<2SOIBn|eyeR^1vdQkIv@U5O6 zzs-_&NCOG2bpQ3#y_A(AWh|@!g^6J&@gipfKA{iZfTb*2M$;sRb%Mjf@P!qQ3_~HO zW)Y)uC(k{)wAJx(tR)v{5uESZ$^giO@pJ>&RP2IbttoavxDWGCHJOu|xCEjK`CSnlJ>3BJ{%^+LB!xA`gbv^L;U%i0Bh%Kr@T9W7@-q#ev^1 zQe#S%w%Gm&ibijkww7nJum}w^bTEU3MduX5S;yHPTg)2Cv3bxZvT1u>TZBVkTw63b z^kt>s6_|EEv7*_ghEt(sy`wEA@g%e2qWRqCM4@iOvgz1x9M%1%S1lDQw}H2Sq#eIS zCit%M$5y4Td8_A_O)riNxMl@k&niSG7=dU*JdoXm`%&WmnX?UV+%|u#ay;irjbae zaRBcnQfYFH@q+b|-JV`Zo5?%nthXi=PpKA&`V5JJxd_r~Q<^z0{4wgxVw(CxbbU-#UikUBzuz zs*i4rZ@&Hb?Og0sE^tcPTHYgoL{SJ9KIAKD>%HCDqNTONbR`J>FEy1mv%1idn0c>` z^1g`F1Vs|@*d!>6FzSXz0wwLJid{OwdDeB`~6PA7UILwGq+!pj5I3aFGM`2=77)yV@wnYpmUk~SGY zLR&D+G)ovV_!M2jp5t~lJ~ATC+w}E=MUWmnKN%kYM+uUG;x!Iglr|P}d=eYnn%JJ% zn#=_T4-shJ=3YBgi0cW&!pf|d;XF#FFtFdwKqDvU_Ys(?L%Qbo3X<51yXNh!l- zw~*i!!b^EuLgv>DejGo>?2ES2r1G=zGoV|=Z_%Mek^qxBfoMDRBG&OqY;v1@bUxSn zGN6B%`1gj~Wf<7xevK72fr3D#O%Peb^}~hL7Sm?Jt}Ll1XHd}ZlQeIFG#5Vy*8Ya% zlo_rk=gf;(S1!=CUnWwjP%H(t-7B<^J_`Xl^1l-W~$RJ)%2(b#WdZ6C+lUX(=JJfDKa{||XYRP*HF zqga>Z5xr&Pk+@5s+`!K-QbE_GgD)Fj*}QrW*!WWCjGe}P6q_!NiQse}gEG63l>7>K z`YHZh87ZBST%h9+hA&{qZrdr|j+W@u?D@PKldztt3PNNO%gc~L>(^5VI?PVS2M#$g z7i3!JmlBgTIH5n2Gwc&xdWih|{58=29KR*4%{w_$Prv)*yDwq`xxm07JMfiN)_;Js zrDvsZzx9+x+qaK%sWf>L=5K)FABpkOYs7b6#JY2V?n79nSHMjrvg=ao9eMKJOFj_n z`BY`a*QMA6m3AxKuPQf{74^RIz<*P@ui`!Bdlf~r*xf9{?JllOmQbR7 zJ7J4%Jd<#Fx}`0bJ7t{?TEL}K;c z$!6u}kzW4?YOmi3ip$@@7c?&uSyM$irLO*W@g`VHuO- zu7$@RW&w2@aWR1_Ic}L^YvjnU^M0^sn(>4Ue}F5i$lYn31ny##xa`g0i4P3WiUT+k zmp`O@gqs&B(>$*B#;r87O+zr{rQ@Y3y2wIc%Jg8y-=a+?tMVRb^1erK!oLB;KNCeh zc{)x>U%BLoEKr0knU9pSVqvWXJ3i1_M+zEA*?pF_Y+CZI3F;7bhut!ffnfXd`ijE< zeNKRoPGovznN4tR@-jx}nJ%9M!~aUsQHBnq3;4_$%;+*JO-8#Lth&`};2Ynj(fu z?JFb>e#+o8z~l&9nwXETU(N+i=DEc?s}rEdOea?IVCaPMZ(vTO@NDB$$)^A(K(jjm zx_3FD{ME$?iUS24Qfy=eGMD9Nv9=QwS&b7E$$(QOL#`9b#~-Ikx^pM&IVvaYS&tJ= z;`osZ#4vGMoKRj9jxS}b`mS7YeC#ed?`9Ke+g$Z^paX2FR~_Fi+lk%6`GvibA3+CO z^b^)SP^f1;@wOpGo7Fo*Kl$1757GQ2@{tak@Jg$m{TUnDg6=| zjtKQ4Y>HSQJdZe_!mORhxM|o4Jn(U0H=J&CJVS*^1>KprMMaj1`zV~?^u*Nkl)Q3L zUMJt5!{BO}mS*oRDe-KDi^|#99-z!Icr__I@w0x#C|CiGKnbP&SKk#?2 zzW3^9fqu8jr#5ely9%nUYdciAQRoc7&t!}hdeQ8U58hjFT z6@c5_J5;%yKDB?V<7v;69-{8w7E|}*g6*q!eYL8#@z+GIJv%3=kIsKdtsTFIb~^=B zueNVoaTQe0j*04{<6lxMPYB2z^r=l7-`bpcJVOgLZP~6Y_!yLCQDCiX|$(uom` zHuHe4&W*d9*~eL8xpVtCQFao`gT=)L$7eH z!6zimNrD?CO%uV*lBR{=RtdKe+%Dl$1Z#5L4uU(y*gtd;+%5Zi2<}yaM>cBQK7#ut zJV5Xu!C`lZ;Fl!*X@cXDhhc)xD8a~jpF2YES%UlDA9^(8o}>2pVtbU@7iipr_a8ob z=)O$ti$(k^)E+CgFH!rl5)7|5zTfhw#l1r9t3~{))P7CH&Tm}Yy!7~z`?^X!Z=lCx sVO;cFEB5?hLiAi$m1sRp`Y9^#`e|L`X6$jyYstMe_U*fb^CdOFs_PGl)0gbPZbK!Cac zB@qVGOvc}5vTe7>ab^WgoDn_oj;V2G&7SRVTj~A2O}sPRotf_a1~8Q-jaGV;ZBK7| z_AyYHStp*^$A7Bsy#Pp1PP%8lE{XTnt#_R|b?Tf`rwV^kQeqe2{wV&n%hMMH;VG^HnARDLS(;x=$%axJUoWz7;#dw`RX}-=L`u-tRj;F!7M{btVC2*DFq?L@8BV zuL%M112d2NK+AM~UE#9)>y@(oNQ3+hM%oQXdr-@m^YXi>UgRjJ97@H|GdYo(_k5#L z>914V{<=X)sd`O1-<0!Rjqm21?;3n>G6~NKO6_ZcQs)l!qA}pDQ-nX?hVM@p**i_#Jf{Ds>uE>rP1GpvI~!iRcU(7 za^9mHQ<{--6aFaW*9+D>P%yN>NK@6EW|{3Dh&=E4r-}vsPdTn^0fai%fY4qx4xMYncCpy5 zC&qf#h%Jl@tVC9-+ut?lRJsA{o?<~cp=|Zb??T^p zGhFE!v?+U#dcVJDD7G4cL-EyNY(6}N`LI`qtuZg3HsE(k=|K-CR_FF}=w)KS-|Jkt-3M;!d8jkw=2i5R!|E000Kav)Y zco1&66dnyJX~)SxBoYW+rquU@w5`8i^^d6i{XT7?7@Z>`zAWK!TR_uHr_x2kJf}(v z;5{)d-i%Nl`HPpkheOfsL*A%A)a?r^D7@Pj*|oKMB;t=oy7zVu214GD&)@A2UGEMC zE_IKLMX!WIJ3QOAcSizIf7giDch!5@AL$+ngoeD^yGNseV8k;rmbUE=dWSD5-h-+e z6;Yo^D4oq>(Fc|ZbsXcOm;zHL0YB)q) z9iY-!2{|Rod8Oqf)*9&X$k)+wz{0Db6+J!j4$oH4R#psw?zA5e@cAR?fsX@P?>4HV z-e$uY3Aw|L=Jdk@Vv&bRPe#m~#J@QzQ9rb9tU{;UxD_a+uES8L zos-5&}>0!3&!&4objw+q@g2K)3I_qk;rh6 zADLVJCwSc!`~u02=S_^8wP|rVFM}7ed}#{nm!>H4+Z54XteE`vAzE2iIEC~6l45>M zGU|1XN$nO6By;%EkV>qQ&sZk$L8~)cVt2xWC6@RD=Hj9v>a33HjEjYq+%v+M06v3( zyxo*8y5fy^qfu4=Hv57RwH2jBs76`l6xzo495g0Yt`m5V9`qt5UXRCw@TsF>dPlOh z?SZ3xsj_;pvL#j7l61B_a#b>deX6~LIH8bt*x%ouw)giBhn3MF`JMg!*G9cTEk^Q( zMu*dqcQhJSsbIB{9-Ht;I~YSS><4S3sH8kdi_x_0g%MiVy+O5u5)$LY>SJwZfMkyo z2#=h`<27Nav}RJd6_^UVadqOkrONfwJ8$ou+57gsi4#i|>!vr|Zl7s?yJO<`BTHGv zBw5^vZ5aWt+4A@6->siJmTKJdbNXI33)b?-lz>-9lqzpgqCsK=J!Qqn)=|lz$t;7_Jg(cD;`-sdj$bX z7@SEc9KAyP+HhF)BcC_KNal!N9Sp0(jFAfgB#|g_#Ilc7;Jxgn5QC>Yrx!dRUmA_d z!EhL04T1evIXA;9^X0IAC|dT7MxxDz1ScWON08Hh(+gJ9FMIV;(NXVcFshXf7B$3LB?kjnIhTk&M|yfV3qVW)GSDAo zYD4Lr`p1FR*7hC-5lTf4&<#ZTjkZwg6)7kcXXo`&@(R$RkdFm_Mra9fr`UiZn7<;8 zJy&}WnYITY0PzuMH!*x+;dyk$ncFD!0J8PtFG6z2gzz701xxd%j;d*2V()^ZB`LMA zX_mG@no$XmdH6@g4!e5qDO^Qo4=VP-_TFn~m zL%89Lrd~i$&QuYgXcVEaG!2_++JGPw8+iQti%KxMGpFJLOx&<&L07SsvP~85ELP~3dqh2rO6m-jmlTN*D((X z^?ktpsDG_8Wr$r2frz_dqMR(B!jwhum^>C9#W3U+=R?)97a}#L6IDtR6{t)J^+pZ* zy^&ESyAAt64aQ_XCTvAu35UI7#?15u{TO?yn|GhjbagMF2V`D%*&pqXjDX4XhWz1C zNMc#u1JTZY2A6)8^;El+tw?Gg@}?~;MmlSrLqZ-$F4@=P&j?Yd6uHZZHz|@L#m$$+4`jSG+OvFDp8q|?X zqvQ-z5hHULV^xY?L4grqw=x2H5slCa5D61MLPR4H7!CxzDvIp|g<{(4^cbaNbrm!l1~}d@)x=qKl$KP|ijZ;#%T^EpHv+*R zDMAKLg+qR%nvef>|qlwEqXAC(w4|bFc3}K z)e)~64N&)qGvoz>Gc3ZKB>pt*ILhF8SXIMny0jNT0Z;=!`v$vw6eyw6-a^{Sxk|p` zJcE!3u^+U&Y0PYiRyfB2^&DdV9wmDnj|m}DZMRe`IZCHHQjUhD`j*A|j#PceT;F{8 zLj8`ZeS?s>E4;hr@+}*XT1k&5du?6ItCG_76 zKv&ku(U@kyjR0oY07ooMlXR+GN}Ixwv_vy5Z4E>yXIcu6_(PzjFQK{W%Xs9`(o%}; z4-EG63RG+;3g4kboA7`h$tE~UZ|#}dbL-&L!30E<<|S9t5SGZ{T+X@`q62i&8VgFKi`MM$%V0971mGcQs96DG$zZcAT8(3PFUuSEHv(Tso(-|HP1_L9JKxCkuuexc8NJ-kJ zho^0qMxpybfw3ZuUZ^Jln|4VZz$-0LyVWjuRoY?IdCD#D=ixyar#1bQoN3)vACmmH zlf6XeyK}X-K@7h}@0ei6=sH&m|o@lhV%B*h5%Bf6F9w<*<38 zh`rc2@JOF&BniblfZs6Y2>26?l8@3z7`ogMELc&`2%w5o10I#;GnkShEd-*xb%do+ z{S>2d+~m)N4vS=u-=`SPuKqh|!_P=^e`9}As$u=`K7-=fXnvhN+t`yxXxo)&bR_b0 zPj`3x#*G^nJngdFEJwgf5~5*Ix^W|$wC$A(H(I(bb|6(p`_nAp=p`jQ3^^>D$na6= zuXwv+7hm1pxqHVrCC7pt@X662M@&i(&r5zY)YV0GP?lYLS(bnjf(}0?2VXC<`Lssy zN~mSoidHtw7aop>{Lwf7ANMPx@yp@s@vwRs--F>eR(jU={5Iy)V*n}#L`Lhg0Ht2F zp;5}kSGRTU7;kU8;K_cxiU4Zg(XU+JY2?k;!SY^sg>rkl1~0z4wR7iqPy4Ie$MZv; zZb#9($1mzd?KXHEvStl%g-mZ_@LD z;M=}y4v9+fcv0Mpoc1rtY4G7WIc-rxN{n0ek`D>fri<8VVH|$(xLqlZ<8QoV+&S*Z zfrC@;Q}(Sm;!dMKrSVd=IbJ$MbYz9o< z)qOebA_c(;r)y zEEdKqF+wGPMPJv}9{RNac5J*%g<72VgD70g<@-Ds;IK@y+7GEr`4I@{nfTYG`X^1Hx}^k%YJdqk!7t zCEpRgYmQsv#rpxJY15lclAsh1wQE4jd1dJgSey0UeIV6+;Slzmqw=}aCrAkewdqZ$ zazaoU`GNr$CP1ABJ!j~uEM71TK{D=?Bcr}6Br|(u(xxln8_=`{E~#Ex&A{DyA?ZRQ=lm?U z3DG3mm&2rdhrm5BK~0HBlh1xHzS5+8C};gJth+hwEOTp3Mc7Sdpr~ro0 z+~tj(BDax9pos@u{u>z30HhWBj27!bPoMVr4*0?&W4U2af9NU(^xHek(5Od#K@D7n z^-GXr6%>F`u$a_chHbzx!YnRz^l16=xQ`zB%oVUYFbh!vP)B&jAlM))SA9SXB9$l5 z0#f(o=#~6(7{k&d_bRXf0mKFdI14iX3jtk4LHRY*CZyC_0DdPo8$Q20Paa#;BcIj< zH?5zfA%(&nvyAD67*c4wIkyp^>M?f!Y^G@89V5}5?>k)bLya2abL5x2!2lHs zo;_O%tavVmuvKLggtq9jmQ7mF9^X~ianbOwJuM$}m7s+L=TjtJakn|Z+qi$>L7Bx|-M%eFnLbWavA;i0~<{*YpXv@K^~|Hk)URAL`6s^lC8MsGrR_qbqdjKDauPhylop#*V*O&pGM};snqnniZ+oR}|Hb&`V00fuR%=>p zPm2ec79uTnrbYV~(&o$2eX;VkSK1GHIxmEf6yNO~o7&9~z{NH-f)dHMUnMD|-4v6k zEcFIeWMdK`7KvDqwsypd_j~0lu<|+3#L~y4{oUS!v2r6cn?pmi&!|^1Q`5n;_)JWq zbw;Ia?O2(SMN8OTl{Q1cnKr3@^%PR1?Za5uEqQ_Nw(CDTuH^QnCN!u`5{agdg$BBQ4 zfwV*k(h@B@Q2GWGg;a!~{6Y1bl%H4L589=&u5h1&H3|FS=z;nSr2`O@e%5^SlPNMH zWL+i?(A-<$_OJ%SO|MLu z$b;~D&%7+)^$V*|;=1+x)brC{eJAo>&tmh=RP)aHvkT2V3mf+>IQLH+{$$rv)79_T z7i-&7we54w3$>nPP50cjlxy4lOB2t3a`4df(RYRxH*}{qbkAECHtb0@Jau18RrLJ0 zY2x^&mFpAd7Au>liYCR$ol6ZHXWg^vv@$t3DLpK!xNV!UCF|Pfb}y7|pS1kUQMOcB zdwbu^zPArd9$KnempFX)=$)hAIi5I~tlBbp1R67E#jU5Oo=&bi@W65Kp}YF_(V3&k z4cq6BEV%bg9{!ojy;QUQ_Nz0mzCAuIE!AzDb;1E;XQ#!b_43_gcaF{8Tv)&L_jb(R{O=E>);}{{{HUxtu_+OoEl$>N zNtJDxwl3AIOB_ucOV+f`NRNw!>OL`3PL24*dco;tD&Wlz9F5QcF1qBDOP;NN;Od;W zE^h5jZSDP0`-80~9#wCgwI*)PUYo0(v(N9F@4A2OquL*DUg&)>`ON9$>6eo3m!YsP zuK{do+UBgYH|MU+*UsDT@4MgiqidhkAoD^^YqGj+PRf|YDvzGF)V)};Ayu*=G4`OO z{riCr!}r4X2Y>Y9k51nodf+*_R3pz;&)VipbGzpo=bPqw<~rwY}R+-qHDr&VX=B@5^_*>9oNt@2zkmGxfgg)M z-u&a*6nN_Z}U5!40+ zlrwRM-Xl?XGY&zow2*oxUZSTOcg0;pL^oGB#jdANi{mcEqPXe>)Q(i+u2A(Fd5lsc z7Ubb=b;Yd(+i55k(9Zt{!m1c4SIP>u)lhz66Pi|j=7z`^d4*HT3*}cTUK8ThLx$Q) z@0b1tKUEp)Fql{-pa#M74a?Z}7=_Icm`7q74FhxC?4bO_3#SjC>_7UIGv`kBzx=}K zLubx1?f$7FpV8F#j8u%D(QvAxM3$GwR@D_I9 zZ<$zt;z$`rIo~3M)Q9o-WCDkjWDJ${WCLm+08NY{*i;k zvWy%&1>O-lGC}<J}o28VxhL_HX5B_Hwn{R~3=3_@A1(nvUk zCPYXr^VhV#Cd>PNaAf}4bf2*#HZIh5CTqIp&OWHv{(~dGV&@jV)!ZV&(6AU{Al7>9 z(W~!L%LoGMBt0hRK|H2P;7QxDuO5hkYmb33@{T}IR@C32*w^Smy-Hh2OE5apUZ#GR z!u}CGh@Po;>A{M>1s|P8NHAt63p!u&8f2*RLjM17mG zOB9wC!F~mln`z5PKNz@38Dds&A=*B+yATl7A0Yip1U7;lj7V&PrR$NiVbR%~ayBnG zTP6-KmAEF3d|Cn~{dc|!Go^JKleXHWmd#1q=1KeXMeK@BO8nt0ofNSa*U0Z#-V4l| z=g%x`-n$_8{8=^DqshMM@}-LEhcyieKU?%GYZ5#E{(h7;eQ3#Dmnjx1YaZK$G8qf; z?cbXDt%aI4a0bn7$ujwotK!>VOI(|6e7is8+B6&c*tKn`L7uiRl{L(kr^=e9OP0#q z3G<9&TH;C7+3gEen^UgMa}6K6b}w~pO_pt)wkIwc$(EX1QSOqngmF`6-#V3P6>9cp zI)!pKF*=Fzw;hv~M~*VK?l(VhY(NVW&57;P$7U;2?oCsNm&&VeZeQ==-3zX!q^;?pqiWHyKIK>s zgRfh~Q^hI5(uMNA1zX>;+2pilu)}ZVi(wHlqd2aUwt^V+UyJx?e(R2wMYa_FYk2a7 zxu{0Wvxo5_o!Qxo4QXRZ)yaOOp!Ll-*_4q4vBG8NI#QTalOkfz0d_yxr4rl!hDFY} zgftaco*gTS!KY$YB)tttM_bYs?=E2Ci*#H{_G*SVj2JS*8fYV!s)cWM5`DZ3T^-Kn za7g8Ad$2JIRSjfLsCGb2*|{rHVz9GV9{B}i2aUzPFIPW-0+7xT${fuWljae(`XEXi zf*B9ly;8JR)|#!LoSNcBYgvzcnC0d=r&T3DU1W42Co>=S9+`uqsk@0u{{)GqjwS|` z2+nEgl0UnjanifJ2;!BG8|Nca{}j|=d?XrfGTR!{rh*#%ztp$l{7oyY@M^TP_* zWWL=t*+=`~LsLVEnuXHFN%PMtYNvK2l!-$Ri)nU67m7DcJo~ev640Al=cmpmEQ!cM zN%N%Xk)vedDC?RJl^9OP%jG}9EXbPaDPV9~gw?2=w)2_~%L6z%F@xf#?|1cAm;JZKE|1ltEbjIv(I- zVL;OlA9n$)Z2d$inaf(1>f$0|DKB$hW>-BXsMnAX1oV&bf;wv$Tp^Yml~&ob6_nCH z>Q5KF5}~84l_#Y)OO`xa z>GiPP^Fa+f4&o+d@5I2LO=QnejyJl(aokIx*x{ld%(_$($y7#gz0n)XypI|7^!tLxu}HVy-w zAM=)zFOCK}qj-WoL;hp%tTo<%qQNL4ndT5`jGZ0^MooOj%yt0onHk=y{|a#oj_N1m zTf`#=0CYkNmN^ipAhY$ysde*0MN*lal%jUd z4vR|O1gHM7KAwkXtv(J>iWM%)zCvpxJV|RL;_w@v+;mjAUkUgyIn!3Y4W!Z_Ly)Dh zSN|N3ytxbj&_VkG0LTV^L;%=;oS4&?ybvB1ZR=CE^@$fB*fy@1&YryaOk>UZz8;>n z`aUS0(ONI^F?32k$*g{U$%Cz+VjQBQ%Ls6aj+O;JU;cu8jQCg~>_c;KPeY%7frvcxk*M5Q zi7_Db`C}S}!$^twQc`~F>r-D(9J+h*&dG(6Et94toBft!%CTsxPuc1dJMSL2bKrrk zokAgFF4}5Sw%UaI?z%hc9@tuzT;-F+d`_9K`p42m+Kz5v`Eo02q;nu-(oL&9J7Ix0 zcQ{pn&AhnDXZjjqj58HttXl^aJ3Iw_7OuWv3N3ct1v}?B^9G@8K&yM;9xlu{?jK_Y z`XDlFR{d|NL;Y(!B7|6wi};3$8KfoVG+=|Te?y>YK^p9;Nao^oOHePEXZ9wY>wo#s zRr7OfpCG9Iw@*R0UcBy$h!ZKlB^3#;JF3jz7OTvKJKlp-PwY5uhKidAEW|Ap0KxS$ z{%E#?`XLBFoQy`u*a5q@B*Jot;D{nOZnu*FNDihMutR}q2j5SpZD)4Gg7WZV7R*)~ zg`rHo`AgZ!V{?*+Ie)6iNLF>f!VGIr7nbUb+6M6cZ~ofXvQq zJtFv$dX>-LSKfGK$ys*mWkJbrM!jTpugDTS8fl_3@2U9Nn7)3hJ{ds zp-Cq^`P!^POo~pJS%+G3riE`*B})m24l&~-gVrMx+ivCqw{j&c>c?Td5PDK(44D@4 z@3Wow6rI?4`@qbB1y^Iz*0{P8q#tITAmuUbPUR}y^d=YT4pio#BZc^`@0b+xcP;3q zbV?mVsp|Xmh~j}G+n2~s04vxjwG=UVk_5j~=>MV~wIU9yd3nXRcP6B_dloAHe_cUPBTaedS5lzNBp*?`JNjXw2yhO8L#_G+#!>*XXgr7MZxn_QaZL*(td4 z8`}+xa?tEp;qtgVEKdsirz;ypzKj`bK9(^v&Hp!B^(AZ-RWNB(!5sUC&w;Mm8{z~97O!07j9Ts~kmejq)RK>YpJ1DD+BAQlSb-Q7vArVQHH%~r`yBwJE zd;8RH%{G7RYRQ0q;i*#l7v8k2agg-zJj3 z-Aw*YOYg3tw1q91c}u;4$j_i7Pef!Qsku`C)sutOZUtg!;;(SI=odN=Ez+Y4m!lI0 z#2P56=MaReZ5W?*g>xdb0P=sJWj;XD$JlnxmYCZ*VqpsPjk7hs(Q{6jfp{Xg50V0q8tn-{NwVSgy|<|PR?$6zw6zu z?{z2L+aF~=l`-g`SDzO%di2X**ai0n zh#4hSpOm>FWRz5W@wr1IRV0?YRoZJYzf->3^gk5$nk+vw;p-z&g!dzpnfw+@Z)s6s zzWMJX`>)Rs9TIMdKGS7f0CcgEw(S`&D4~cIj<3OkrWw#R;lNYXij zQbqiYi#LdmtkDHL*xX_XgD66vjd*YtSE3Nk7?YleHks%KIe*@Q^Sg-2pO6+-Kn~l? zzGWJeLr9D(X7=p6f9QwDe{lT4p63_JkEZrKKX0Dik&sAfH0w*%Zuz*PBf01KNo%tF z=n}SLp$>h3&1zTGWXZ37ZV@VuiEJ+`QQIp?dC*?Lxq%>JL0IW@SmeMMWSwBlc^1I3 zSYq(WgOn+@eifvkJJ77fJ(^jE3eXzbBvNGNp{|wD(@4x^tin8CGr?vPQiH|b&~$g` z&d@u-1y{$NV4{3loNjzuN(57`j-;*QS0B4Nn7PB-&ZhjX6T`}wRKs^VqEr~ zf}MZ>L6;i9kRSV^m&Ra>3{=1Y0ph_&Be*}3Bnik=t0bhfL|Jn*9Q3(`xBLhTle2L|8?(!$@q7nqG_kD_5@M^3tGCa|)h$?0x<8|UzoN(gNss?PkLU16OP9jo zpt?-o|B)UfL#e-_$A6~B|BFZ3#z2h|NNmokusviqi|7%!(m;h~2p5atK`2AIJ3xup zFxF9~#NyqfKE8)!5xOAhHQ{GcXT~X6>SinH06NjG7I{{Dzv$hfIq^fwJ z;mcNwrQ&g^#jqY)RIjZo5|9Ys3dyb+2lfyqQjirB#oDmjfUpz&jsZrdOukZmH5!z)P^hD^n|3 zs?n#|Ol-FC{nmF|=Ndn3xz{pZ{`*zGTQ%32YTA>kd5WN1O^xkLhE_or%V~TkdR`eewNs@1DcOAJmb~j8(F<0Yo6j zybmzAraIanB$c_p$>FAaDF)UhN(@sJ2LNN{82mv4u=_JU4J&5SBR5 zSPcd)k7~zl@@fh2%cGPqQ`hPjw%vfJPExskyPJNm9`2a}lM@`&1o)#ov!08OG-&~t zSOgA0Zz7a#>=rCsI!sD(KDxB5@{W-Zm6w_hS;zw(vXj;>*!AH4p8@CsbR5dP^^KLu zFGSWa89JQ3s0xQ0{kR$}+Hdqbd+G@HS;+@rw`AP;+LldpU{$vKI|^3g^?|llYH@3) z+=|w=w(}!>T%Kch)6u88&=g7uDHYof!Pffi_>ounM_L~%d#-#yq0Ontx&ZENlPO#w!b)riI#pgfED zFtB={*tJevY-ji85o^!DiR4)nV>&GcMFS~lUPf>`UJ$GxUFpV%7-2iEk2!%$3Hi-E z1-eKz@}dk`A|K;1tl5I~0<@Ab&9c{U>jeeFI9#gDCvTn+9}xi!EPT4@J5V{O#~=VJ zI~+wMD53`J*6<4?>DUw3@A17GGT2y~N`dHro)MAJ$&^9O^lJ4xnvYf)!cm6ys1sp$&C?HNkmrlV#C@D}upk zd$(6{IU18q+aEY~VCy+2WXA)?PMnona#c^3GUgwBVZs!N zDk{xFW|OPB(JSaQYpI)c^q_9?4!4r8g&v#nVCPh2d0;?(<{93v@>P9N+mNt_8h;uU z{3l3VUlE1ch7_A83+vA<)SOF7?uQ6rxU z_cgz#d`>Us&$waUi*&3b_!*4R;gLw%dX<@v=p1 zV%7$)(3UR00BcZ$-Ja<^@pr^RH=ROZY1~9vFh0lDykNXVvFh7H1>WY@SVE7TdEu1ISU2tW7KT9LJq(BgoXx=+5d!IFzosBR zfA-{wuF((~VKdWk+z|{F8ZY1+?j43Dy3Ehz!g?KdMbLR&M(b&T;|EJ*mYG+n|1w7Q zSg(hlQqk8Rc7q018}D@-iDma|knTWZq7ls5=YfHEG)xT#0)pd4leD$xENUGLlSvG5 z0c6XrH5ez?wRS2!K->NNqKkw4wVA(K>9%*)cq&F^Rt{LbIU`KQ609SDC-!#f&Iq)O zz=K^dANvIl1_72I74UlnQ2`EWU&ehIR3zsCAze{ndT!&!1?n2HjG6?Xgh%Om5oY18 z?9=bvB%^zN*By@`{+vk^00~$epPvuLzyNDU9&EIe0PHvdwI+)n5d&?|IYJQ5aA+AA zZuDpuCvZdo)OBeCInXALe28DifKKoq0w9iM0BqfL&qx?|r3CzuSDLb@*01Mpx=66c z51Qa=6OA9rD`GX0=CzH_dYo#YtG56;{!=Pcf=rij(|ce*YcuwK{J5x#ei7x@Ya=h5 zTDXd{(QIM(kB~4>Q-2AnygI*%fzMtlf#C+u;95g=Y9resj%{l*Ol-3~X1y@Fb?Xiv zKWxuG{AqDB58u8!Ew*ajJ?$18Q^&MW+lf$r1C&mkr^iQlKzb zl_V7rg7;Ga{S0PmHx)w^{1TF4H{vP5Rx&aE5PK2!8T+IK*Ie^MM4#A7CVem&oPG(9 ze_LEORWn^V9at!qe;xm_!%F9ktlD`aAF47OF-zo@e;be0$18^HEH>|vbL7IR6f1P( zf_~2c=KY0I!%!W^Ds~*-(<*Z$IyViMTy&?HhwRjp{uFC^9c*A#NeKd_}*1 z1#0Lqx>SZ{=P+;%G#QhdNrRmfMl=?NnYcbyyAvl&x4t6+A`81io-Sm+Lf3rs8nh7P z55Ho=Dh7V#Qbr9!&+xl^Io{)P_z@3FO>>NHp~j8A+1~{kjYa~X-js?_5wA}TN4Nkq z3>i28{WFjBNV57v{WyHWKMj3t(59XbyED7)wsWV zGD@n$hFu^_3i`JF&q&oV&s;&9VAXlJF@mn_~8&O?YGz-WA-owSu$mRr3*hE zVm=kygb4^kI@%?~Y^1JoOBkG^!#z7{_&TP8!mlVbr=6$yuXZs@P}aCK?D8WJ2>ukU zVF7t!BdPymE=CDd3l&F_&Lc}z^)RBh(?u`RTQDICUfV4$jS>b4y*>>JdZ99(|oZAUp+;wd< z04)XW;AtJ=og)@W!$Je$3|5Wi9iy;v58ZCwGe7}MjlzF9EoV;&2Sy1P1tC(TH6>Q6 z!9@H1p9m^7XgiidoDz25icQ6^htzhb4OSQh4GL-fA`D(u@mLE+*t;zVB}I%OS5_oJ zDk}n3IDH1h5CBn=07lSWD?wcQz%; z?^fNZqF>tCw2WWc;ei?KomF7-#y{g<2BTAvDa+Y`p}Ksi#&EQMLT;JBvx4a<$~#qR z!KqSyZjsm=D;N`7+IkH46#3QI#$K6jETYBsia&_%vvti7r98N42|w=032yEbB|k%1 znbn?uVvW%uw3j>fn@pr5c^W}!iBy$3eWZ|F3}B-XbMdwr^l^beT!zA+*{G~$gY2#Y zLFC5*3KPUHitQ)_E95N zY|b8}FnT1ZwoOR;n(&F#{#e4cU!spTGwbJeYMX$Pr8d$03!oi8cgM2jVU2Op7shjP%tT%0+0gnV=7sZ8Y=&zQ79$Gu*5UU zr76mxA~DqRWRC!uoHBxCVR{M}EzmVx2Hz9$;D^0%I!PtDNt-i(qTy)9(#fRdr|=-; z)XaxrP^}2Kj~Av*S*9f}Kz}5X{wQwBl557IFy@1s;^25DH7s4;Z@{3RT_P5NAa{hC z!P-L1NS+|aCt8J($(U>ZE8);)B*$E)x?GPiTyy->M3>D-+$ znTxkUAA5WM%>G%4|G1of9%$Rc3VGJOP_cRLP|~@T&IN7zg7IDNly(RoRQHNzl`KYm zxiBR^{Vg})0c0b?S@>2uZaAx*9K0uTsA#6v)Kyk+KI;5ulo6}S?JyWaTJ`(;{{!_^ zqtp#elhQ5clymy*$F};_tm}&Q5k)T4KAb5qeV0yif-`sQH!78xnnQhoTDXE!Wo9t3 zJk;iA34TtE<3>+Q=AC=^qks_NYz8VBc?|k zr?ghwO9Bppn>0D_t39+yPv#*ijk0#OoPKpWJk0JTVmB0}i=hhP_xbYk$`*FJiApx* zX(z7jz^%m|y4TdtF8|=S6_uR*+E)(u_dS2O@A%PE&!x+G#kmG4rYO!qpT#{XFVWqI zeOQ-CKddrdkMuzNAPV7V+67V>!e%MIW|=IsfXMu}1??wCqm=Iq0)B_mTCs)i^G4Y( z_^LFe)D{Ys4&#kId5RPk-y_KbM*wNhK4#uOI#9 z(MccJ-}*cCvwa-*XOE@ox*teeCongJiWB0DdwO{G^xT%z?xV@}V+-ZS7s^jg6it@j zs+y`=5KjKAt>XjBM9Ji}Tk)xQ;`x-TWkKkARP4A_GgUKT%~(stlIh-zfLEe%nO>PD z@|W|VYg&*UL1IRrmlxJoV#zP+?V@`!dTVTI>=*cUXX;@ZO$Fga1>u!(mWrD>gHDBQ zo|UMu&6y@j$$m)EFuG#d<_@uJ%TBvk_qe`FtVl#M0$y{6*z5j_KRow?bITO+cx#a; zCuqux@*Ji(Uh~&}KlZz^A2t5*rjIuL=-MBTel+?~M{3V0kOEQ8xLx8dSaY@9X~_ui z&h{b6Zj~`RuJ@Q@C8xv*7HWD24>v+JT#|mNqmkZQJ$Oaa|Pam+U1O zGkG4ltEhlPWafp8g#s{scE_#ysru=@sg0Q;7Gx7jN~y%@$kYp&Vip7g^s3uEGd-Hw zS>>H@s?w8TWy9*sTD)AslEFguV6XVtyi>F;71=ZFU0u)LZ5{l*r-!{CS!~M|qMdYJ{7#Ye1I9iKdKmX117@qnW@Z~cblVy#wJCkLtDNEb3gOaGCug$?0v?~QuM)d|4wU1I#QzW7_}bI} literal 0 HcmV?d00001 diff --git a/psets/9/finance/env/lib/python3.12/site-packages/jinja2/__pycache__/visitor.cpython-312.pyc b/psets/9/finance/env/lib/python3.12/site-packages/jinja2/__pycache__/visitor.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..7a016a6bf67f368ff8aad1b69d2be4ced3eda8cb GIT binary patch literal 5356 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 YJSOzqC(u3U6ZQ$4=T7~Lz=LnHq)$ literal 0 HcmV?d00001 diff --git a/psets/9/finance/env/lib/python3.12/site-packages/jinja2/_identifier.py b/psets/9/finance/env/lib/python3.12/site-packages/jinja2/_identifier.py new file mode 100644 index 0000000..928c150 --- /dev/null +++ b/psets/9/finance/env/lib/python3.12/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/psets/9/finance/env/lib/python3.12/site-packages/jinja2/async_utils.py b/psets/9/finance/env/lib/python3.12/site-packages/jinja2/async_utils.py new file mode 100644 index 0000000..e65219e --- /dev/null +++ b/psets/9/finance/env/lib/python3.12/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 # type: ignore[attr-defined] + 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/psets/9/finance/env/lib/python3.12/site-packages/jinja2/bccache.py b/psets/9/finance/env/lib/python3.12/site-packages/jinja2/bccache.py new file mode 100644 index 0000000..ada8b09 --- /dev/null +++ b/psets/9/finance/env/lib/python3.12/site-packages/jinja2/bccache.py @@ -0,0 +1,408 @@ +"""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/psets/9/finance/env/lib/python3.12/site-packages/jinja2/compiler.py b/psets/9/finance/env/lib/python3.12/site-packages/jinja2/compiler.py new file mode 100644 index 0000000..2740717 --- /dev/null +++ b/psets/9/finance/env/lib/python3.12/site-packages/jinja2/compiler.py @@ -0,0 +1,1960 @@ +"""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: # noqa E721 + 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 async_exported + from .runtime import 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/psets/9/finance/env/lib/python3.12/site-packages/jinja2/constants.py b/psets/9/finance/env/lib/python3.12/site-packages/jinja2/constants.py new file mode 100644 index 0000000..41a1c23 --- /dev/null +++ b/psets/9/finance/env/lib/python3.12/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/psets/9/finance/env/lib/python3.12/site-packages/jinja2/debug.py b/psets/9/finance/env/lib/python3.12/site-packages/jinja2/debug.py new file mode 100644 index 0000000..7ed7e92 --- /dev/null +++ b/psets/9/finance/env/lib/python3.12/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/psets/9/finance/env/lib/python3.12/site-packages/jinja2/defaults.py b/psets/9/finance/env/lib/python3.12/site-packages/jinja2/defaults.py new file mode 100644 index 0000000..638cad3 --- /dev/null +++ b/psets/9/finance/env/lib/python3.12/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/psets/9/finance/env/lib/python3.12/site-packages/jinja2/environment.py b/psets/9/finance/env/lib/python3.12/site-packages/jinja2/environment.py new file mode 100644 index 0000000..1d3be0b --- /dev/null +++ b/psets/9/finance/env/lib/python3.12/site-packages/jinja2/environment.py @@ -0,0 +1,1675 @@ +"""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 # type: ignore[attr-defined] +from .defaults import DEFAULT_NAMESPACE +from .defaults import DEFAULT_POLICIES +from .defaults import DEFAULT_TESTS # type: ignore[attr-defined] +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[t.Any]", 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.Any, t.Any]], +) -> t.Optional[t.MutableMapping[t.Tuple["weakref.ref[t.Any]", str], "Template"]]: + """Create an empty copy of the given cache.""" + if cache is None: + return None + + if type(cache) is dict: # noqa E721 + 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) + + 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 = "