From 963b5bc68b16e1b2e2d9ac1d88635184293b018f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Batuhan=20Berk=20Ba=C5=9Fo=C4=9Flu?= Date: Mon, 12 Oct 2020 12:10:01 -0400 Subject: [PATCH] Added delete option to database storage. --- DBHelper.py | 29 +- ...on-firebase-adminsdk-krrgw-05da515de5.json | 12 + .../DESCRIPTION.rst | 44 + .../INSTALLER | 0 .../CacheControl-0.12.6.dist-info/METADATA | 74 + .../CacheControl-0.12.6.dist-info/RECORD | 35 + .../WHEEL | 2 +- .../entry_points.txt | 3 + .../metadata.json | 1 + .../top_level.txt | 1 + .../google_auth_httplib2.cpython-36.pyc | Bin 0 -> 8182 bytes .../_cffi_backend.cp36-win32.pyd | Bin 0 -> 146432 bytes venv/Lib/site-packages/apiclient/__init__.py | 36 + .../__pycache__/__init__.cpython-36.pyc | Bin 0 -> 857 bytes .../site-packages/cachecontrol/__init__.py | 11 + .../__pycache__/__init__.cpython-36.pyc | Bin 0 -> 600 bytes .../__pycache__/_cmd.cpython-36.pyc | Bin 0 -> 1543 bytes .../__pycache__/adapter.cpython-36.pyc | Bin 0 -> 3087 bytes .../__pycache__/cache.cpython-36.pyc | Bin 0 -> 1816 bytes .../__pycache__/compat.cpython-36.pyc | Bin 0 -> 759 bytes .../__pycache__/controller.cpython-36.pyc | Bin 0 -> 7829 bytes .../__pycache__/filewrapper.cpython-36.pyc | Bin 0 -> 2204 bytes .../__pycache__/heuristics.cpython-36.pyc | Bin 0 -> 4734 bytes .../__pycache__/serialize.cpython-36.pyc | Bin 0 -> 4241 bytes .../__pycache__/wrapper.cpython-36.pyc | Bin 0 -> 716 bytes venv/Lib/site-packages/cachecontrol/_cmd.py | 57 + .../Lib/site-packages/cachecontrol/adapter.py | 133 + venv/Lib/site-packages/cachecontrol/cache.py | 39 + .../cachecontrol/caches/__init__.py | 2 + .../__pycache__/__init__.cpython-36.pyc | Bin 0 -> 344 bytes .../__pycache__/file_cache.cpython-36.pyc | Bin 0 -> 3254 bytes .../__pycache__/redis_cache.cpython-36.pyc | Bin 0 -> 1588 bytes .../cachecontrol/caches/file_cache.py | 146 + .../cachecontrol/caches/redis_cache.py | 33 + venv/Lib/site-packages/cachecontrol/compat.py | 29 + .../site-packages/cachecontrol/controller.py | 376 + .../site-packages/cachecontrol/filewrapper.py | 80 + .../site-packages/cachecontrol/heuristics.py | 135 + .../site-packages/cachecontrol/serialize.py | 188 + .../Lib/site-packages/cachecontrol/wrapper.py | 29 + .../cachetools-4.1.1.dist-info/INSTALLER | 1 + .../cachetools-4.1.1.dist-info/LICENSE | 20 + .../cachetools-4.1.1.dist-info/METADATA | 124 + .../cachetools-4.1.1.dist-info/RECORD | 26 + .../cachetools-4.1.1.dist-info/WHEEL | 5 + .../cachetools-4.1.1.dist-info/top_level.txt | 1 + venv/Lib/site-packages/cachetools/__init__.py | 20 + .../__pycache__/__init__.cpython-36.pyc | Bin 0 -> 676 bytes .../cachetools/__pycache__/abc.cpython-36.pyc | Bin 0 -> 1477 bytes .../__pycache__/cache.cpython-36.pyc | Bin 0 -> 3324 bytes .../__pycache__/decorators.cpython-36.pyc | Bin 0 -> 2505 bytes .../__pycache__/func.cpython-36.pyc | Bin 0 -> 4707 bytes .../__pycache__/keys.cpython-36.pyc | Bin 0 -> 2124 bytes .../cachetools/__pycache__/lfu.cpython-36.pyc | Bin 0 -> 1644 bytes .../cachetools/__pycache__/lru.cpython-36.pyc | Bin 0 -> 1814 bytes .../cachetools/__pycache__/rr.cpython-36.pyc | Bin 0 -> 1349 bytes .../cachetools/__pycache__/ttl.cpython-36.pyc | Bin 0 -> 7054 bytes venv/Lib/site-packages/cachetools/abc.py | 46 + venv/Lib/site-packages/cachetools/cache.py | 89 + .../site-packages/cachetools/decorators.py | 88 + venv/Lib/site-packages/cachetools/func.py | 147 + venv/Lib/site-packages/cachetools/keys.py | 52 + venv/Lib/site-packages/cachetools/lfu.py | 34 + venv/Lib/site-packages/cachetools/lru.py | 40 + venv/Lib/site-packages/cachetools/rr.py | 35 + venv/Lib/site-packages/cachetools/ttl.py | 209 + .../certifi-2020.6.20.dist-info/INSTALLER | 1 + .../certifi-2020.6.20.dist-info/LICENSE | 21 + .../certifi-2020.6.20.dist-info/METADATA | 82 + .../certifi-2020.6.20.dist-info/RECORD | 13 + .../certifi-2020.6.20.dist-info/WHEEL | 6 + .../certifi-2020.6.20.dist-info/top_level.txt | 1 + venv/Lib/site-packages/certifi/__init__.py | 3 + venv/Lib/site-packages/certifi/__main__.py | 12 + .../__pycache__/__init__.cpython-36.pyc | Bin 0 -> 326 bytes .../__pycache__/__main__.cpython-36.pyc | Bin 0 -> 491 bytes .../certifi/__pycache__/core.cpython-36.pyc | Bin 0 -> 1195 bytes venv/Lib/site-packages/certifi/cacert.pem | 4620 +++++++++ venv/Lib/site-packages/certifi/core.py | 60 + .../cffi-1.14.3.dist-info/INSTALLER | 1 + .../cffi-1.14.3.dist-info/LICENSE | 26 + .../cffi-1.14.3.dist-info/METADATA | 37 + .../cffi-1.14.3.dist-info/RECORD | 44 + .../site-packages/cffi-1.14.3.dist-info/WHEEL | 5 + .../cffi-1.14.3.dist-info/entry_points.txt | 3 + .../cffi-1.14.3.dist-info/top_level.txt | 2 + venv/Lib/site-packages/cffi/__init__.py | 14 + .../cffi/__pycache__/__init__.cpython-36.pyc | Bin 0 -> 596 bytes .../cffi/__pycache__/api.cpython-36.pyc | Bin 0 -> 34009 bytes .../__pycache__/backend_ctypes.cpython-36.pyc | Bin 0 -> 40053 bytes .../__pycache__/cffi_opcode.cpython-36.pyc | Bin 0 -> 4847 bytes .../__pycache__/commontypes.cpython-36.pyc | Bin 0 -> 1983 bytes .../cffi/__pycache__/cparser.cpython-36.pyc | Bin 0 -> 23673 bytes .../cffi/__pycache__/error.cpython-36.pyc | Bin 0 -> 1593 bytes .../__pycache__/ffiplatform.cpython-36.pyc | Bin 0 -> 3562 bytes .../cffi/__pycache__/lock.cpython-36.pyc | Bin 0 -> 487 bytes .../cffi/__pycache__/model.cpython-36.pyc | Bin 0 -> 19788 bytes .../cffi/__pycache__/pkgconfig.cpython-36.pyc | Bin 0 -> 5269 bytes .../__pycache__/recompiler.cpython-36.pyc | Bin 0 -> 46983 bytes .../__pycache__/setuptools_ext.cpython-36.pyc | Bin 0 -> 7403 bytes .../__pycache__/vengine_cpy.cpython-36.pyc | Bin 0 -> 35691 bytes .../__pycache__/vengine_gen.cpython-36.pyc | Bin 0 -> 21170 bytes .../cffi/__pycache__/verifier.cpython-36.pyc | Bin 0 -> 9187 bytes venv/Lib/site-packages/cffi/_cffi_errors.h | 147 + venv/Lib/site-packages/cffi/_cffi_include.h | 385 + venv/Lib/site-packages/cffi/_embedding.h | 527 ++ venv/Lib/site-packages/cffi/api.py | 965 ++ venv/Lib/site-packages/cffi/backend_ctypes.py | 1121 +++ venv/Lib/site-packages/cffi/cffi_opcode.py | 187 + venv/Lib/site-packages/cffi/commontypes.py | 80 + venv/Lib/site-packages/cffi/cparser.py | 1006 ++ venv/Lib/site-packages/cffi/error.py | 31 + venv/Lib/site-packages/cffi/ffiplatform.py | 127 + venv/Lib/site-packages/cffi/lock.py | 30 + venv/Lib/site-packages/cffi/model.py | 617 ++ venv/Lib/site-packages/cffi/parse_c_type.h | 181 + venv/Lib/site-packages/cffi/pkgconfig.py | 121 + venv/Lib/site-packages/cffi/recompiler.py | 1571 ++++ venv/Lib/site-packages/cffi/setuptools_ext.py | 219 + venv/Lib/site-packages/cffi/vengine_cpy.py | 1076 +++ venv/Lib/site-packages/cffi/vengine_gen.py | 675 ++ venv/Lib/site-packages/cffi/verifier.py | 306 + .../chardet-3.0.4.dist-info/DESCRIPTION.rst | 70 + .../chardet-3.0.4.dist-info/INSTALLER | 1 + .../chardet-3.0.4.dist-info/METADATA | 96 + .../chardet-3.0.4.dist-info/RECORD | 91 + .../chardet-3.0.4.dist-info/WHEEL | 6 + .../chardet-3.0.4.dist-info/entry_points.txt | 3 + .../chardet-3.0.4.dist-info/metadata.json | 1 + .../chardet-3.0.4.dist-info/top_level.txt | 1 + .../packages => }/chardet/__init__.py | 31 +- .../__pycache__/__init__.cpython-36.pyc | Bin 0 -> 894 bytes .../__pycache__/big5freq.cpython-36.pyc | Bin 0 -> 54781 bytes .../__pycache__/big5prober.cpython-36.pyc | Bin 0 -> 1170 bytes .../chardistribution.cpython-36.pyc | Bin 0 -> 6366 bytes .../charsetgroupprober.cpython-36.pyc | Bin 0 -> 2277 bytes .../__pycache__/charsetprober.cpython-36.pyc | Bin 0 -> 3503 bytes .../codingstatemachine.cpython-36.pyc | Bin 0 -> 2934 bytes .../chardet/__pycache__/compat.cpython-36.pyc | Bin 0 -> 410 bytes .../__pycache__/cp949prober.cpython-36.pyc | Bin 0 -> 1177 bytes .../chardet/__pycache__/enums.cpython-36.pyc | Bin 0 -> 2668 bytes .../__pycache__/escprober.cpython-36.pyc | Bin 0 -> 2659 bytes .../chardet/__pycache__/escsm.cpython-36.pyc | Bin 0 -> 7416 bytes .../__pycache__/eucjpprober.cpython-36.pyc | Bin 0 -> 2463 bytes .../__pycache__/euckrfreq.cpython-36.pyc | Bin 0 -> 24167 bytes .../__pycache__/euckrprober.cpython-36.pyc | Bin 0 -> 1178 bytes .../__pycache__/euctwfreq.cpython-36.pyc | Bin 61279 -> 54790 bytes .../__pycache__/euctwprober.cpython-36.pyc | Bin 0 -> 1178 bytes .../__pycache__/gb2312freq.cpython-36.pyc | Bin 68897 -> 38432 bytes .../__pycache__/gb2312prober.cpython-36.pyc | Bin 0 -> 1186 bytes .../__pycache__/hebrewprober.cpython-36.pyc | Bin 0 -> 3020 bytes .../__pycache__/jisfreq.cpython-36.pyc | Bin 84113 -> 44576 bytes .../chardet/__pycache__/jpcntx.cpython-36.pyc | Bin 0 -> 38715 bytes .../langbulgarianmodel.cpython-36.pyc | Bin 24900 -> 24930 bytes .../langcyrillicmodel.cpython-36.pyc | Bin 30430 -> 30481 bytes .../__pycache__/langgreekmodel.cpython-36.pyc | Bin 24587 -> 24608 bytes .../langhebrewmodel.cpython-36.pyc | Bin 23445 -> 23462 bytes .../langhungarianmodel.cpython-36.pyc | Bin 24885 -> 24904 bytes .../__pycache__/langthaimodel.cpython-36.pyc | Bin 23431 -> 23441 bytes .../langturkishmodel.cpython-36.pyc | Bin 0 -> 23459 bytes .../__pycache__/latin1prober.cpython-36.pyc | Bin 0 -> 2991 bytes .../mbcharsetprober.cpython-36.pyc | Bin 0 -> 2282 bytes .../mbcsgroupprober.cpython-36.pyc | Bin 0 -> 1173 bytes .../chardet/__pycache__/mbcssm.cpython-36.pyc | Bin 0 -> 17626 bytes .../sbcharsetprober.cpython-36.pyc | Bin 0 -> 3035 bytes .../sbcsgroupprober.cpython-36.pyc | Bin 0 -> 1663 bytes .../__pycache__/sjisprober.cpython-36.pyc | Bin 0 -> 2489 bytes .../universaldetector.cpython-36.pyc | Bin 0 -> 5884 bytes .../__pycache__/utf8prober.cpython-36.pyc | Bin 0 -> 2020 bytes .../__pycache__/version.cpython-36.pyc | Bin 0 -> 489 bytes venv/Lib/site-packages/chardet/big5freq.py | 386 + .../packages => }/chardet/big5prober.py | 15 +- .../packages => }/chardet/chardistribution.py | 148 +- .../chardet/charsetgroupprober.py | 106 + .../site-packages/chardet/charsetprober.py | 145 + .../Lib/site-packages/chardet/cli/__init__.py | 1 + .../cli/__pycache__/__init__.cpython-36.pyc | Bin 0 -> 246 bytes .../cli/__pycache__/chardetect.cpython-36.pyc | Bin 0 -> 3134 bytes .../chardet => chardet/cli}/chardetect.py | 21 +- .../chardet/codingstatemachine.py | 88 + .../{requests/packages => }/chardet/compat.py | 16 +- .../packages => }/chardet/cp949prober.py | 19 +- venv/Lib/site-packages/chardet/enums.py | 76 + venv/Lib/site-packages/chardet/escprober.py | 101 + venv/Lib/site-packages/chardet/escsm.py | 246 + venv/Lib/site-packages/chardet/eucjpprober.py | 92 + venv/Lib/site-packages/chardet/euckrfreq.py | 195 + .../packages => }/chardet/euckrprober.py | 15 +- .../packages => }/chardet/euctwfreq.py | 719 +- .../packages => }/chardet/euctwprober.py | 19 +- .../packages => }/chardet/gb2312freq.py | 195 +- .../packages => }/chardet/gb2312prober.py | 19 +- .../packages => }/chardet/hebrewprober.py | 163 +- .../packages => }/chardet/jisfreq.py | 250 +- .../{requests/packages => }/chardet/jpcntx.py | 124 +- .../chardet/langbulgarianmodel.py | 25 +- .../chardet/langcyrillicmodel.py | 82 +- .../packages => }/chardet/langgreekmodel.py | 28 +- .../packages => }/chardet/langhebrewmodel.py | 17 +- .../chardet/langhungarianmodel.py | 24 +- .../packages => }/chardet/langthaimodel.py | 13 +- .../site-packages/chardet/langturkishmodel.py | 193 + .../packages => }/chardet/latin1prober.py | 48 +- .../site-packages/chardet/mbcharsetprober.py | 91 + .../packages => }/chardet/mbcsgroupprober.py | 6 +- venv/Lib/site-packages/chardet/mbcssm.py | 572 ++ .../site-packages/chardet/sbcharsetprober.py | 132 + .../packages => }/chardet/sbcsgroupprober.py | 30 +- venv/Lib/site-packages/chardet/sjisprober.py | 92 + .../chardet/universaldetector.py | 286 + .../packages => }/chardet/utf8prober.py | 62 +- venv/Lib/site-packages/chardet/version.py | 9 + .../firebase_admin-4.4.0.dist-info/INSTALLER | 1 + .../firebase_admin-4.4.0.dist-info/LICENSE | 201 + .../firebase_admin-4.4.0.dist-info/METADATA | 27 + .../firebase_admin-4.4.0.dist-info/RECORD | 59 + .../REQUESTED} | 0 .../firebase_admin-4.4.0.dist-info/WHEEL | 5 + .../top_level.txt | 1 + .../site-packages/firebase_admin/__about__.py | 21 + .../site-packages/firebase_admin/__init__.py | 309 + .../__pycache__/__about__.cpython-36.pyc | Bin 0 -> 506 bytes .../__pycache__/__init__.cpython-36.pyc | Bin 0 -> 10913 bytes .../__pycache__/_auth_client.cpython-36.pyc | Bin 0 -> 32567 bytes .../_auth_providers.cpython-36.pyc | Bin 0 -> 15188 bytes .../__pycache__/_auth_utils.cpython-36.pyc | Bin 0 -> 15541 bytes .../__pycache__/_http_client.cpython-36.pyc | Bin 0 -> 5407 bytes .../_messaging_encoder.cpython-36.pyc | Bin 0 -> 23995 bytes .../_messaging_utils.cpython-36.pyc | Bin 0 -> 24189 bytes .../__pycache__/_rfc3339.cpython-36.pyc | Bin 0 -> 2104 bytes .../__pycache__/_sseclient.cpython-36.pyc | Bin 0 -> 5930 bytes .../__pycache__/_token_gen.cpython-36.pyc | Bin 0 -> 14119 bytes .../_user_identifier.cpython-36.pyc | Bin 0 -> 3443 bytes .../__pycache__/_user_import.cpython-36.pyc | Bin 0 -> 18290 bytes .../__pycache__/_user_mgt.cpython-36.pyc | Bin 0 -> 30671 bytes .../__pycache__/_utils.cpython-36.pyc | Bin 0 -> 10698 bytes .../__pycache__/auth.cpython-36.pyc | Bin 0 -> 32345 bytes .../__pycache__/credentials.cpython-36.pyc | Bin 0 -> 8112 bytes .../__pycache__/db.cpython-36.pyc | Bin 0 -> 37896 bytes .../__pycache__/exceptions.cpython-36.pyc | Bin 0 -> 9622 bytes .../__pycache__/firestore.cpython-36.pyc | Bin 0 -> 2616 bytes .../__pycache__/instance_id.cpython-36.pyc | Bin 0 -> 3506 bytes .../__pycache__/messaging.cpython-36.pyc | Bin 0 -> 16873 bytes .../__pycache__/ml.cpython-36.pyc | Bin 0 -> 34347 bytes .../project_management.cpython-36.pyc | Bin 0 -> 24530 bytes .../__pycache__/storage.cpython-36.pyc | Bin 0 -> 2874 bytes .../__pycache__/tenant_mgt.cpython-36.pyc | Bin 0 -> 15522 bytes .../firebase_admin/_auth_client.py | 703 ++ .../firebase_admin/_auth_providers.py | 390 + .../firebase_admin/_auth_utils.py | 422 + .../firebase_admin/_http_client.py | 148 + .../firebase_admin/_messaging_encoder.py | 696 ++ .../firebase_admin/_messaging_utils.py | 494 + .../site-packages/firebase_admin/_rfc3339.py | 87 + .../firebase_admin/_sseclient.py | 208 + .../firebase_admin/_token_gen.py | 401 + .../firebase_admin/_user_identifier.py | 103 + .../firebase_admin/_user_import.py | 520 + .../site-packages/firebase_admin/_user_mgt.py | 846 ++ .../site-packages/firebase_admin/_utils.py | 341 + venv/Lib/site-packages/firebase_admin/auth.py | 883 ++ .../firebase_admin/credentials.py | 214 + venv/Lib/site-packages/firebase_admin/db.py | 991 ++ .../firebase_admin/exceptions.py | 237 + .../site-packages/firebase_admin/firestore.py | 76 + .../firebase_admin/instance_id.py | 99 + .../site-packages/firebase_admin/messaging.py | 495 + venv/Lib/site-packages/firebase_admin/ml.py | 983 ++ .../firebase_admin/project_management.py | 664 ++ .../site-packages/firebase_admin/storage.py | 82 + .../firebase_admin/tenant_mgt.py | 445 + .../google/_async_resumable_media/__init__.py | 61 + .../__pycache__/__init__.cpython-36.pyc | Bin 0 -> 1255 bytes .../__pycache__/_download.cpython-36.pyc | Bin 0 -> 18490 bytes .../__pycache__/_helpers.cpython-36.pyc | Bin 0 -> 6003 bytes .../__pycache__/_upload.cpython-36.pyc | Bin 0 -> 33053 bytes .../_async_resumable_media/_download.py | 553 ++ .../google/_async_resumable_media/_helpers.py | 198 + .../google/_async_resumable_media/_upload.py | 979 ++ .../requests/__init__.py | 678 ++ .../__pycache__/__init__.cpython-36.pyc | Bin 0 -> 21110 bytes .../_request_helpers.cpython-36.pyc | Bin 0 -> 4329 bytes .../__pycache__/download.cpython-36.pyc | Bin 0 -> 16289 bytes .../__pycache__/upload.cpython-36.pyc | Bin 0 -> 18075 bytes .../requests/_request_helpers.py | 155 + .../requests/download.py | 461 + .../_async_resumable_media/requests/upload.py | 515 + .../site-packages/google/api_core/__init__.py | 22 + .../__pycache__/__init__.cpython-36.pyc | Bin 0 -> 451 bytes .../api_core/__pycache__/bidi.cpython-36.pyc | Bin 0 -> 21484 bytes .../__pycache__/client_info.cpython-36.pyc | Bin 0 -> 2861 bytes .../__pycache__/client_options.cpython-36.pyc | Bin 0 -> 3651 bytes .../datetime_helpers.cpython-36.pyc | Bin 0 -> 8065 bytes .../__pycache__/exceptions.cpython-36.pyc | Bin 0 -> 16234 bytes .../general_helpers.cpython-36.pyc | Bin 0 -> 657 bytes .../__pycache__/grpc_helpers.cpython-36.pyc | Bin 0 -> 14356 bytes .../grpc_helpers_async.cpython-36.pyc | Bin 0 -> 10684 bytes .../api_core/__pycache__/iam.cpython-36.pyc | Bin 0 -> 13221 bytes .../__pycache__/operation.cpython-36.pyc | Bin 0 -> 10647 bytes .../operation_async.cpython-36.pyc | Bin 0 -> 6646 bytes .../__pycache__/page_iterator.cpython-36.pyc | Bin 0 -> 17659 bytes .../page_iterator_async.cpython-36.pyc | Bin 0 -> 8682 bytes .../__pycache__/path_template.cpython-36.pyc | Bin 0 -> 5211 bytes .../protobuf_helpers.cpython-36.pyc | Bin 0 -> 9215 bytes .../api_core/__pycache__/retry.cpython-36.pyc | Bin 0 -> 10332 bytes .../__pycache__/retry_async.cpython-36.pyc | Bin 0 -> 8810 bytes .../__pycache__/timeout.cpython-36.pyc | Bin 0 -> 7007 bytes .../__pycache__/version.cpython-36.pyc | Bin 0 -> 271 bytes .../Lib/site-packages/google/api_core/bidi.py | 735 ++ .../google/api_core/client_info.py | 98 + .../google/api_core/client_options.py | 116 + .../google/api_core/datetime_helpers.py | 296 + .../google/api_core/exceptions.py | 474 + .../google/api_core/future/__init__.py | 19 + .../__pycache__/__init__.cpython-36.pyc | Bin 0 -> 403 bytes .../__pycache__/_helpers.cpython-36.pyc | Bin 0 -> 919 bytes .../__pycache__/async_future.cpython-36.pyc | Bin 0 -> 5457 bytes .../future/__pycache__/base.cpython-36.pyc | Bin 0 -> 1892 bytes .../future/__pycache__/polling.cpython-36.pyc | Bin 0 -> 5886 bytes .../google/api_core/future/_helpers.py | 39 + .../google/api_core/future/async_future.py | 157 + .../google/api_core/future/base.py | 67 + .../google/api_core/future/polling.py | 186 + .../google/api_core/gapic_v1/__init__.py | 28 + .../__pycache__/__init__.cpython-36.pyc | Bin 0 -> 632 bytes .../__pycache__/client_info.cpython-36.pyc | Bin 0 -> 2086 bytes .../__pycache__/config.cpython-36.pyc | Bin 0 -> 5113 bytes .../__pycache__/config_async.cpython-36.pyc | Bin 0 -> 1466 bytes .../__pycache__/method.cpython-36.pyc | Bin 0 -> 7464 bytes .../__pycache__/method_async.cpython-36.pyc | Bin 0 -> 1341 bytes .../__pycache__/routing_header.cpython-36.pyc | Bin 0 -> 1561 bytes .../google/api_core/gapic_v1/client_info.py | 55 + .../google/api_core/gapic_v1/config.py | 169 + .../google/api_core/gapic_v1/config_async.py | 42 + .../google/api_core/gapic_v1/method.py | 244 + .../google/api_core/gapic_v1/method_async.py | 45 + .../api_core/gapic_v1/routing_header.py | 62 + .../google/api_core/general_helpers.py | 33 + .../google/api_core/grpc_helpers.py | 466 + .../google/api_core/grpc_helpers_async.py | 289 + venv/Lib/site-packages/google/api_core/iam.py | 460 + .../google/api_core/operation.py | 327 + .../google/api_core/operation_async.py | 215 + .../google/api_core/operations_v1/__init__.py | 24 + .../__pycache__/__init__.cpython-36.pyc | Bin 0 -> 655 bytes .../operations_async_client.cpython-36.pyc | Bin 0 -> 10932 bytes .../operations_client.cpython-36.pyc | Bin 0 -> 11492 bytes .../operations_client_config.cpython-36.pyc | Bin 0 -> 996 bytes .../operations_v1/operations_async_client.py | 274 + .../operations_v1/operations_client.py | 288 + .../operations_v1/operations_client_config.py | 59 + .../google/api_core/page_iterator.py | 557 ++ .../google/api_core/page_iterator_async.py | 278 + .../google/api_core/path_template.py | 197 + .../google/api_core/protobuf_helpers.py | 370 + .../site-packages/google/api_core/retry.py | 364 + .../google/api_core/retry_async.py | 282 + .../site-packages/google/api_core/timeout.py | 224 + .../site-packages/google/api_core/version.py | 15 + .../Lib/site-packages/google/auth/__init__.py | 24 + .../auth/__pycache__/__init__.cpython-36.pyc | Bin 0 -> 499 bytes .../__pycache__/_cloud_sdk.cpython-36.pyc | Bin 0 -> 3379 bytes .../_credentials_async.cpython-36.pyc | Bin 0 -> 6889 bytes .../auth/__pycache__/_default.cpython-36.pyc | Bin 0 -> 10582 bytes .../__pycache__/_default_async.cpython-36.pyc | Bin 0 -> 8065 bytes .../auth/__pycache__/_helpers.cpython-36.pyc | Bin 0 -> 6501 bytes .../__pycache__/_jwt_async.cpython-36.pyc | Bin 0 -> 5869 bytes .../__pycache__/_oauth2client.cpython-36.pyc | Bin 0 -> 5068 bytes .../_service_account_info.cpython-36.pyc | Bin 0 -> 2070 bytes .../__pycache__/app_engine.cpython-36.pyc | Bin 0 -> 5072 bytes .../__pycache__/credentials.cpython-36.pyc | Bin 0 -> 12786 bytes .../environment_vars.cpython-36.pyc | Bin 0 -> 622 bytes .../__pycache__/exceptions.cpython-36.pyc | Bin 0 -> 1883 bytes .../auth/__pycache__/iam.cpython-36.pyc | Bin 0 -> 3408 bytes .../impersonated_credentials.cpython-36.pyc | Bin 0 -> 12247 bytes .../auth/__pycache__/jwt.cpython-36.pyc | Bin 0 -> 25163 bytes .../site-packages/google/auth/_cloud_sdk.py | 152 + .../google/auth/_credentials_async.py | 176 + .../Lib/site-packages/google/auth/_default.py | 354 + .../google/auth/_default_async.py | 266 + .../Lib/site-packages/google/auth/_helpers.py | 232 + .../site-packages/google/auth/_jwt_async.py | 168 + .../google/auth/_oauth2client.py | 169 + .../google/auth/_service_account_info.py | 74 + .../site-packages/google/auth/app_engine.py | 170 + .../google/auth/compute_engine/__init__.py | 21 + .../__pycache__/__init__.cpython-36.pyc | Bin 0 -> 459 bytes .../__pycache__/_metadata.cpython-36.pyc | Bin 0 -> 6689 bytes .../__pycache__/credentials.cpython-36.pyc | Bin 0 -> 12189 bytes .../google/auth/compute_engine/_metadata.py | 257 + .../google/auth/compute_engine/credentials.py | 392 + .../site-packages/google/auth/credentials.py | 351 + .../google/auth/crypt/__init__.py | 100 + .../crypt/__pycache__/__init__.cpython-36.pyc | Bin 0 -> 2596 bytes .../_cryptography_rsa.cpython-36.pyc | Bin 0 -> 4887 bytes .../crypt/__pycache__/_helpers.cpython-36.pyc | Bin 0 -> 252 bytes .../__pycache__/_python_rsa.cpython-36.pyc | Bin 0 -> 5772 bytes .../crypt/__pycache__/base.cpython-36.pyc | Bin 0 -> 4186 bytes .../crypt/__pycache__/es256.cpython-36.pyc | Bin 0 -> 5236 bytes .../auth/crypt/__pycache__/rsa.cpython-36.pyc | Bin 0 -> 493 bytes .../google/auth/crypt/_cryptography_rsa.py | 149 + .../google/auth/crypt/_helpers.py | 0 .../google/auth/crypt/_python_rsa.py | 173 + .../site-packages/google/auth/crypt/base.py | 131 + .../site-packages/google/auth/crypt/es256.py | 160 + .../site-packages/google/auth/crypt/rsa.py | 30 + .../google/auth/environment_vars.py | 61 + .../site-packages/google/auth/exceptions.py | 45 + venv/Lib/site-packages/google/auth/iam.py | 100 + .../google/auth/impersonated_credentials.py | 398 + venv/Lib/site-packages/google/auth/jwt.py | 844 ++ .../google/auth/transport/__init__.py | 97 + .../__pycache__/__init__.cpython-36.pyc | Bin 0 -> 3208 bytes .../_aiohttp_requests.cpython-36.pyc | Bin 0 -> 11381 bytes .../__pycache__/_http_client.cpython-36.pyc | Bin 0 -> 3490 bytes .../__pycache__/_mtls_helper.cpython-36.pyc | Bin 0 -> 7319 bytes .../transport/__pycache__/grpc.cpython-36.pyc | Bin 0 -> 11850 bytes .../transport/__pycache__/mtls.cpython-36.pyc | Bin 0 -> 3381 bytes .../__pycache__/requests.cpython-36.pyc | Bin 0 -> 15698 bytes .../__pycache__/urllib3.cpython-36.pyc | Bin 0 -> 12598 bytes .../auth/transport/_aiohttp_requests.py | 384 + .../google/auth/transport/_http_client.py | 115 + .../google/auth/transport/_mtls_helper.py | 250 + .../google/auth/transport/grpc.py | 334 + .../google/auth/transport/mtls.py | 105 + .../google/auth/transport/requests.py | 521 + .../google/auth/transport/urllib3.py | 426 + .../cloud/__pycache__/_helpers.cpython-36.pyc | Bin 0 -> 19427 bytes .../cloud/__pycache__/_http.cpython-36.pyc | Bin 0 -> 12897 bytes .../cloud/__pycache__/_testing.cpython-36.pyc | Bin 0 -> 4579 bytes .../cloud/__pycache__/client.cpython-36.pyc | Bin 0 -> 8796 bytes .../environment_vars.cpython-36.pyc | Bin 0 -> 631 bytes .../__pycache__/exceptions.cpython-36.pyc | Bin 0 -> 1166 bytes .../__pycache__/firestore.cpython-36.pyc | Bin 0 -> 1385 bytes .../cloud/__pycache__/obsolete.cpython-36.pyc | Bin 0 -> 1005 bytes .../__pycache__/operation.cpython-36.pyc | Bin 0 -> 8094 bytes .../cloud/__pycache__/version.cpython-36.pyc | Bin 0 -> 267 bytes .../site-packages/google/cloud/_helpers.py | 636 ++ venv/Lib/site-packages/google/cloud/_http.py | 440 + .../site-packages/google/cloud/_testing.py | 126 + venv/Lib/site-packages/google/cloud/client.py | 250 + .../google/cloud/environment_vars.py | 38 + .../site-packages/google/cloud/exceptions.py | 59 + .../site-packages/google/cloud/firestore.py | 69 + .../cloud/firestore_admin_v1/__init__.py | 45 + .../__pycache__/__init__.cpython-36.pyc | Bin 0 -> 1093 bytes .../__pycache__/types.cpython-36.pyc | Bin 0 -> 1284 bytes .../firestore_admin_v1/gapic/__init__.py | 0 .../gapic/__pycache__/__init__.cpython-36.pyc | Bin 0 -> 272 bytes .../gapic/__pycache__/enums.cpython-36.pyc | Bin 0 -> 6263 bytes .../firestore_admin_client.cpython-36.pyc | Bin 0 -> 35944 bytes ...restore_admin_client_config.cpython-36.pyc | Bin 0 -> 1111 bytes .../cloud/firestore_admin_v1/gapic/enums.py | 142 + .../gapic/firestore_admin_client.py | 1089 +++ .../gapic/firestore_admin_client_config.py | 69 + .../gapic/transports/__init__.py | 0 .../__pycache__/__init__.cpython-36.pyc | Bin 0 -> 283 bytes ...estore_admin_grpc_transport.cpython-36.pyc | Bin 0 -> 9968 bytes .../firestore_admin_grpc_transport.py | 269 + .../firestore_admin_v1/proto/__init__.py | 0 .../proto/__pycache__/__init__.cpython-36.pyc | Bin 0 -> 272 bytes .../__pycache__/field_pb2.cpython-36.pyc | Bin 0 -> 7542 bytes .../__pycache__/field_pb2_grpc.cpython-36.pyc | Bin 0 -> 380 bytes .../firestore_admin_pb2.cpython-36.pyc | Bin 0 -> 21663 bytes .../firestore_admin_pb2_grpc.cpython-36.pyc | Bin 0 -> 12313 bytes .../__pycache__/index_pb2.cpython-36.pyc | Bin 0 -> 8717 bytes .../__pycache__/index_pb2_grpc.cpython-36.pyc | Bin 0 -> 380 bytes .../__pycache__/location_pb2.cpython-36.pyc | Bin 0 -> 2390 bytes .../location_pb2_grpc.cpython-36.pyc | Bin 0 -> 383 bytes .../__pycache__/operation_pb2.cpython-36.pyc | Bin 0 -> 16967 bytes .../operation_pb2_grpc.cpython-36.pyc | Bin 0 -> 384 bytes .../firestore_admin_v1/proto/field.proto | 100 + .../firestore_admin_v1/proto/field_pb2.py | 285 + .../proto/field_pb2_grpc.py | 3 + .../proto/firestore_admin.proto | 355 + .../proto/firestore_admin_pb2.py | 1188 +++ .../proto/firestore_admin_pb2_grpc.py | 478 + .../firestore_admin_v1/proto/index.proto | 158 + .../firestore_admin_v1/proto/index_pb2.py | 473 + .../proto/index_pb2_grpc.py | 3 + .../firestore_admin_v1/proto/location.proto | 35 + .../firestore_admin_v1/proto/location_pb2.py | 71 + .../proto/location_pb2_grpc.py | 3 + .../firestore_admin_v1/proto/operation.proto | 204 + .../firestore_admin_v1/proto/operation_pb2.py | 1185 +++ .../proto/operation_pb2_grpc.py | 3 + .../google/cloud/firestore_admin_v1/types.py | 66 + .../google/cloud/firestore_v1/__init__.py | 71 + .../__pycache__/__init__.cpython-36.pyc | Bin 0 -> 1828 bytes .../__pycache__/_helpers.cpython-36.pyc | Bin 0 -> 31627 bytes .../__pycache__/batch.cpython-36.pyc | Bin 0 -> 6080 bytes .../__pycache__/client.cpython-36.pyc | Bin 0 -> 19819 bytes .../__pycache__/collection.cpython-36.pyc | Bin 0 -> 18939 bytes .../__pycache__/document.cpython-36.pyc | Bin 0 -> 26083 bytes .../__pycache__/field_path.cpython-36.pyc | Bin 0 -> 11134 bytes .../__pycache__/order.cpython-36.pyc | Bin 0 -> 4760 bytes .../__pycache__/query.cpython-36.pyc | Bin 0 -> 36277 bytes .../__pycache__/transaction.cpython-36.pyc | Bin 0 -> 14155 bytes .../__pycache__/transforms.cpython-36.pyc | Bin 0 -> 5492 bytes .../__pycache__/types.cpython-36.pyc | Bin 0 -> 1363 bytes .../__pycache__/watch.cpython-36.pyc | Bin 0 -> 18551 bytes .../google/cloud/firestore_v1/_helpers.py | 1049 +++ .../google/cloud/firestore_v1/batch.py | 160 + .../google/cloud/firestore_v1/client.py | 622 ++ .../google/cloud/firestore_v1/collection.py | 509 + .../google/cloud/firestore_v1/document.py | 787 ++ .../google/cloud/firestore_v1/field_path.py | 395 + .../cloud/firestore_v1/gapic/__init__.py | 0 .../gapic/__pycache__/__init__.cpython-36.pyc | Bin 0 -> 266 bytes .../gapic/__pycache__/enums.cpython-36.pyc | Bin 0 -> 7197 bytes .../firestore_client.cpython-36.pyc | Bin 0 -> 56068 bytes .../firestore_client_config.cpython-36.pyc | Bin 0 -> 1365 bytes .../google/cloud/firestore_v1/gapic/enums.py | 180 + .../firestore_v1/gapic/firestore_client.py | 1673 ++++ .../gapic/firestore_client_config.py | 109 + .../firestore_v1/gapic/transports/__init__.py | 0 .../__pycache__/__init__.cpython-36.pyc | Bin 0 -> 277 bytes .../firestore_grpc_transport.cpython-36.pyc | Bin 0 -> 11109 bytes .../transports/firestore_grpc_transport.py | 319 + .../google/cloud/firestore_v1/order.py | 207 + .../cloud/firestore_v1/proto/__init__.py | 0 .../proto/__pycache__/__init__.cpython-36.pyc | Bin 0 -> 266 bytes .../__pycache__/common_pb2.cpython-36.pyc | Bin 0 -> 7306 bytes .../common_pb2_grpc.cpython-36.pyc | Bin 0 -> 375 bytes .../__pycache__/document_pb2.cpython-36.pyc | Bin 0 -> 12327 bytes .../document_pb2_grpc.cpython-36.pyc | Bin 0 -> 377 bytes .../__pycache__/firestore_pb2.cpython-36.pyc | Bin 0 -> 66605 bytes .../firestore_pb2_grpc.cpython-36.pyc | Bin 0 -> 16057 bytes .../__pycache__/query_pb2.cpython-36.pyc | Bin 0 -> 16916 bytes .../__pycache__/query_pb2_grpc.cpython-36.pyc | Bin 0 -> 374 bytes .../__pycache__/test_v1_pb2.cpython-36.pyc | Bin 0 -> 19249 bytes .../__pycache__/tests_pb2.cpython-36.pyc | Bin 0 -> 22382 bytes .../__pycache__/write_pb2.cpython-36.pyc | Bin 0 -> 20543 bytes .../__pycache__/write_pb2_grpc.cpython-36.pyc | Bin 0 -> 374 bytes .../cloud/firestore_v1/proto/common.proto | 83 + .../cloud/firestore_v1/proto/common_pb2.py | 456 + .../firestore_v1/proto/common_pb2_grpc.py | 3 + .../cloud/firestore_v1/proto/document.proto | 150 + .../cloud/firestore_v1/proto/document_pb2.py | 815 ++ .../firestore_v1/proto/document_pb2_grpc.py | 3 + .../cloud/firestore_v1/proto/firestore.proto | 896 ++ .../cloud/firestore_v1/proto/firestore_pb2.py | 4500 +++++++++ .../firestore_v1/proto/firestore_pb2_grpc.py | 743 ++ .../cloud/firestore_v1/proto/query.proto | 267 + .../cloud/firestore_v1/proto/query_pb2.py | 1280 +++ .../firestore_v1/proto/query_pb2_grpc.py | 3 + .../cloud/firestore_v1/proto/test_v1_pb2.py | 2190 +++++ .../cloud/firestore_v1/proto/tests_pb2.py | 2208 +++++ .../cloud/firestore_v1/proto/write.proto | 258 + .../cloud/firestore_v1/proto/write_pb2.py | 1193 +++ .../firestore_v1/proto/write_pb2_grpc.py | 3 + .../google/cloud/firestore_v1/query.py | 1129 +++ .../google/cloud/firestore_v1/transaction.py | 442 + .../google/cloud/firestore_v1/transforms.py | 151 + .../google/cloud/firestore_v1/types.py | 63 + .../google/cloud/firestore_v1/watch.py | 743 ++ .../cloud/firestore_v1beta1/__init__.py | 73 + .../__pycache__/__init__.cpython-36.pyc | Bin 0 -> 1981 bytes .../__pycache__/_helpers.cpython-36.pyc | Bin 0 -> 30722 bytes .../__pycache__/batch.cpython-36.pyc | Bin 0 -> 6021 bytes .../__pycache__/client.cpython-36.pyc | Bin 0 -> 17509 bytes .../__pycache__/collection.cpython-36.pyc | Bin 0 -> 17475 bytes .../__pycache__/document.cpython-36.pyc | Bin 0 -> 25592 bytes .../__pycache__/field_path.cpython-36.pyc | Bin 0 -> 10785 bytes .../__pycache__/order.cpython-36.pyc | Bin 0 -> 4770 bytes .../__pycache__/query.cpython-36.pyc | Bin 0 -> 31587 bytes .../__pycache__/transaction.cpython-36.pyc | Bin 0 -> 12737 bytes .../__pycache__/transforms.cpython-36.pyc | Bin 0 -> 3091 bytes .../__pycache__/types.cpython-36.pyc | Bin 0 -> 1378 bytes .../__pycache__/watch.cpython-36.pyc | Bin 0 -> 18012 bytes .../cloud/firestore_v1beta1/_helpers.py | 998 ++ .../google/cloud/firestore_v1beta1/batch.py | 162 + .../google/cloud/firestore_v1beta1/client.py | 542 ++ .../cloud/firestore_v1beta1/collection.py | 478 + .../cloud/firestore_v1beta1/document.py | 780 ++ .../cloud/firestore_v1beta1/field_path.py | 386 + .../cloud/firestore_v1beta1/gapic/__init__.py | 0 .../gapic/__pycache__/__init__.cpython-36.pyc | Bin 0 -> 271 bytes .../gapic/__pycache__/enums.cpython-36.pyc | Bin 0 -> 6508 bytes .../firestore_client.cpython-36.pyc | Bin 0 -> 49234 bytes .../firestore_client_config.cpython-36.pyc | Bin 0 -> 1244 bytes .../cloud/firestore_v1beta1/gapic/enums.py | 156 + .../gapic/firestore_client.py | 1457 +++ .../gapic/firestore_client_config.py | 97 + .../gapic/transports/__init__.py | 0 .../__pycache__/__init__.cpython-36.pyc | Bin 0 -> 282 bytes .../firestore_grpc_transport.cpython-36.pyc | Bin 0 -> 9570 bytes .../transports/firestore_grpc_transport.py | 283 + .../google/cloud/firestore_v1beta1/order.py | 207 + .../cloud/firestore_v1beta1/proto/__init__.py | 0 .../proto/__pycache__/__init__.cpython-36.pyc | Bin 0 -> 271 bytes .../__pycache__/common_pb2.cpython-36.pyc | Bin 0 -> 7486 bytes .../common_pb2_grpc.cpython-36.pyc | Bin 0 -> 380 bytes .../__pycache__/document_pb2.cpython-36.pyc | Bin 0 -> 12582 bytes .../document_pb2_grpc.cpython-36.pyc | Bin 0 -> 382 bytes ...nt_flow_document_change_pb2.cpython-36.pyc | Bin 0 -> 2404 bytes ...ow_document_change_pb2_grpc.cpython-36.pyc | Bin 0 -> 314 bytes .../__pycache__/firestore_pb2.cpython-36.pyc | Bin 0 -> 58493 bytes .../firestore_pb2_grpc.cpython-36.pyc | Bin 0 -> 15237 bytes .../__pycache__/query_pb2.cpython-36.pyc | Bin 0 -> 17321 bytes .../__pycache__/query_pb2_grpc.cpython-36.pyc | Bin 0 -> 379 bytes .../test_v1beta1_pb2.cpython-36.pyc | Bin 0 -> 20008 bytes .../__pycache__/write_pb2.cpython-36.pyc | Bin 0 -> 20648 bytes .../__pycache__/write_pb2_grpc.cpython-36.pyc | Bin 0 -> 379 bytes .../firestore_v1beta1/proto/admin/__init__.py | 0 .../admin/__pycache__/__init__.cpython-36.pyc | Bin 0 -> 277 bytes .../firestore_admin_pb2.cpython-36.pyc | Bin 0 -> 26600 bytes .../firestore_admin_pb2_grpc.cpython-36.pyc | Bin 0 -> 7286 bytes .../__pycache__/index_pb2.cpython-36.pyc | Bin 0 -> 5692 bytes .../__pycache__/index_pb2_grpc.cpython-36.pyc | Bin 0 -> 299 bytes .../proto/admin/firestore_admin_pb2.py | 1343 +++ .../proto/admin/firestore_admin_pb2_grpc.py | 203 + .../proto/admin/index_pb2.py | 300 + .../proto/admin/index_pb2_grpc.py | 2 + .../firestore_v1beta1/proto/common.proto | 84 + .../firestore_v1beta1/proto/common_pb2.py | 456 + .../proto/common_pb2_grpc.py | 3 + .../firestore_v1beta1/proto/document.proto | 151 + .../firestore_v1beta1/proto/document_pb2.py | 815 ++ .../proto/document_pb2_grpc.py | 3 + .../proto/event_flow_document_change_pb2.py | 62 + .../event_flow_document_change_pb2_grpc.py | 2 + .../cloud/firestore_v1beta1/proto/field.proto | 95 + .../firestore_v1beta1/proto/firestore.proto | 766 ++ .../proto/firestore_admin.proto | 365 + .../firestore_v1beta1/proto/firestore_pb2.py | 3914 ++++++++ .../proto/firestore_pb2_grpc.py | 669 ++ .../cloud/firestore_v1beta1/proto/index.proto | 102 + .../firestore_v1beta1/proto/location.proto | 34 + .../firestore_v1beta1/proto/operation.proto | 203 + .../cloud/firestore_v1beta1/proto/query.proto | 244 + .../firestore_v1beta1/proto/query_pb2.py | 1284 +++ .../firestore_v1beta1/proto/query_pb2_grpc.py | 3 + .../proto/test_v1beta1_pb2.py | 2190 +++++ .../cloud/firestore_v1beta1/proto/write.proto | 255 + .../firestore_v1beta1/proto/write_pb2.py | 1178 +++ .../firestore_v1beta1/proto/write_pb2_grpc.py | 3 + .../google/cloud/firestore_v1beta1/query.py | 971 ++ .../cloud/firestore_v1beta1/transaction.py | 409 + .../cloud/firestore_v1beta1/transforms.py | 90 + .../google/cloud/firestore_v1beta1/types.py | 63 + .../google/cloud/firestore_v1beta1/watch.py | 722 ++ .../site-packages/google/cloud/obsolete.py | 42 + .../site-packages/google/cloud/operation.py | 266 + .../google/cloud/storage/__init__.py | 45 + .../__pycache__/__init__.cpython-36.pyc | Bin 0 -> 1241 bytes .../__pycache__/_helpers.cpython-36.pyc | Bin 0 -> 17708 bytes .../storage/__pycache__/_http.cpython-36.pyc | Bin 0 -> 1490 bytes .../__pycache__/_signing.cpython-36.pyc | Bin 0 -> 22042 bytes .../storage/__pycache__/acl.cpython-36.pyc | Bin 0 -> 22920 bytes .../storage/__pycache__/batch.cpython-36.pyc | Bin 0 -> 10827 bytes .../storage/__pycache__/blob.cpython-36.pyc | Bin 0 -> 124819 bytes .../storage/__pycache__/bucket.cpython-36.pyc | Bin 0 -> 108970 bytes .../storage/__pycache__/client.cpython-36.pyc | Bin 0 -> 36141 bytes .../__pycache__/constants.cpython-36.pyc | Bin 0 -> 830 bytes .../__pycache__/hmac_key.cpython-36.pyc | Bin 0 -> 8612 bytes .../storage/__pycache__/iam.cpython-36.pyc | Bin 0 -> 1500 bytes .../__pycache__/notification.cpython-36.pyc | Bin 0 -> 13712 bytes .../google/cloud/storage/_helpers.py | 514 + .../google/cloud/storage/_http.py | 48 + .../google/cloud/storage/_signing.py | 720 ++ .../site-packages/google/cloud/storage/acl.py | 657 ++ .../google/cloud/storage/batch.py | 348 + .../google/cloud/storage/blob.py | 3680 ++++++++ .../google/cloud/storage/bucket.py | 3146 +++++++ .../google/cloud/storage/client.py | 1139 +++ .../google/cloud/storage/constants.py | 98 + .../google/cloud/storage/hmac_key.py | 287 + .../site-packages/google/cloud/storage/iam.py | 86 + .../google/cloud/storage/notification.py | 426 + .../Lib/site-packages/google/cloud/version.py | 15 + .../site-packages/google/oauth2/__init__.py | 15 + .../__pycache__/__init__.cpython-36.pyc | Bin 0 -> 296 bytes .../oauth2/__pycache__/_client.cpython-36.pyc | Bin 0 -> 7483 bytes .../__pycache__/_client_async.cpython-36.pyc | Bin 0 -> 7514 bytes .../_credentials_async.cpython-36.pyc | Bin 0 -> 3266 bytes .../_id_token_async.cpython-36.pyc | Bin 0 -> 7978 bytes .../_service_account_async.cpython-36.pyc | Bin 0 -> 4847 bytes .../__pycache__/credentials.cpython-36.pyc | Bin 0 -> 12933 bytes .../__pycache__/id_token.cpython-36.pyc | Bin 0 -> 7722 bytes .../service_account.cpython-36.pyc | Bin 0 -> 19713 bytes .../site-packages/google/oauth2/_client.py | 259 + .../google/oauth2/_client_async.py | 264 + .../google/oauth2/_credentials_async.py | 108 + .../google/oauth2/_id_token_async.py | 267 + .../google/oauth2/_service_account_async.py | 132 + .../google/oauth2/credentials.py | 383 + .../site-packages/google/oauth2/id_token.py | 266 + .../google/oauth2/service_account.py | 606 ++ .../google/resumable_media/__init__.py | 61 + .../__pycache__/__init__.cpython-36.pyc | Bin 0 -> 1248 bytes .../__pycache__/_download.cpython-36.pyc | Bin 0 -> 18617 bytes .../__pycache__/_helpers.cpython-36.pyc | Bin 0 -> 10646 bytes .../__pycache__/_upload.cpython-36.pyc | Bin 0 -> 34591 bytes .../__pycache__/common.cpython-36.pyc | Bin 0 -> 3978 bytes .../google/resumable_media/_download.py | 556 ++ .../google/resumable_media/_helpers.py | 366 + .../google/resumable_media/_upload.py | 1016 ++ .../google/resumable_media/common.py | 148 + .../resumable_media/requests/__init__.py | 678 ++ .../__pycache__/__init__.cpython-36.pyc | Bin 0 -> 21089 bytes .../_request_helpers.cpython-36.pyc | Bin 0 -> 4055 bytes .../__pycache__/download.cpython-36.pyc | Bin 0 -> 16694 bytes .../__pycache__/upload.cpython-36.pyc | Bin 0 -> 18426 bytes .../requests/_request_helpers.py | 136 + .../resumable_media/requests/download.py | 501 + .../google/resumable_media/requests/upload.py | 536 ++ .../google_api_core-1.22.4-py3.8-nspkg.pth | 1 + .../INSTALLER | 1 + .../google_api_core-1.22.4.dist-info/LICENSE | 201 + .../google_api_core-1.22.4.dist-info/METADATA | 62 + .../google_api_core-1.22.4.dist-info/RECORD | 80 + .../google_api_core-1.22.4.dist-info/WHEEL | 6 + .../namespace_packages.txt | 1 + .../top_level.txt | 1 + .../INSTALLER | 1 + .../LICENSE | 22 + .../METADATA | 103 + .../RECORD | 38 + .../WHEEL | 6 + .../top_level.txt | 3 + .../google_auth-1.22.1-py3.8-nspkg.pth | 1 + .../google_auth-1.22.1.dist-info/INSTALLER | 1 + .../google_auth-1.22.1.dist-info/LICENSE | 201 + .../google_auth-1.22.1.dist-info/METADATA | 100 + .../google_auth-1.22.1.dist-info/RECORD | 94 + .../google_auth-1.22.1.dist-info/WHEEL | 6 + .../namespace_packages.txt | 1 + .../top_level.txt | 1 + .../INSTALLER | 1 + .../LICENSE | 201 + .../METADATA | 63 + .../RECORD | 8 + .../WHEEL | 6 + .../top_level.txt | 1 + .../Lib/site-packages/google_auth_httplib2.py | 262 + .../google_cloud_core-1.4.3-py3.8-nspkg.pth | 3 + .../INSTALLER | 1 + .../google_cloud_core-1.4.3.dist-info/LICENSE | 201 + .../METADATA | 68 + .../google_cloud_core-1.4.3.dist-info/RECORD | 26 + .../google_cloud_core-1.4.3.dist-info/WHEEL | 6 + .../namespace_packages.txt | 2 + .../top_level.txt | 1 + ...ogle_cloud_firestore-1.9.0-py3.8-nspkg.pth | 3 + .../INSTALLER | 1 + .../LICENSE | 201 + .../METADATA | 143 + .../RECORD | 208 + .../WHEEL | 6 + .../namespace_packages.txt | 2 + .../top_level.txt | 1 + ...oogle_cloud_storage-1.31.2-py3.8-nspkg.pth | 3 + .../INSTALLER | 1 + .../LICENSE | 201 + .../METADATA | 134 + .../RECORD | 34 + .../WHEEL | 6 + .../namespace_packages.txt | 2 + .../top_level.txt | 1 + .../google_crc32c-1.0.0.dist-info/INSTALLER | 1 + .../google_crc32c-1.0.0.dist-info/LICENSE | 201 + .../google_crc32c-1.0.0.dist-info/METADATA | 176 + .../google_crc32c-1.0.0.dist-info/RECORD | 19 + .../google_crc32c-1.0.0.dist-info/WHEEL | 5 + .../top_level.txt | 1 + .../google_crc32c-1.0.0.dist-info/zip-safe | 1 + .../site-packages/google_crc32c/__config__.py | 38 + .../site-packages/google_crc32c/__init__.py | 37 + .../__pycache__/__config__.cpython-36.pyc | Bin 0 -> 693 bytes .../__pycache__/__init__.cpython-36.pyc | Bin 0 -> 789 bytes .../__pycache__/_checksum.cpython-36.pyc | Bin 0 -> 2714 bytes .../__pycache__/cffi.cpython-36.pyc | Bin 0 -> 2198 bytes .../__pycache__/python.cpython-36.pyc | Bin 0 -> 4959 bytes .../site-packages/google_crc32c/_checksum.py | 86 + .../google_crc32c/_crc32c_cffi.cp36-win32.pyd | Bin 0 -> 9728 bytes venv/Lib/site-packages/google_crc32c/cffi.py | 72 + .../google_crc32c/extra-dll/crc32c.dll | Bin 0 -> 31232 bytes .../Lib/site-packages/google_crc32c/python.py | 124 + ...ogle_resumable_media-1.1.0-py3.8-nspkg.pth | 1 + .../INSTALLER | 1 + .../LICENSE | 202 + .../METADATA | 61 + .../RECORD | 42 + .../WHEEL | 6 + .../namespace_packages.txt | 1 + .../top_level.txt | 1 + .../site-packages/googleapiclient/__init__.py | 27 + .../__pycache__/__init__.cpython-36.pyc | Bin 0 -> 665 bytes .../__pycache__/_auth.cpython-36.pyc | Bin 0 -> 4111 bytes .../__pycache__/_helpers.cpython-36.pyc | Bin 0 -> 6052 bytes .../__pycache__/channel.cpython-36.pyc | Bin 0 -> 9848 bytes .../__pycache__/discovery.cpython-36.pyc | Bin 0 -> 41871 bytes .../__pycache__/errors.cpython-36.pyc | Bin 0 -> 5638 bytes .../__pycache__/http.cpython-36.pyc | Bin 0 -> 52329 bytes .../__pycache__/mimeparse.cpython-36.pyc | Bin 0 -> 6870 bytes .../__pycache__/model.cpython-36.pyc | Bin 0 -> 12418 bytes .../__pycache__/sample_tools.cpython-36.pyc | Bin 0 -> 2981 bytes .../__pycache__/schema.cpython-36.pyc | Bin 0 -> 8922 bytes .../site-packages/googleapiclient/_auth.py | 162 + .../site-packages/googleapiclient/_helpers.py | 211 + .../site-packages/googleapiclient/channel.py | 317 + .../googleapiclient/discovery.py | 1488 +++ .../discovery_cache/__init__.py | 49 + .../__pycache__/__init__.cpython-36.pyc | Bin 0 -> 1159 bytes .../appengine_memcache.cpython-36.pyc | Bin 0 -> 1543 bytes .../__pycache__/base.cpython-36.pyc | Bin 0 -> 1244 bytes .../__pycache__/file_cache.cpython-36.pyc | Bin 0 -> 3624 bytes .../discovery_cache/appengine_memcache.py | 56 + .../googleapiclient/discovery_cache/base.py | 46 + .../discovery_cache/file_cache.py | 146 + .../site-packages/googleapiclient/errors.py | 180 + .../Lib/site-packages/googleapiclient/http.py | 1922 ++++ .../googleapiclient/mimeparse.py | 183 + .../site-packages/googleapiclient/model.py | 407 + .../googleapiclient/sample_tools.py | 110 + .../site-packages/googleapiclient/schema.py | 315 + venv/Lib/site-packages/grpc/__init__.py | 2125 +++++ .../grpc/__pycache__/__init__.cpython-36.pyc | Bin 0 -> 79550 bytes .../grpc/__pycache__/_auth.cpython-36.pyc | Bin 0 -> 1931 bytes .../grpc/__pycache__/_channel.cpython-36.pyc | Bin 0 -> 41170 bytes .../grpc/__pycache__/_common.cpython-36.pyc | Bin 0 -> 5259 bytes .../__pycache__/_compression.cpython-36.pyc | Bin 0 -> 1255 bytes .../_grpcio_metadata.cpython-36.pyc | Bin 0 -> 269 bytes .../__pycache__/_interceptor.cpython-36.pyc | Bin 0 -> 17240 bytes .../_plugin_wrapping.cpython-36.pyc | Bin 0 -> 2984 bytes .../_runtime_protos.cpython-36.pyc | Bin 0 -> 5419 bytes .../grpc/__pycache__/_server.cpython-36.pyc | Bin 0 -> 27026 bytes .../__pycache__/_simple_stubs.cpython-36.pyc | Bin 0 -> 18293 bytes .../__pycache__/_utilities.cpython-36.pyc | Bin 0 -> 5236 bytes venv/Lib/site-packages/grpc/_auth.py | 58 + venv/Lib/site-packages/grpc/_channel.py | 1461 +++ venv/Lib/site-packages/grpc/_common.py | 168 + venv/Lib/site-packages/grpc/_compression.py | 55 + .../site-packages/grpc/_cython/__init__.py | 13 + .../__pycache__/__init__.cpython-36.pyc | Bin 0 -> 247 bytes .../_cython/_credentials/roots.pem} | 3374 +++---- .../grpc/_cython/_cygrpc/__init__.py | 13 + .../__pycache__/__init__.cpython-36.pyc | Bin 0 -> 255 bytes .../grpc/_cython/cygrpc.cp36-win32.pyd | Bin 0 -> 4609024 bytes .../site-packages/grpc/_grpcio_metadata.py | 1 + venv/Lib/site-packages/grpc/_interceptor.py | 562 ++ .../site-packages/grpc/_plugin_wrapping.py | 101 + .../Lib/site-packages/grpc/_runtime_protos.py | 171 + venv/Lib/site-packages/grpc/_server.py | 995 ++ venv/Lib/site-packages/grpc/_simple_stubs.py | 493 + venv/Lib/site-packages/grpc/_utilities.py | 169 + venv/Lib/site-packages/grpc/aio/__init__.py | 81 + .../aio/__pycache__/__init__.cpython-36.pyc | Bin 0 -> 2106 bytes .../aio/__pycache__/_base_call.cpython-36.pyc | Bin 0 -> 8578 bytes .../__pycache__/_base_channel.cpython-36.pyc | Bin 0 -> 13460 bytes .../__pycache__/_base_server.cpython-36.pyc | Bin 0 -> 11323 bytes .../grpc/aio/__pycache__/_call.cpython-36.pyc | Bin 0 -> 19925 bytes .../aio/__pycache__/_channel.cpython-36.pyc | Bin 0 -> 12378 bytes .../__pycache__/_interceptor.cpython-36.pyc | Bin 0 -> 32574 bytes .../aio/__pycache__/_metadata.cpython-36.pyc | Bin 0 -> 4757 bytes .../aio/__pycache__/_server.cpython-36.pyc | Bin 0 -> 8062 bytes .../aio/__pycache__/_typing.cpython-36.pyc | Bin 0 -> 962 bytes .../aio/__pycache__/_utils.cpython-36.pyc | Bin 0 -> 541 bytes venv/Lib/site-packages/grpc/aio/_base_call.py | 244 + .../site-packages/grpc/aio/_base_channel.py | 347 + .../site-packages/grpc/aio/_base_server.py | 294 + venv/Lib/site-packages/grpc/aio/_call.py | 629 ++ venv/Lib/site-packages/grpc/aio/_channel.py | 469 + .../site-packages/grpc/aio/_interceptor.py | 987 ++ venv/Lib/site-packages/grpc/aio/_metadata.py | 119 + venv/Lib/site-packages/grpc/aio/_server.py | 209 + venv/Lib/site-packages/grpc/aio/_typing.py | 32 + venv/Lib/site-packages/grpc/aio/_utils.py | 22 + venv/Lib/site-packages/grpc/beta/__init__.py | 13 + .../beta/__pycache__/__init__.cpython-36.pyc | Bin 0 -> 244 bytes .../_client_adaptations.cpython-36.pyc | Bin 0 -> 18114 bytes .../beta/__pycache__/_metadata.cpython-36.pyc | Bin 0 -> 1437 bytes .../_server_adaptations.cpython-36.pyc | Bin 0 -> 11921 bytes .../implementations.cpython-36.pyc | Bin 0 -> 10129 bytes .../__pycache__/interfaces.cpython-36.pyc | Bin 0 -> 6320 bytes .../beta/__pycache__/utilities.cpython-36.pyc | Bin 0 -> 4435 bytes .../grpc/beta/_client_adaptations.py | 706 ++ venv/Lib/site-packages/grpc/beta/_metadata.py | 52 + .../grpc/beta/_server_adaptations.py | 385 + .../grpc/beta/implementations.py | 310 + .../Lib/site-packages/grpc/beta/interfaces.py | 165 + venv/Lib/site-packages/grpc/beta/utilities.py | 149 + .../grpc/experimental/__init__.py | 127 + .../__pycache__/__init__.cpython-36.pyc | Bin 0 -> 3607 bytes .../__pycache__/gevent.cpython-36.pyc | Bin 0 -> 736 bytes .../__pycache__/session_cache.cpython-36.pyc | Bin 0 -> 1569 bytes .../grpc/experimental/aio/__init__.py | 16 + .../aio/__pycache__/__init__.cpython-36.pyc | Bin 0 -> 347 bytes .../site-packages/grpc/experimental/gevent.py | 27 + .../grpc/experimental/session_cache.py | 45 + .../site-packages/grpc/framework/__init__.py | 13 + .../__pycache__/__init__.cpython-36.pyc | Bin 0 -> 249 bytes .../grpc/framework/common/__init__.py | 13 + .../__pycache__/__init__.cpython-36.pyc | Bin 0 -> 256 bytes .../__pycache__/cardinality.cpython-36.pyc | Bin 0 -> 817 bytes .../common/__pycache__/style.cpython-36.pyc | Bin 0 -> 647 bytes .../grpc/framework/common/cardinality.py | 26 + .../grpc/framework/common/style.py | 24 + .../grpc/framework/foundation/__init__.py | 13 + .../__pycache__/__init__.cpython-36.pyc | Bin 0 -> 260 bytes .../__pycache__/abandonment.cpython-36.pyc | Bin 0 -> 698 bytes .../__pycache__/callable_util.cpython-36.pyc | Bin 0 -> 3197 bytes .../__pycache__/future.cpython-36.pyc | Bin 0 -> 7189 bytes .../__pycache__/logging_pool.cpython-36.pyc | Bin 0 -> 2536 bytes .../__pycache__/stream.cpython-36.pyc | Bin 0 -> 1363 bytes .../__pycache__/stream_util.cpython-36.pyc | Bin 0 -> 4619 bytes .../grpc/framework/foundation/abandonment.py | 22 + .../framework/foundation/callable_util.py | 96 + .../grpc/framework/foundation/future.py | 221 + .../grpc/framework/foundation/logging_pool.py | 72 + .../grpc/framework/foundation/stream.py | 45 + .../grpc/framework/foundation/stream_util.py | 148 + .../grpc/framework/interfaces/__init__.py | 13 + .../__pycache__/__init__.cpython-36.pyc | Bin 0 -> 260 bytes .../framework/interfaces/base/__init__.py | 13 + .../base/__pycache__/__init__.cpython-36.pyc | Bin 0 -> 265 bytes .../base/__pycache__/base.cpython-36.pyc | Bin 0 -> 13154 bytes .../base/__pycache__/utilities.cpython-36.pyc | Bin 0 -> 2056 bytes .../grpc/framework/interfaces/base/base.py | 330 + .../framework/interfaces/base/utilities.py | 71 + .../framework/interfaces/face/__init__.py | 13 + .../face/__pycache__/__init__.cpython-36.pyc | Bin 0 -> 265 bytes .../face/__pycache__/face.cpython-36.pyc | Bin 0 -> 39818 bytes .../face/__pycache__/utilities.cpython-36.pyc | Bin 0 -> 5359 bytes .../grpc/framework/interfaces/face/face.py | 1052 +++ .../framework/interfaces/face/utilities.py | 168 + .../grpcio-1.32.0.dist-info/DESCRIPTION.rst | 117 + .../grpcio-1.32.0.dist-info/INSTALLER | 1 + .../grpcio-1.32.0.dist-info/METADATA | 143 + .../grpcio-1.32.0.dist-info/RECORD | 117 + .../grpcio-1.32.0.dist-info/WHEEL | 5 + .../grpcio-1.32.0.dist-info/metadata.json | 1 + .../grpcio-1.32.0.dist-info/top_level.txt | 1 + .../idna-2.10.dist-info/INSTALLER | 1 + .../idna-2.10.dist-info/LICENSE.rst | 34 + .../idna-2.10.dist-info/METADATA | 243 + .../site-packages/idna-2.10.dist-info/RECORD | 22 + .../site-packages/idna-2.10.dist-info/WHEEL | 6 + .../idna-2.10.dist-info/top_level.txt | 1 + venv/Lib/site-packages/idna/__init__.py | 2 + .../idna/__pycache__/__init__.cpython-36.pyc | Bin 0 -> 308 bytes .../idna/__pycache__/codec.cpython-36.pyc | Bin 0 -> 3155 bytes .../idna/__pycache__/compat.cpython-36.pyc | Bin 0 -> 668 bytes .../idna/__pycache__/core.cpython-36.pyc | Bin 0 -> 9365 bytes .../idna/__pycache__/idnadata.cpython-36.pyc | Bin 0 -> 30800 bytes .../idna/__pycache__/intranges.cpython-36.pyc | Bin 0 -> 1869 bytes .../__pycache__/package_data.cpython-36.pyc | Bin 0 -> 263 bytes .../idna/__pycache__/uts46data.cpython-36.pyc | Bin 0 -> 246465 bytes venv/Lib/site-packages/idna/codec.py | 118 + venv/Lib/site-packages/idna/compat.py | 12 + venv/Lib/site-packages/idna/core.py | 400 + venv/Lib/site-packages/idna/idnadata.py | 2050 ++++ venv/Lib/site-packages/idna/intranges.py | 53 + venv/Lib/site-packages/idna/package_data.py | 2 + venv/Lib/site-packages/idna/uts46data.py | 8357 +++++++++++++++++ .../msgpack-1.0.0.dist-info/COPYING | 14 + .../msgpack-1.0.0.dist-info/INSTALLER | 1 + .../msgpack-1.0.0.dist-info/METADATA | 299 + .../msgpack-1.0.0.dist-info/RECORD | 17 + .../msgpack-1.0.0.dist-info/WHEEL | 5 + .../msgpack-1.0.0.dist-info/top_level.txt | 1 + venv/Lib/site-packages/msgpack/__init__.py | 54 + .../__pycache__/__init__.cpython-36.pyc | Bin 0 -> 1443 bytes .../__pycache__/_version.cpython-36.pyc | Bin 0 -> 279 bytes .../__pycache__/exceptions.cpython-36.pyc | Bin 0 -> 1917 bytes .../msgpack/__pycache__/ext.cpython-36.pyc | Bin 0 -> 6286 bytes .../__pycache__/fallback.cpython-36.pyc | Bin 0 -> 26169 bytes .../msgpack/_cmsgpack.cp36-win32.pyd | Bin 0 -> 108032 bytes venv/Lib/site-packages/msgpack/_version.py | 1 + venv/Lib/site-packages/msgpack/exceptions.py | 48 + venv/Lib/site-packages/msgpack/ext.py | 191 + venv/Lib/site-packages/msgpack/fallback.py | 1063 +++ .../pycparser-2.20.dist-info/INSTALLER | 1 + .../pycparser-2.20.dist-info/LICENSE | 27 + .../pycparser-2.20.dist-info/METADATA | 27 + .../pycparser-2.20.dist-info/RECORD | 41 + .../pycparser-2.20.dist-info/WHEEL | 6 + .../pycparser-2.20.dist-info/top_level.txt | 1 + venv/Lib/site-packages/pycparser/__init__.py | 90 + .../__pycache__/__init__.cpython-36.pyc | Bin 0 -> 2624 bytes .../__pycache__/_ast_gen.cpython-36.pyc | Bin 0 -> 10509 bytes .../__pycache__/_build_tables.cpython-36.pyc | Bin 0 -> 598 bytes .../__pycache__/ast_transforms.cpython-36.pyc | Bin 0 -> 2622 bytes .../__pycache__/c_ast.cpython-36.pyc | Bin 0 -> 38142 bytes .../__pycache__/c_generator.cpython-36.pyc | Bin 0 -> 17011 bytes .../__pycache__/c_lexer.cpython-36.pyc | Bin 0 -> 12596 bytes .../__pycache__/c_parser.cpython-36.pyc | Bin 0 -> 62014 bytes .../__pycache__/lextab.cpython-36.pyc | Bin 0 -> 5701 bytes .../__pycache__/plyparser.cpython-36.pyc | Bin 0 -> 4751 bytes .../__pycache__/yacctab.cpython-36.pyc | Bin 0 -> 143105 bytes venv/Lib/site-packages/pycparser/_ast_gen.py | 338 + .../site-packages/pycparser/_build_tables.py | 37 + venv/Lib/site-packages/pycparser/_c_ast.cfg | 191 + .../site-packages/pycparser/ast_transforms.py | 106 + venv/Lib/site-packages/pycparser/c_ast.py | 1084 +++ .../site-packages/pycparser/c_generator.py | 444 + venv/Lib/site-packages/pycparser/c_lexer.py | 514 + venv/Lib/site-packages/pycparser/c_parser.py | 1863 ++++ venv/Lib/site-packages/pycparser/lextab.py | 10 + .../site-packages/pycparser/ply/__init__.py | 5 + .../ply/__pycache__/__init__.cpython-36.pyc | Bin 0 -> 297 bytes .../ply/__pycache__/cpp.cpython-36.pyc | Bin 0 -> 16330 bytes .../ply/__pycache__/ctokens.cpython-36.pyc | Bin 0 -> 2270 bytes .../ply/__pycache__/lex.cpython-36.pyc | Bin 0 -> 21571 bytes .../ply/__pycache__/yacc.cpython-36.pyc | Bin 0 -> 53999 bytes .../ply/__pycache__/ygen.cpython-36.pyc | Bin 0 -> 1812 bytes venv/Lib/site-packages/pycparser/ply/cpp.py | 905 ++ .../site-packages/pycparser/ply/ctokens.py | 133 + venv/Lib/site-packages/pycparser/ply/lex.py | 1099 +++ venv/Lib/site-packages/pycparser/ply/yacc.py | 3494 +++++++ venv/Lib/site-packages/pycparser/ply/ygen.py | 74 + venv/Lib/site-packages/pycparser/plyparser.py | 133 + venv/Lib/site-packages/pycparser/yacctab.py | 338 + .../pytz-2020.1.dist-info/DESCRIPTION.rst | 598 ++ .../pytz-2020.1.dist-info/INSTALLER | 1 + .../pytz-2020.1.dist-info/LICENSE.txt | 19 + .../pytz-2020.1.dist-info/METADATA | 632 ++ .../pytz-2020.1.dist-info/RECORD | 621 ++ .../site-packages/pytz-2020.1.dist-info/WHEEL | 6 + .../pytz-2020.1.dist-info/metadata.json | 1 + .../pytz-2020.1.dist-info/top_level.txt | 1 + .../pytz-2020.1.dist-info/zip-safe | 1 + venv/Lib/site-packages/pytz/__init__.py | 1552 +++ .../pytz/__pycache__/__init__.cpython-36.pyc | Bin 0 -> 29627 bytes .../__pycache__/exceptions.cpython-36.pyc | Bin 0 -> 2271 bytes .../pytz/__pycache__/lazy.cpython-36.pyc | Bin 0 -> 5345 bytes .../pytz/__pycache__/reference.cpython-36.pyc | Bin 0 -> 3964 bytes .../pytz/__pycache__/tzfile.cpython-36.pyc | Bin 0 -> 3200 bytes .../pytz/__pycache__/tzinfo.cpython-36.pyc | Bin 0 -> 15022 bytes venv/Lib/site-packages/pytz/exceptions.py | 59 + venv/Lib/site-packages/pytz/lazy.py | 172 + venv/Lib/site-packages/pytz/reference.py | 140 + venv/Lib/site-packages/pytz/tzfile.py | 134 + venv/Lib/site-packages/pytz/tzinfo.py | 577 ++ .../pytz/zoneinfo/Africa/Abidjan | Bin 0 -> 148 bytes .../site-packages/pytz/zoneinfo/Africa/Accra | Bin 0 -> 816 bytes .../pytz/zoneinfo/Africa/Addis_Ababa | Bin 0 -> 251 bytes .../pytz/zoneinfo/Africa/Algiers | Bin 0 -> 735 bytes .../site-packages/pytz/zoneinfo/Africa/Asmara | Bin 0 -> 251 bytes .../site-packages/pytz/zoneinfo/Africa/Asmera | Bin 0 -> 251 bytes .../site-packages/pytz/zoneinfo/Africa/Bamako | Bin 0 -> 148 bytes .../site-packages/pytz/zoneinfo/Africa/Bangui | Bin 0 -> 149 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 -> 149 bytes .../pytz/zoneinfo/Africa/Bujumbura | Bin 0 -> 149 bytes .../site-packages/pytz/zoneinfo/Africa/Cairo | Bin 0 -> 1955 bytes .../pytz/zoneinfo/Africa/Casablanca | Bin 0 -> 2429 bytes .../site-packages/pytz/zoneinfo/Africa/Ceuta | Bin 0 -> 2036 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 -> 251 bytes .../pytz/zoneinfo/Africa/Djibouti | Bin 0 -> 251 bytes .../site-packages/pytz/zoneinfo/Africa/Douala | Bin 0 -> 149 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 -> 653 bytes .../pytz/zoneinfo/Africa/Kampala | Bin 0 -> 251 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 -> 149 bytes .../site-packages/pytz/zoneinfo/Africa/Lagos | Bin 0 -> 149 bytes .../pytz/zoneinfo/Africa/Libreville | Bin 0 -> 149 bytes .../site-packages/pytz/zoneinfo/Africa/Lome | Bin 0 -> 148 bytes .../site-packages/pytz/zoneinfo/Africa/Luanda | Bin 0 -> 149 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 -> 149 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 -> 251 bytes .../pytz/zoneinfo/Africa/Monrovia | Bin 0 -> 208 bytes .../pytz/zoneinfo/Africa/Nairobi | Bin 0 -> 251 bytes .../pytz/zoneinfo/Africa/Ndjamena | Bin 0 -> 199 bytes .../site-packages/pytz/zoneinfo/Africa/Niamey | Bin 0 -> 149 bytes .../pytz/zoneinfo/Africa/Nouakchott | Bin 0 -> 148 bytes .../pytz/zoneinfo/Africa/Ouagadougou | Bin 0 -> 148 bytes .../pytz/zoneinfo/Africa/Porto-Novo | Bin 0 -> 149 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 -> 148 bytes .../pytz/zoneinfo/America/Antigua | Bin 0 -> 148 bytes .../pytz/zoneinfo/America/Araguaina | Bin 0 -> 884 bytes .../zoneinfo/America/Argentina/Buenos_Aires | Bin 0 -> 1076 bytes .../pytz/zoneinfo/America/Argentina/Catamarca | Bin 0 -> 1076 bytes .../zoneinfo/America/Argentina/ComodRivadavia | Bin 0 -> 1076 bytes .../pytz/zoneinfo/America/Argentina/Cordoba | Bin 0 -> 1076 bytes .../pytz/zoneinfo/America/Argentina/Jujuy | Bin 0 -> 1048 bytes .../pytz/zoneinfo/America/Argentina/La_Rioja | Bin 0 -> 1090 bytes .../pytz/zoneinfo/America/Argentina/Mendoza | Bin 0 -> 1076 bytes .../zoneinfo/America/Argentina/Rio_Gallegos | Bin 0 -> 1076 bytes .../pytz/zoneinfo/America/Argentina/Salta | Bin 0 -> 1048 bytes .../pytz/zoneinfo/America/Argentina/San_Juan | Bin 0 -> 1090 bytes .../pytz/zoneinfo/America/Argentina/San_Luis | Bin 0 -> 1102 bytes .../pytz/zoneinfo/America/Argentina/Tucuman | Bin 0 -> 1104 bytes .../pytz/zoneinfo/America/Argentina/Ushuaia | Bin 0 -> 1076 bytes .../site-packages/pytz/zoneinfo/America/Aruba | Bin 0 -> 186 bytes .../pytz/zoneinfo/America/Asuncion | Bin 0 -> 2044 bytes .../pytz/zoneinfo/America/Atikokan | Bin 0 -> 336 bytes .../site-packages/pytz/zoneinfo/America/Atka | Bin 0 -> 2356 bytes .../site-packages/pytz/zoneinfo/America/Bahia | Bin 0 -> 1024 bytes .../pytz/zoneinfo/America/Bahia_Banderas | Bin 0 -> 1546 bytes .../pytz/zoneinfo/America/Barbados | Bin 0 -> 314 bytes .../site-packages/pytz/zoneinfo/America/Belem | Bin 0 -> 576 bytes .../pytz/zoneinfo/America/Belize | Bin 0 -> 948 bytes .../pytz/zoneinfo/America/Blanc-Sablon | Bin 0 -> 298 bytes .../pytz/zoneinfo/America/Boa_Vista | Bin 0 -> 632 bytes .../pytz/zoneinfo/America/Bogota | Bin 0 -> 246 bytes .../site-packages/pytz/zoneinfo/America/Boise | Bin 0 -> 2394 bytes .../pytz/zoneinfo/America/Buenos_Aires | Bin 0 -> 1076 bytes .../pytz/zoneinfo/America/Cambridge_Bay | Bin 0 -> 2084 bytes .../pytz/zoneinfo/America/Campo_Grande | Bin 0 -> 1444 bytes .../pytz/zoneinfo/America/Cancun | Bin 0 -> 782 bytes .../pytz/zoneinfo/America/Caracas | Bin 0 -> 264 bytes .../pytz/zoneinfo/America/Catamarca | Bin 0 -> 1076 bytes .../pytz/zoneinfo/America/Cayenne | Bin 0 -> 198 bytes .../pytz/zoneinfo/America/Cayman | Bin 0 -> 182 bytes .../pytz/zoneinfo/America/Chicago | Bin 0 -> 3576 bytes .../pytz/zoneinfo/America/Chihuahua | Bin 0 -> 1484 bytes .../pytz/zoneinfo/America/Coral_Harbour | Bin 0 -> 336 bytes .../pytz/zoneinfo/America/Cordoba | Bin 0 -> 1076 bytes .../pytz/zoneinfo/America/Costa_Rica | Bin 0 -> 316 bytes .../pytz/zoneinfo/America/Creston | Bin 0 -> 208 bytes .../pytz/zoneinfo/America/Cuiaba | Bin 0 -> 1416 bytes .../pytz/zoneinfo/America/Curacao | Bin 0 -> 186 bytes .../pytz/zoneinfo/America/Danmarkshavn | Bin 0 -> 698 bytes .../pytz/zoneinfo/America/Dawson | Bin 0 -> 1600 bytes .../pytz/zoneinfo/America/Dawson_Creek | Bin 0 -> 1050 bytes .../pytz/zoneinfo/America/Denver | Bin 0 -> 2444 bytes .../pytz/zoneinfo/America/Detroit | Bin 0 -> 2230 bytes .../pytz/zoneinfo/America/Dominica | Bin 0 -> 148 bytes .../pytz/zoneinfo/America/Edmonton | Bin 0 -> 2332 bytes .../pytz/zoneinfo/America/Eirunepe | Bin 0 -> 656 bytes .../pytz/zoneinfo/America/El_Salvador | Bin 0 -> 224 bytes .../pytz/zoneinfo/America/Ensenada | Bin 0 -> 2342 bytes .../pytz/zoneinfo/America/Fort_Nelson | Bin 0 -> 2240 bytes .../pytz/zoneinfo/America/Fort_Wayne | Bin 0 -> 1666 bytes .../pytz/zoneinfo/America/Fortaleza | Bin 0 -> 716 bytes .../pytz/zoneinfo/America/Glace_Bay | Bin 0 -> 2192 bytes .../pytz/zoneinfo/America/Godthab | Bin 0 -> 1878 bytes .../pytz/zoneinfo/America/Goose_Bay | Bin 0 -> 3210 bytes .../pytz/zoneinfo/America/Grand_Turk | Bin 0 -> 1848 bytes .../pytz/zoneinfo/America/Grenada | Bin 0 -> 148 bytes .../pytz/zoneinfo/America/Guadeloupe | Bin 0 -> 148 bytes .../pytz/zoneinfo/America/Guatemala | Bin 0 -> 280 bytes .../pytz/zoneinfo/America/Guayaquil | Bin 0 -> 246 bytes .../pytz/zoneinfo/America/Guyana | Bin 0 -> 236 bytes .../pytz/zoneinfo/America/Halifax | Bin 0 -> 3424 bytes .../pytz/zoneinfo/America/Havana | Bin 0 -> 2416 bytes .../pytz/zoneinfo/America/Hermosillo | Bin 0 -> 416 bytes .../zoneinfo/America/Indiana/Indianapolis | Bin 0 -> 1666 bytes .../pytz/zoneinfo/America/Indiana/Knox | Bin 0 -> 2428 bytes .../pytz/zoneinfo/America/Indiana/Marengo | Bin 0 -> 1722 bytes .../pytz/zoneinfo/America/Indiana/Petersburg | Bin 0 -> 1904 bytes .../pytz/zoneinfo/America/Indiana/Tell_City | Bin 0 -> 1684 bytes .../pytz/zoneinfo/America/Indiana/Vevay | Bin 0 -> 1414 bytes .../pytz/zoneinfo/America/Indiana/Vincennes | Bin 0 -> 1694 bytes .../pytz/zoneinfo/America/Indiana/Winamac | Bin 0 -> 1778 bytes .../pytz/zoneinfo/America/Indianapolis | Bin 0 -> 1666 bytes .../pytz/zoneinfo/America/Inuvik | Bin 0 -> 1894 bytes .../pytz/zoneinfo/America/Iqaluit | Bin 0 -> 2032 bytes .../pytz/zoneinfo/America/Jamaica | Bin 0 -> 482 bytes .../site-packages/pytz/zoneinfo/America/Jujuy | Bin 0 -> 1048 bytes .../pytz/zoneinfo/America/Juneau | Bin 0 -> 2353 bytes .../pytz/zoneinfo/America/Kentucky/Louisville | Bin 0 -> 2772 bytes .../pytz/zoneinfo/America/Kentucky/Monticello | Bin 0 -> 2352 bytes .../pytz/zoneinfo/America/Knox_IN | Bin 0 -> 2428 bytes .../pytz/zoneinfo/America/Kralendijk | Bin 0 -> 186 bytes .../pytz/zoneinfo/America/La_Paz | Bin 0 -> 232 bytes .../site-packages/pytz/zoneinfo/America/Lima | Bin 0 -> 406 bytes .../pytz/zoneinfo/America/Los_Angeles | Bin 0 -> 2836 bytes .../pytz/zoneinfo/America/Louisville | Bin 0 -> 2772 bytes .../pytz/zoneinfo/America/Lower_Princes | Bin 0 -> 186 bytes .../pytz/zoneinfo/America/Maceio | Bin 0 -> 744 bytes .../pytz/zoneinfo/America/Managua | Bin 0 -> 430 bytes .../pytz/zoneinfo/America/Manaus | Bin 0 -> 604 bytes .../pytz/zoneinfo/America/Marigot | Bin 0 -> 148 bytes .../pytz/zoneinfo/America/Martinique | Bin 0 -> 232 bytes .../pytz/zoneinfo/America/Matamoros | Bin 0 -> 1390 bytes .../pytz/zoneinfo/America/Mazatlan | Bin 0 -> 1526 bytes .../pytz/zoneinfo/America/Mendoza | Bin 0 -> 1076 bytes .../pytz/zoneinfo/America/Menominee | Bin 0 -> 2274 bytes .../pytz/zoneinfo/America/Merida | Bin 0 -> 1422 bytes .../pytz/zoneinfo/America/Metlakatla | Bin 0 -> 1423 bytes .../pytz/zoneinfo/America/Mexico_City | Bin 0 -> 1584 bytes .../pytz/zoneinfo/America/Miquelon | Bin 0 -> 1666 bytes .../pytz/zoneinfo/America/Moncton | Bin 0 -> 3154 bytes .../pytz/zoneinfo/America/Monterrey | Bin 0 -> 1390 bytes .../pytz/zoneinfo/America/Montevideo | Bin 0 -> 1510 bytes .../pytz/zoneinfo/America/Montreal | Bin 0 -> 3494 bytes .../pytz/zoneinfo/America/Montserrat | Bin 0 -> 148 bytes .../pytz/zoneinfo/America/Nassau | Bin 0 -> 2258 bytes .../pytz/zoneinfo/America/New_York | Bin 0 -> 3536 bytes .../pytz/zoneinfo/America/Nipigon | Bin 0 -> 2122 bytes .../site-packages/pytz/zoneinfo/America/Nome | Bin 0 -> 2367 bytes .../pytz/zoneinfo/America/Noronha | Bin 0 -> 716 bytes .../pytz/zoneinfo/America/North_Dakota/Beulah | Bin 0 -> 2380 bytes .../pytz/zoneinfo/America/North_Dakota/Center | Bin 0 -> 2380 bytes .../zoneinfo/America/North_Dakota/New_Salem | Bin 0 -> 2380 bytes .../site-packages/pytz/zoneinfo/America/Nuuk | Bin 0 -> 1878 bytes .../pytz/zoneinfo/America/Ojinaga | Bin 0 -> 1484 bytes .../pytz/zoneinfo/America/Panama | Bin 0 -> 182 bytes .../pytz/zoneinfo/America/Pangnirtung | Bin 0 -> 2094 bytes .../pytz/zoneinfo/America/Paramaribo | Bin 0 -> 262 bytes .../pytz/zoneinfo/America/Phoenix | Bin 0 -> 328 bytes .../pytz/zoneinfo/America/Port-au-Prince | Bin 0 -> 1434 bytes .../pytz/zoneinfo/America/Port_of_Spain | Bin 0 -> 148 bytes .../pytz/zoneinfo/America/Porto_Acre | Bin 0 -> 628 bytes .../pytz/zoneinfo/America/Porto_Velho | Bin 0 -> 576 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 -> 2122 bytes .../pytz/zoneinfo/America/Rankin_Inlet | Bin 0 -> 1892 bytes .../pytz/zoneinfo/America/Recife | Bin 0 -> 716 bytes .../pytz/zoneinfo/America/Regina | Bin 0 -> 980 bytes .../pytz/zoneinfo/America/Resolute | Bin 0 -> 1892 bytes .../pytz/zoneinfo/America/Rio_Branco | Bin 0 -> 628 bytes .../pytz/zoneinfo/America/Rosario | Bin 0 -> 1076 bytes .../pytz/zoneinfo/America/Santa_Isabel | Bin 0 -> 2342 bytes .../pytz/zoneinfo/America/Santarem | Bin 0 -> 602 bytes .../pytz/zoneinfo/America/Santiago | Bin 0 -> 2529 bytes .../pytz/zoneinfo/America/Santo_Domingo | Bin 0 -> 458 bytes .../pytz/zoneinfo/America/Sao_Paulo | Bin 0 -> 1444 bytes .../pytz/zoneinfo/America/Scoresbysund | Bin 0 -> 1916 bytes .../pytz/zoneinfo/America/Shiprock | Bin 0 -> 2444 bytes .../site-packages/pytz/zoneinfo/America/Sitka | Bin 0 -> 2329 bytes .../pytz/zoneinfo/America/St_Barthelemy | Bin 0 -> 148 bytes .../pytz/zoneinfo/America/St_Johns | Bin 0 -> 3655 bytes .../pytz/zoneinfo/America/St_Kitts | Bin 0 -> 148 bytes .../pytz/zoneinfo/America/St_Lucia | Bin 0 -> 148 bytes .../pytz/zoneinfo/America/St_Thomas | Bin 0 -> 148 bytes .../pytz/zoneinfo/America/St_Vincent | Bin 0 -> 148 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 -> 2202 bytes .../pytz/zoneinfo/America/Tijuana | Bin 0 -> 2342 bytes .../pytz/zoneinfo/America/Toronto | Bin 0 -> 3494 bytes .../pytz/zoneinfo/America/Tortola | Bin 0 -> 148 bytes .../pytz/zoneinfo/America/Vancouver | Bin 0 -> 2892 bytes .../pytz/zoneinfo/America/Virgin | Bin 0 -> 148 bytes .../pytz/zoneinfo/America/Whitehorse | Bin 0 -> 1600 bytes .../pytz/zoneinfo/America/Winnipeg | Bin 0 -> 2868 bytes .../pytz/zoneinfo/America/Yakutat | Bin 0 -> 2305 bytes .../pytz/zoneinfo/America/Yellowknife | Bin 0 -> 1966 bytes .../pytz/zoneinfo/Antarctica/Casey | Bin 0 -> 297 bytes .../pytz/zoneinfo/Antarctica/Davis | Bin 0 -> 297 bytes .../pytz/zoneinfo/Antarctica/DumontDUrville | Bin 0 -> 194 bytes .../pytz/zoneinfo/Antarctica/Macquarie | Bin 0 -> 1520 bytes .../pytz/zoneinfo/Antarctica/Mawson | Bin 0 -> 199 bytes .../pytz/zoneinfo/Antarctica/McMurdo | Bin 0 -> 2437 bytes .../pytz/zoneinfo/Antarctica/Palmer | Bin 0 -> 1418 bytes .../pytz/zoneinfo/Antarctica/Rothera | Bin 0 -> 164 bytes .../pytz/zoneinfo/Antarctica/South_Pole | Bin 0 -> 2437 bytes .../pytz/zoneinfo/Antarctica/Syowa | Bin 0 -> 165 bytes .../pytz/zoneinfo/Antarctica/Troll | Bin 0 -> 1162 bytes .../pytz/zoneinfo/Antarctica/Vostok | Bin 0 -> 165 bytes .../pytz/zoneinfo/Arctic/Longyearbyen | Bin 0 -> 2228 bytes .../Lib/site-packages/pytz/zoneinfo/Asia/Aden | Bin 0 -> 165 bytes .../site-packages/pytz/zoneinfo/Asia/Almaty | Bin 0 -> 997 bytes .../site-packages/pytz/zoneinfo/Asia/Amman | Bin 0 -> 1853 bytes .../site-packages/pytz/zoneinfo/Asia/Anadyr | Bin 0 -> 1188 bytes .../site-packages/pytz/zoneinfo/Asia/Aqtau | Bin 0 -> 983 bytes .../site-packages/pytz/zoneinfo/Asia/Aqtobe | Bin 0 -> 1011 bytes .../site-packages/pytz/zoneinfo/Asia/Ashgabat | Bin 0 -> 619 bytes .../pytz/zoneinfo/Asia/Ashkhabad | Bin 0 -> 619 bytes .../site-packages/pytz/zoneinfo/Asia/Atyrau | Bin 0 -> 991 bytes .../site-packages/pytz/zoneinfo/Asia/Baghdad | Bin 0 -> 983 bytes .../site-packages/pytz/zoneinfo/Asia/Bahrain | Bin 0 -> 199 bytes .../Lib/site-packages/pytz/zoneinfo/Asia/Baku | Bin 0 -> 1227 bytes .../site-packages/pytz/zoneinfo/Asia/Bangkok | Bin 0 -> 199 bytes .../site-packages/pytz/zoneinfo/Asia/Barnaul | Bin 0 -> 1221 bytes .../site-packages/pytz/zoneinfo/Asia/Beirut | Bin 0 -> 2154 bytes .../site-packages/pytz/zoneinfo/Asia/Bishkek | Bin 0 -> 983 bytes .../site-packages/pytz/zoneinfo/Asia/Brunei | Bin 0 -> 203 bytes .../site-packages/pytz/zoneinfo/Asia/Calcutta | Bin 0 -> 285 bytes .../site-packages/pytz/zoneinfo/Asia/Chita | Bin 0 -> 1221 bytes .../pytz/zoneinfo/Asia/Choibalsan | Bin 0 -> 949 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 -> 372 bytes .../site-packages/pytz/zoneinfo/Asia/Dacca | Bin 0 -> 337 bytes .../site-packages/pytz/zoneinfo/Asia/Damascus | Bin 0 -> 2294 bytes .../site-packages/pytz/zoneinfo/Asia/Dhaka | Bin 0 -> 337 bytes .../Lib/site-packages/pytz/zoneinfo/Asia/Dili | Bin 0 -> 227 bytes .../site-packages/pytz/zoneinfo/Asia/Dubai | Bin 0 -> 165 bytes .../site-packages/pytz/zoneinfo/Asia/Dushanbe | Bin 0 -> 591 bytes .../pytz/zoneinfo/Asia/Famagusta | Bin 0 -> 2028 bytes .../Lib/site-packages/pytz/zoneinfo/Asia/Gaza | Bin 0 -> 2316 bytes .../site-packages/pytz/zoneinfo/Asia/Harbin | Bin 0 -> 561 bytes .../site-packages/pytz/zoneinfo/Asia/Hebron | Bin 0 -> 2344 bytes .../pytz/zoneinfo/Asia/Ho_Chi_Minh | Bin 0 -> 351 bytes .../pytz/zoneinfo/Asia/Hong_Kong | Bin 0 -> 1203 bytes .../Lib/site-packages/pytz/zoneinfo/Asia/Hovd | Bin 0 -> 891 bytes .../site-packages/pytz/zoneinfo/Asia/Irkutsk | Bin 0 -> 1243 bytes .../site-packages/pytz/zoneinfo/Asia/Istanbul | Bin 0 -> 1947 bytes .../site-packages/pytz/zoneinfo/Asia/Jakarta | Bin 0 -> 355 bytes .../site-packages/pytz/zoneinfo/Asia/Jayapura | Bin 0 -> 221 bytes .../pytz/zoneinfo/Asia/Jerusalem | Bin 0 -> 2288 bytes .../site-packages/pytz/zoneinfo/Asia/Kabul | Bin 0 -> 208 bytes .../pytz/zoneinfo/Asia/Kamchatka | Bin 0 -> 1166 bytes .../site-packages/pytz/zoneinfo/Asia/Karachi | Bin 0 -> 379 bytes .../site-packages/pytz/zoneinfo/Asia/Kashgar | Bin 0 -> 165 bytes .../pytz/zoneinfo/Asia/Kathmandu | Bin 0 -> 212 bytes .../site-packages/pytz/zoneinfo/Asia/Katmandu | Bin 0 -> 212 bytes .../site-packages/pytz/zoneinfo/Asia/Khandyga | Bin 0 -> 1271 bytes .../site-packages/pytz/zoneinfo/Asia/Kolkata | Bin 0 -> 285 bytes .../pytz/zoneinfo/Asia/Krasnoyarsk | Bin 0 -> 1207 bytes .../pytz/zoneinfo/Asia/Kuala_Lumpur | Bin 0 -> 383 bytes .../site-packages/pytz/zoneinfo/Asia/Kuching | Bin 0 -> 483 bytes .../site-packages/pytz/zoneinfo/Asia/Kuwait | Bin 0 -> 165 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 -> 1222 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 -> 165 bytes .../site-packages/pytz/zoneinfo/Asia/Nicosia | Bin 0 -> 2002 bytes .../pytz/zoneinfo/Asia/Novokuznetsk | Bin 0 -> 1165 bytes .../pytz/zoneinfo/Asia/Novosibirsk | Bin 0 -> 1221 bytes .../Lib/site-packages/pytz/zoneinfo/Asia/Omsk | Bin 0 -> 1207 bytes .../Lib/site-packages/pytz/zoneinfo/Asia/Oral | Bin 0 -> 1005 bytes .../pytz/zoneinfo/Asia/Phnom_Penh | Bin 0 -> 199 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 -> 199 bytes .../site-packages/pytz/zoneinfo/Asia/Qostanay | Bin 0 -> 1011 bytes .../pytz/zoneinfo/Asia/Qyzylorda | Bin 0 -> 1025 bytes .../site-packages/pytz/zoneinfo/Asia/Rangoon | Bin 0 -> 268 bytes .../site-packages/pytz/zoneinfo/Asia/Riyadh | Bin 0 -> 165 bytes .../site-packages/pytz/zoneinfo/Asia/Saigon | Bin 0 -> 351 bytes .../site-packages/pytz/zoneinfo/Asia/Sakhalin | Bin 0 -> 1202 bytes .../pytz/zoneinfo/Asia/Samarkand | Bin 0 -> 577 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 -> 383 bytes .../pytz/zoneinfo/Asia/Srednekolymsk | Bin 0 -> 1208 bytes .../site-packages/pytz/zoneinfo/Asia/Taipei | Bin 0 -> 761 bytes .../site-packages/pytz/zoneinfo/Asia/Tashkent | Bin 0 -> 591 bytes .../site-packages/pytz/zoneinfo/Asia/Tbilisi | Bin 0 -> 1035 bytes .../site-packages/pytz/zoneinfo/Asia/Tehran | Bin 0 -> 2582 bytes .../site-packages/pytz/zoneinfo/Asia/Tel_Aviv | Bin 0 -> 2288 bytes .../site-packages/pytz/zoneinfo/Asia/Thimbu | Bin 0 -> 203 bytes .../site-packages/pytz/zoneinfo/Asia/Thimphu | Bin 0 -> 203 bytes .../site-packages/pytz/zoneinfo/Asia/Tokyo | Bin 0 -> 309 bytes .../site-packages/pytz/zoneinfo/Asia/Tomsk | Bin 0 -> 1221 bytes .../pytz/zoneinfo/Asia/Ujung_Pandang | Bin 0 -> 254 bytes .../pytz/zoneinfo/Asia/Ulaanbaatar | Bin 0 -> 891 bytes .../pytz/zoneinfo/Asia/Ulan_Bator | Bin 0 -> 891 bytes .../site-packages/pytz/zoneinfo/Asia/Urumqi | Bin 0 -> 165 bytes .../site-packages/pytz/zoneinfo/Asia/Ust-Nera | Bin 0 -> 1252 bytes .../pytz/zoneinfo/Asia/Vientiane | Bin 0 -> 199 bytes .../pytz/zoneinfo/Asia/Vladivostok | Bin 0 -> 1208 bytes .../site-packages/pytz/zoneinfo/Asia/Yakutsk | Bin 0 -> 1207 bytes .../site-packages/pytz/zoneinfo/Asia/Yangon | Bin 0 -> 268 bytes .../pytz/zoneinfo/Asia/Yekaterinburg | Bin 0 -> 1243 bytes .../site-packages/pytz/zoneinfo/Asia/Yerevan | Bin 0 -> 1151 bytes .../pytz/zoneinfo/Atlantic/Azores | Bin 0 -> 3484 bytes .../pytz/zoneinfo/Atlantic/Bermuda | Bin 0 -> 1978 bytes .../pytz/zoneinfo/Atlantic/Canary | Bin 0 -> 1897 bytes .../pytz/zoneinfo/Atlantic/Cape_Verde | Bin 0 -> 270 bytes .../pytz/zoneinfo/Atlantic/Faeroe | Bin 0 -> 1815 bytes .../pytz/zoneinfo/Atlantic/Faroe | Bin 0 -> 1815 bytes .../pytz/zoneinfo/Atlantic/Jan_Mayen | Bin 0 -> 2228 bytes .../pytz/zoneinfo/Atlantic/Madeira | Bin 0 -> 3475 bytes .../pytz/zoneinfo/Atlantic/Reykjavik | Bin 0 -> 1162 bytes .../pytz/zoneinfo/Atlantic/South_Georgia | Bin 0 -> 164 bytes .../pytz/zoneinfo/Atlantic/St_Helena | Bin 0 -> 148 bytes .../pytz/zoneinfo/Atlantic/Stanley | Bin 0 -> 1214 bytes .../site-packages/pytz/zoneinfo/Australia/ACT | Bin 0 -> 2204 bytes .../pytz/zoneinfo/Australia/Adelaide | Bin 0 -> 2222 bytes .../pytz/zoneinfo/Australia/Brisbane | Bin 0 -> 433 bytes .../pytz/zoneinfo/Australia/Broken_Hill | Bin 0 -> 2243 bytes .../pytz/zoneinfo/Australia/Canberra | Bin 0 -> 2204 bytes .../pytz/zoneinfo/Australia/Currie | Bin 0 -> 2204 bytes .../pytz/zoneinfo/Australia/Darwin | Bin 0 -> 304 bytes .../pytz/zoneinfo/Australia/Eucla | Bin 0 -> 484 bytes .../pytz/zoneinfo/Australia/Hobart | Bin 0 -> 2316 bytes .../site-packages/pytz/zoneinfo/Australia/LHI | Bin 0 -> 1860 bytes .../pytz/zoneinfo/Australia/Lindeman | Bin 0 -> 489 bytes .../pytz/zoneinfo/Australia/Lord_Howe | Bin 0 -> 1860 bytes .../pytz/zoneinfo/Australia/Melbourne | Bin 0 -> 2204 bytes .../site-packages/pytz/zoneinfo/Australia/NSW | Bin 0 -> 2204 bytes .../pytz/zoneinfo/Australia/North | Bin 0 -> 304 bytes .../pytz/zoneinfo/Australia/Perth | Bin 0 -> 460 bytes .../pytz/zoneinfo/Australia/Queensland | Bin 0 -> 433 bytes .../pytz/zoneinfo/Australia/South | Bin 0 -> 2222 bytes .../pytz/zoneinfo/Australia/Sydney | Bin 0 -> 2204 bytes .../pytz/zoneinfo/Australia/Tasmania | Bin 0 -> 2316 bytes .../pytz/zoneinfo/Australia/Victoria | Bin 0 -> 2204 bytes .../pytz/zoneinfo/Australia/West | Bin 0 -> 460 bytes .../pytz/zoneinfo/Australia/Yancowinna | Bin 0 -> 2243 bytes .../site-packages/pytz/zoneinfo/Brazil/Acre | Bin 0 -> 628 bytes .../pytz/zoneinfo/Brazil/DeNoronha | Bin 0 -> 716 bytes .../site-packages/pytz/zoneinfo/Brazil/East | Bin 0 -> 1444 bytes .../site-packages/pytz/zoneinfo/Brazil/West | Bin 0 -> 604 bytes venv/Lib/site-packages/pytz/zoneinfo/CET | Bin 0 -> 2094 bytes venv/Lib/site-packages/pytz/zoneinfo/CST6CDT | Bin 0 -> 2310 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 -> 1600 bytes .../pytz/zoneinfo/Chile/Continental | Bin 0 -> 2529 bytes .../pytz/zoneinfo/Chile/EasterIsland | Bin 0 -> 2233 bytes venv/Lib/site-packages/pytz/zoneinfo/Cuba | Bin 0 -> 2416 bytes venv/Lib/site-packages/pytz/zoneinfo/EET | Bin 0 -> 1908 bytes venv/Lib/site-packages/pytz/zoneinfo/EST | Bin 0 -> 114 bytes venv/Lib/site-packages/pytz/zoneinfo/EST5EDT | Bin 0 -> 2310 bytes venv/Lib/site-packages/pytz/zoneinfo/Egypt | Bin 0 -> 1955 bytes venv/Lib/site-packages/pytz/zoneinfo/Eire | Bin 0 -> 3492 bytes venv/Lib/site-packages/pytz/zoneinfo/Etc/GMT | Bin 0 -> 114 bytes .../Lib/site-packages/pytz/zoneinfo/Etc/GMT+0 | Bin 0 -> 114 bytes .../Lib/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 .../Lib/site-packages/pytz/zoneinfo/Etc/GMT+2 | Bin 0 -> 116 bytes .../Lib/site-packages/pytz/zoneinfo/Etc/GMT+3 | Bin 0 -> 116 bytes .../Lib/site-packages/pytz/zoneinfo/Etc/GMT+4 | Bin 0 -> 116 bytes .../Lib/site-packages/pytz/zoneinfo/Etc/GMT+5 | Bin 0 -> 116 bytes .../Lib/site-packages/pytz/zoneinfo/Etc/GMT+6 | Bin 0 -> 116 bytes .../Lib/site-packages/pytz/zoneinfo/Etc/GMT+7 | Bin 0 -> 116 bytes .../Lib/site-packages/pytz/zoneinfo/Etc/GMT+8 | Bin 0 -> 116 bytes .../Lib/site-packages/pytz/zoneinfo/Etc/GMT+9 | Bin 0 -> 116 bytes .../Lib/site-packages/pytz/zoneinfo/Etc/GMT-0 | Bin 0 -> 114 bytes .../Lib/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 .../Lib/site-packages/pytz/zoneinfo/Etc/GMT-2 | Bin 0 -> 117 bytes .../Lib/site-packages/pytz/zoneinfo/Etc/GMT-3 | Bin 0 -> 117 bytes .../Lib/site-packages/pytz/zoneinfo/Etc/GMT-4 | Bin 0 -> 117 bytes .../Lib/site-packages/pytz/zoneinfo/Etc/GMT-5 | Bin 0 -> 117 bytes .../Lib/site-packages/pytz/zoneinfo/Etc/GMT-6 | Bin 0 -> 117 bytes .../Lib/site-packages/pytz/zoneinfo/Etc/GMT-7 | Bin 0 -> 117 bytes .../Lib/site-packages/pytz/zoneinfo/Etc/GMT-8 | Bin 0 -> 117 bytes .../Lib/site-packages/pytz/zoneinfo/Etc/GMT-9 | Bin 0 -> 117 bytes venv/Lib/site-packages/pytz/zoneinfo/Etc/GMT0 | Bin 0 -> 114 bytes .../site-packages/pytz/zoneinfo/Etc/Greenwich | Bin 0 -> 114 bytes venv/Lib/site-packages/pytz/zoneinfo/Etc/UCT | Bin 0 -> 114 bytes venv/Lib/site-packages/pytz/zoneinfo/Etc/UTC | Bin 0 -> 114 bytes .../site-packages/pytz/zoneinfo/Etc/Universal | Bin 0 -> 114 bytes venv/Lib/site-packages/pytz/zoneinfo/Etc/Zulu | Bin 0 -> 114 bytes .../pytz/zoneinfo/Europe/Amsterdam | Bin 0 -> 2910 bytes .../pytz/zoneinfo/Europe/Andorra | Bin 0 -> 1742 bytes .../pytz/zoneinfo/Europe/Astrakhan | Bin 0 -> 1165 bytes .../site-packages/pytz/zoneinfo/Europe/Athens | Bin 0 -> 2262 bytes .../pytz/zoneinfo/Europe/Belfast | Bin 0 -> 3648 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 -> 2137 bytes .../site-packages/pytz/zoneinfo/Europe/Dublin | Bin 0 -> 3492 bytes .../pytz/zoneinfo/Europe/Gibraltar | Bin 0 -> 3052 bytes .../pytz/zoneinfo/Europe/Guernsey | Bin 0 -> 3648 bytes .../pytz/zoneinfo/Europe/Helsinki | Bin 0 -> 1900 bytes .../pytz/zoneinfo/Europe/Isle_of_Man | Bin 0 -> 3648 bytes .../pytz/zoneinfo/Europe/Istanbul | Bin 0 -> 1947 bytes .../site-packages/pytz/zoneinfo/Europe/Jersey | Bin 0 -> 3648 bytes .../pytz/zoneinfo/Europe/Kaliningrad | Bin 0 -> 1493 bytes .../site-packages/pytz/zoneinfo/Europe/Kiev | Bin 0 -> 2088 bytes .../site-packages/pytz/zoneinfo/Europe/Kirov | Bin 0 -> 1153 bytes .../site-packages/pytz/zoneinfo/Europe/Lisbon | Bin 0 -> 3469 bytes .../pytz/zoneinfo/Europe/Ljubljana | Bin 0 -> 1920 bytes .../site-packages/pytz/zoneinfo/Europe/London | Bin 0 -> 3648 bytes .../pytz/zoneinfo/Europe/Luxembourg | Bin 0 -> 2946 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 -> 1321 bytes .../site-packages/pytz/zoneinfo/Europe/Monaco | Bin 0 -> 2944 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 -> 2228 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 -> 1215 bytes .../pytz/zoneinfo/Europe/San_Marino | Bin 0 -> 2641 bytes .../pytz/zoneinfo/Europe/Sarajevo | Bin 0 -> 1920 bytes .../pytz/zoneinfo/Europe/Saratov | Bin 0 -> 1183 bytes .../pytz/zoneinfo/Europe/Simferopol | Bin 0 -> 1453 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 -> 1909 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 -> 1267 bytes .../pytz/zoneinfo/Europe/Uzhgorod | Bin 0 -> 2050 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 -> 1165 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 -> 2106 bytes .../site-packages/pytz/zoneinfo/Europe/Zurich | Bin 0 -> 1909 bytes venv/Lib/site-packages/pytz/zoneinfo/Factory | Bin 0 -> 116 bytes venv/Lib/site-packages/pytz/zoneinfo/GB | Bin 0 -> 3648 bytes venv/Lib/site-packages/pytz/zoneinfo/GB-Eire | Bin 0 -> 3648 bytes venv/Lib/site-packages/pytz/zoneinfo/GMT | Bin 0 -> 114 bytes venv/Lib/site-packages/pytz/zoneinfo/GMT+0 | Bin 0 -> 114 bytes venv/Lib/site-packages/pytz/zoneinfo/GMT-0 | Bin 0 -> 114 bytes venv/Lib/site-packages/pytz/zoneinfo/GMT0 | Bin 0 -> 114 bytes .../Lib/site-packages/pytz/zoneinfo/Greenwich | Bin 0 -> 114 bytes venv/Lib/site-packages/pytz/zoneinfo/HST | Bin 0 -> 115 bytes venv/Lib/site-packages/pytz/zoneinfo/Hongkong | Bin 0 -> 1203 bytes venv/Lib/site-packages/pytz/zoneinfo/Iceland | Bin 0 -> 1162 bytes .../pytz/zoneinfo/Indian/Antananarivo | Bin 0 -> 251 bytes .../site-packages/pytz/zoneinfo/Indian/Chagos | Bin 0 -> 199 bytes .../pytz/zoneinfo/Indian/Christmas | Bin 0 -> 165 bytes .../site-packages/pytz/zoneinfo/Indian/Cocos | Bin 0 -> 174 bytes .../site-packages/pytz/zoneinfo/Indian/Comoro | Bin 0 -> 251 bytes .../pytz/zoneinfo/Indian/Kerguelen | Bin 0 -> 165 bytes .../site-packages/pytz/zoneinfo/Indian/Mahe | Bin 0 -> 165 bytes .../pytz/zoneinfo/Indian/Maldives | Bin 0 -> 199 bytes .../pytz/zoneinfo/Indian/Mauritius | Bin 0 -> 241 bytes .../pytz/zoneinfo/Indian/Mayotte | Bin 0 -> 251 bytes .../pytz/zoneinfo/Indian/Reunion | Bin 0 -> 165 bytes venv/Lib/site-packages/pytz/zoneinfo/Iran | Bin 0 -> 2582 bytes venv/Lib/site-packages/pytz/zoneinfo/Israel | Bin 0 -> 2288 bytes venv/Lib/site-packages/pytz/zoneinfo/Jamaica | Bin 0 -> 482 bytes venv/Lib/site-packages/pytz/zoneinfo/Japan | Bin 0 -> 309 bytes .../Lib/site-packages/pytz/zoneinfo/Kwajalein | Bin 0 -> 316 bytes venv/Lib/site-packages/pytz/zoneinfo/Libya | Bin 0 -> 625 bytes venv/Lib/site-packages/pytz/zoneinfo/MET | Bin 0 -> 2094 bytes venv/Lib/site-packages/pytz/zoneinfo/MST | Bin 0 -> 114 bytes venv/Lib/site-packages/pytz/zoneinfo/MST7MDT | Bin 0 -> 2310 bytes .../pytz/zoneinfo/Mexico/BajaNorte | Bin 0 -> 2342 bytes .../pytz/zoneinfo/Mexico/BajaSur | Bin 0 -> 1526 bytes .../pytz/zoneinfo/Mexico/General | Bin 0 -> 1584 bytes venv/Lib/site-packages/pytz/zoneinfo/NZ | Bin 0 -> 2437 bytes venv/Lib/site-packages/pytz/zoneinfo/NZ-CHAT | Bin 0 -> 2068 bytes venv/Lib/site-packages/pytz/zoneinfo/Navajo | Bin 0 -> 2444 bytes venv/Lib/site-packages/pytz/zoneinfo/PRC | Bin 0 -> 561 bytes venv/Lib/site-packages/pytz/zoneinfo/PST8PDT | Bin 0 -> 2310 bytes .../site-packages/pytz/zoneinfo/Pacific/Apia | Bin 0 -> 1097 bytes .../pytz/zoneinfo/Pacific/Auckland | Bin 0 -> 2437 bytes .../pytz/zoneinfo/Pacific/Bougainville | Bin 0 -> 268 bytes .../pytz/zoneinfo/Pacific/Chatham | Bin 0 -> 2068 bytes .../site-packages/pytz/zoneinfo/Pacific/Chuuk | Bin 0 -> 269 bytes .../pytz/zoneinfo/Pacific/Easter | Bin 0 -> 2233 bytes .../site-packages/pytz/zoneinfo/Pacific/Efate | Bin 0 -> 466 bytes .../pytz/zoneinfo/Pacific/Enderbury | Bin 0 -> 234 bytes .../pytz/zoneinfo/Pacific/Fakaofo | Bin 0 -> 200 bytes .../site-packages/pytz/zoneinfo/Pacific/Fiji | Bin 0 -> 1077 bytes .../pytz/zoneinfo/Pacific/Funafuti | Bin 0 -> 166 bytes .../pytz/zoneinfo/Pacific/Galapagos | Bin 0 -> 238 bytes .../pytz/zoneinfo/Pacific/Gambier | Bin 0 -> 164 bytes .../pytz/zoneinfo/Pacific/Guadalcanal | Bin 0 -> 166 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/Kiritimati | Bin 0 -> 238 bytes .../pytz/zoneinfo/Pacific/Kosrae | Bin 0 -> 351 bytes .../pytz/zoneinfo/Pacific/Kwajalein | Bin 0 -> 316 bytes .../pytz/zoneinfo/Pacific/Majuro | Bin 0 -> 310 bytes .../pytz/zoneinfo/Pacific/Marquesas | Bin 0 -> 173 bytes .../pytz/zoneinfo/Pacific/Midway | Bin 0 -> 175 bytes .../site-packages/pytz/zoneinfo/Pacific/Nauru | Bin 0 -> 252 bytes .../site-packages/pytz/zoneinfo/Pacific/Niue | Bin 0 -> 241 bytes .../pytz/zoneinfo/Pacific/Norfolk | Bin 0 -> 880 bytes .../pytz/zoneinfo/Pacific/Noumea | Bin 0 -> 304 bytes .../pytz/zoneinfo/Pacific/Pago_Pago | Bin 0 -> 175 bytes .../site-packages/pytz/zoneinfo/Pacific/Palau | Bin 0 -> 180 bytes .../pytz/zoneinfo/Pacific/Pitcairn | Bin 0 -> 202 bytes .../pytz/zoneinfo/Pacific/Pohnpei | Bin 0 -> 303 bytes .../pytz/zoneinfo/Pacific/Ponape | Bin 0 -> 303 bytes .../pytz/zoneinfo/Pacific/Port_Moresby | Bin 0 -> 186 bytes .../pytz/zoneinfo/Pacific/Rarotonga | Bin 0 -> 577 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 -> 165 bytes .../pytz/zoneinfo/Pacific/Tarawa | Bin 0 -> 166 bytes .../pytz/zoneinfo/Pacific/Tongatapu | Bin 0 -> 372 bytes .../site-packages/pytz/zoneinfo/Pacific/Truk | Bin 0 -> 269 bytes .../site-packages/pytz/zoneinfo/Pacific/Wake | Bin 0 -> 166 bytes .../pytz/zoneinfo/Pacific/Wallis | Bin 0 -> 166 bytes .../site-packages/pytz/zoneinfo/Pacific/Yap | Bin 0 -> 269 bytes venv/Lib/site-packages/pytz/zoneinfo/Poland | Bin 0 -> 2654 bytes venv/Lib/site-packages/pytz/zoneinfo/Portugal | Bin 0 -> 3469 bytes venv/Lib/site-packages/pytz/zoneinfo/ROC | Bin 0 -> 761 bytes venv/Lib/site-packages/pytz/zoneinfo/ROK | Bin 0 -> 617 bytes .../Lib/site-packages/pytz/zoneinfo/Singapore | Bin 0 -> 383 bytes venv/Lib/site-packages/pytz/zoneinfo/Turkey | Bin 0 -> 1947 bytes venv/Lib/site-packages/pytz/zoneinfo/UCT | Bin 0 -> 114 bytes .../Lib/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 -> 328 bytes .../site-packages/pytz/zoneinfo/US/Central | Bin 0 -> 3576 bytes .../pytz/zoneinfo/US/East-Indiana | Bin 0 -> 1666 bytes .../site-packages/pytz/zoneinfo/US/Eastern | Bin 0 -> 3536 bytes .../Lib/site-packages/pytz/zoneinfo/US/Hawaii | Bin 0 -> 329 bytes .../pytz/zoneinfo/US/Indiana-Starke | Bin 0 -> 2428 bytes .../site-packages/pytz/zoneinfo/US/Michigan | Bin 0 -> 2230 bytes .../site-packages/pytz/zoneinfo/US/Mountain | Bin 0 -> 2444 bytes .../site-packages/pytz/zoneinfo/US/Pacific | Bin 0 -> 2836 bytes venv/Lib/site-packages/pytz/zoneinfo/US/Samoa | Bin 0 -> 175 bytes venv/Lib/site-packages/pytz/zoneinfo/UTC | Bin 0 -> 114 bytes .../Lib/site-packages/pytz/zoneinfo/Universal | Bin 0 -> 114 bytes venv/Lib/site-packages/pytz/zoneinfo/W-SU | Bin 0 -> 1535 bytes venv/Lib/site-packages/pytz/zoneinfo/WET | Bin 0 -> 1905 bytes venv/Lib/site-packages/pytz/zoneinfo/Zulu | Bin 0 -> 114 bytes .../site-packages/pytz/zoneinfo/iso3166.tab | 274 + .../site-packages/pytz/zoneinfo/leapseconds | 78 + .../site-packages/pytz/zoneinfo/posixrules | Bin 0 -> 3536 bytes .../Lib/site-packages/pytz/zoneinfo/tzdata.zi | 4410 +++++++++ venv/Lib/site-packages/pytz/zoneinfo/zone.tab | 452 + .../site-packages/pytz/zoneinfo/zone1970.tab | 384 + .../requests-2.11.1.dist-info/DESCRIPTION.rst | 1294 --- .../requests-2.11.1.dist-info/METADATA | 1323 --- .../requests-2.11.1.dist-info/RECORD | 170 - .../requests-2.11.1.dist-info/metadata.json | 1 - .../requests-2.24.0.dist-info/DESCRIPTION.rst | 136 + .../requests-2.24.0.dist-info/INSTALLER | 1 + .../requests-2.24.0.dist-info/LICENSE.txt | 13 + .../requests-2.24.0.dist-info/METADATA | 177 + .../requests-2.24.0.dist-info/RECORD | 44 + .../requests-2.24.0.dist-info/WHEEL | 6 + .../requests-2.24.0.dist-info/metadata.json | 1 + .../top_level.txt | 0 venv/Lib/site-packages/requests/__init__.py | 107 +- .../__pycache__/__init__.cpython-36.pyc | Bin 2509 -> 3505 bytes .../__pycache__/__version__.cpython-36.pyc | Bin 0 -> 606 bytes .../_internal_utils.cpython-36.pyc | Bin 0 -> 1359 bytes .../__pycache__/adapters.cpython-36.pyc | Bin 15858 -> 16878 bytes .../requests/__pycache__/api.cpython-36.pyc | Bin 6089 -> 6788 bytes .../requests/__pycache__/auth.cpython-36.pyc | Bin 7203 -> 8403 bytes .../requests/__pycache__/certs.cpython-36.pyc | Bin 875 -> 672 bytes .../__pycache__/compat.cpython-36.pyc | Bin 1543 -> 1706 bytes .../__pycache__/cookies.cpython-36.pyc | Bin 18527 -> 18838 bytes .../__pycache__/exceptions.cpython-36.pyc | Bin 4931 -> 5543 bytes .../requests/__pycache__/help.cpython-36.pyc | Bin 0 -> 2679 bytes .../requests/__pycache__/hooks.cpython-36.pyc | Bin 1048 -> 1031 bytes .../__pycache__/models.cpython-36.pyc | Bin 21962 -> 24146 bytes .../__pycache__/packages.cpython-36.pyc | Bin 0 -> 483 bytes .../__pycache__/sessions.cpython-36.pyc | Bin 18020 -> 19482 bytes .../__pycache__/status_codes.cpython-36.pyc | Bin 3709 -> 4888 bytes .../__pycache__/structures.cpython-36.pyc | Bin 4456 -> 4460 bytes .../requests/__pycache__/utils.cpython-36.pyc | Bin 18908 -> 22345 bytes .../Lib/site-packages/requests/__version__.py | 14 + .../site-packages/requests/_internal_utils.py | 42 + venv/Lib/site-packages/requests/adapters.py | 106 +- venv/Lib/site-packages/requests/api.py | 55 +- venv/Lib/site-packages/requests/auth.py | 63 +- venv/Lib/site-packages/requests/certs.py | 13 +- venv/Lib/site-packages/requests/compat.py | 20 +- venv/Lib/site-packages/requests/cookies.py | 53 +- venv/Lib/site-packages/requests/exceptions.py | 19 +- venv/Lib/site-packages/requests/help.py | 119 + venv/Lib/site-packages/requests/hooks.py | 4 +- venv/Lib/site-packages/requests/models.py | 221 +- venv/Lib/site-packages/requests/packages.py | 14 + .../requests/packages/__init__.py | 36 - .../__pycache__/__init__.cpython-36.pyc | Bin 1654 -> 0 bytes .../__pycache__/__init__.cpython-36.pyc | Bin 747 -> 0 bytes .../__pycache__/big5freq.cpython-36.pyc | Bin 141841 -> 0 bytes .../__pycache__/big5prober.cpython-36.pyc | Bin 1009 -> 0 bytes .../__pycache__/chardetect.cpython-36.pyc | Bin 3038 -> 0 bytes .../chardistribution.cpython-36.pyc | Bin 6231 -> 0 bytes .../charsetgroupprober.cpython-36.pyc | Bin 2075 -> 0 bytes .../__pycache__/charsetprober.cpython-36.pyc | Bin 1826 -> 0 bytes .../codingstatemachine.cpython-36.pyc | Bin 1546 -> 0 bytes .../chardet/__pycache__/compat.cpython-36.pyc | Bin 555 -> 0 bytes .../__pycache__/constants.cpython-36.pyc | Bin 410 -> 0 bytes .../__pycache__/cp949prober.cpython-36.pyc | Bin 1016 -> 0 bytes .../__pycache__/escprober.cpython-36.pyc | Bin 1996 -> 0 bytes .../chardet/__pycache__/escsm.cpython-36.pyc | Bin 6966 -> 0 bytes .../__pycache__/eucjpprober.cpython-36.pyc | Bin 2307 -> 0 bytes .../__pycache__/euckrfreq.cpython-36.pyc | Bin 88881 -> 0 bytes .../__pycache__/euckrprober.cpython-36.pyc | Bin 1017 -> 0 bytes .../__pycache__/euctwprober.cpython-36.pyc | Bin 1017 -> 0 bytes .../__pycache__/gb2312prober.cpython-36.pyc | Bin 1023 -> 0 bytes .../__pycache__/hebrewprober.cpython-36.pyc | Bin 2811 -> 0 bytes .../chardet/__pycache__/jpcntx.cpython-36.pyc | Bin 38618 -> 0 bytes .../__pycache__/latin1prober.cpython-36.pyc | Bin 2843 -> 0 bytes .../mbcharsetprober.cpython-36.pyc | Bin 2034 -> 0 bytes .../mbcsgroupprober.cpython-36.pyc | Bin 1120 -> 0 bytes .../chardet/__pycache__/mbcssm.cpython-36.pyc | Bin 16663 -> 0 bytes .../sbcharsetprober.cpython-36.pyc | Bin 2793 -> 0 bytes .../sbcsgroupprober.cpython-36.pyc | Bin 1684 -> 0 bytes .../__pycache__/sjisprober.cpython-36.pyc | Bin 2340 -> 0 bytes .../universaldetector.cpython-36.pyc | Bin 3320 -> 0 bytes .../__pycache__/utf8prober.cpython-36.pyc | Bin 1839 -> 0 bytes .../requests/packages/chardet/big5freq.py | 925 -- .../packages/chardet/charsetgroupprober.py | 106 - .../packages/chardet/charsetprober.py | 62 - .../packages/chardet/codingstatemachine.py | 61 - .../requests/packages/chardet/constants.py | 39 - .../requests/packages/chardet/escprober.py | 86 - .../requests/packages/chardet/escsm.py | 242 - .../requests/packages/chardet/eucjpprober.py | 90 - .../requests/packages/chardet/euckrfreq.py | 596 -- .../packages/chardet/mbcharsetprober.py | 86 - .../requests/packages/chardet/mbcssm.py | 572 -- .../packages/chardet/sbcharsetprober.py | 120 - .../requests/packages/chardet/sjisprober.py | 91 - .../packages/chardet/universaldetector.py | 170 - .../__pycache__/__init__.cpython-36.pyc | Bin 2577 -> 0 bytes .../__pycache__/_collections.cpython-36.pyc | Bin 10660 -> 0 bytes .../__pycache__/connection.cpython-36.pyc | Bin 8519 -> 0 bytes .../__pycache__/connectionpool.cpython-36.pyc | Bin 22803 -> 0 bytes .../__pycache__/exceptions.cpython-36.pyc | Bin 8976 -> 0 bytes .../urllib3/__pycache__/fields.cpython-36.pyc | Bin 5934 -> 0 bytes .../__pycache__/filepost.cpython-36.pyc | Bin 2737 -> 0 bytes .../__pycache__/poolmanager.cpython-36.pyc | Bin 10923 -> 0 bytes .../__pycache__/response.cpython-36.pyc | Bin 13856 -> 0 bytes .../requests/packages/urllib3/connection.py | 330 - .../__pycache__/__init__.cpython-36.pyc | Bin 268 -> 0 bytes .../__pycache__/appengine.cpython-36.pyc | Bin 6736 -> 0 bytes .../__pycache__/ntlmpool.cpython-36.pyc | Bin 3365 -> 0 bytes .../__pycache__/pyopenssl.cpython-36.pyc | Bin 10209 -> 0 bytes .../contrib/__pycache__/socks.cpython-36.pyc | Bin 4583 -> 0 bytes .../packages/urllib3/contrib/appengine.py | 231 - .../packages/urllib3/contrib/ntlmpool.py | 115 - .../packages/urllib3/contrib/pyopenssl.py | 358 - .../packages/urllib3/contrib/socks.py | 172 - .../requests/packages/urllib3/fields.py | 178 - .../__pycache__/__init__.cpython-36.pyc | Bin 394 -> 0 bytes .../__pycache__/ordered_dict.cpython-36.pyc | Bin 8471 -> 0 bytes .../packages/__pycache__/six.cpython-36.pyc | Bin 24566 -> 0 bytes .../packages/urllib3/packages/ordered_dict.py | 259 - .../__pycache__/__init__.cpython-36.pyc | Bin 555 -> 0 bytes .../_implementation.cpython-36.pyc | Bin 2379 -> 0 bytes .../ssl_match_hostname/_implementation.py | 105 - .../requests/packages/urllib3/poolmanager.py | 367 - .../packages/urllib3/util/__init__.py | 46 - .../util/__pycache__/__init__.cpython-36.pyc | Bin 1066 -> 0 bytes .../__pycache__/connection.cpython-36.pyc | Bin 3352 -> 0 bytes .../util/__pycache__/request.cpython-36.pyc | Bin 2051 -> 0 bytes .../util/__pycache__/response.cpython-36.pyc | Bin 1923 -> 0 bytes .../util/__pycache__/retry.cpython-36.pyc | Bin 9207 -> 0 bytes .../util/__pycache__/ssl_.cpython-36.pyc | Bin 8832 -> 0 bytes .../util/__pycache__/url.cpython-36.pyc | Bin 4987 -> 0 bytes .../requests/packages/urllib3/util/request.py | 72 - .../requests/packages/urllib3/util/ssl_.py | 320 - .../requests/packages/urllib3/util/url.py | 217 - venv/Lib/site-packages/requests/sessions.py | 327 +- .../site-packages/requests/status_codes.py | 42 +- venv/Lib/site-packages/requests/structures.py | 10 +- venv/Lib/site-packages/requests/utils.py | 311 +- .../uritemplate-3.0.1.dist-info/AUTHORS.rst | 15 + .../uritemplate-3.0.1.dist-info/INSTALLER | 1 + .../uritemplate-3.0.1.dist-info/LICENSE | 3 + .../LICENSE.APACHE | 202 + .../uritemplate-3.0.1.dist-info/LICENSE.BSD | 23 + .../uritemplate-3.0.1.dist-info/METADATA | 175 + .../uritemplate-3.0.1.dist-info/RECORD | 19 + .../uritemplate-3.0.1.dist-info/WHEEL | 6 + .../uritemplate-3.0.1.dist-info/top_level.txt | 1 + .../Lib/site-packages/uritemplate/__init__.py | 26 + .../__pycache__/__init__.cpython-36.pyc | Bin 0 -> 1027 bytes .../__pycache__/api.cpython-36.pyc | Bin 0 -> 2353 bytes .../__pycache__/orderedset.cpython-36.pyc | Bin 0 -> 2911 bytes .../__pycache__/template.cpython-36.pyc | Bin 0 -> 4872 bytes .../__pycache__/variable.cpython-36.pyc | Bin 0 -> 10431 bytes venv/Lib/site-packages/uritemplate/api.py | 73 + .../site-packages/uritemplate/orderedset.py | 90 + .../Lib/site-packages/uritemplate/template.py | 152 + .../Lib/site-packages/uritemplate/variable.py | 386 + .../urllib3-1.25.10.dist-info/INSTALLER | 1 + .../urllib3-1.25.10.dist-info/LICENSE.txt | 21 + .../urllib3-1.25.10.dist-info/METADATA | 1281 +++ .../urllib3-1.25.10.dist-info/RECORD | 80 + .../urllib3-1.25.10.dist-info/WHEEL | 6 + .../urllib3-1.25.10.dist-info/top_level.txt | 1 + .../packages => }/urllib3/__init__.py | 65 +- .../__pycache__/__init__.cpython-36.pyc | Bin 0 -> 2273 bytes .../__pycache__/_collections.cpython-36.pyc | Bin 0 -> 10743 bytes .../__pycache__/_version.cpython-36.pyc | Bin 0 -> 265 bytes .../__pycache__/connection.cpython-36.pyc | Bin 0 -> 10308 bytes .../__pycache__/connectionpool.cpython-36.pyc | Bin 0 -> 24053 bytes .../__pycache__/exceptions.cpython-36.pyc | Bin 0 -> 11177 bytes .../urllib3/__pycache__/fields.cpython-36.pyc | Bin 0 -> 8155 bytes .../__pycache__/filepost.cpython-36.pyc | Bin 0 -> 2811 bytes .../__pycache__/poolmanager.cpython-36.pyc | Bin 0 -> 13830 bytes .../__pycache__/request.cpython-36.pyc | Bin 5679 -> 5643 bytes .../__pycache__/response.cpython-36.pyc | Bin 0 -> 20593 bytes .../packages => }/urllib3/_collections.py | 86 +- venv/Lib/site-packages/urllib3/_version.py | 2 + venv/Lib/site-packages/urllib3/connection.py | 424 + .../packages => }/urllib3/connectionpool.py | 531 +- .../site-packages/urllib3/contrib/__init__.py | 0 .../__pycache__/__init__.cpython-36.pyc | Bin 0 -> 250 bytes .../_appengine_environ.cpython-36.pyc | Bin 0 -> 1459 bytes .../__pycache__/appengine.cpython-36.pyc | Bin 0 -> 8207 bytes .../__pycache__/ntlmpool.cpython-36.pyc | Bin 0 -> 3296 bytes .../__pycache__/pyopenssl.cpython-36.pyc | Bin 0 -> 15029 bytes .../securetransport.cpython-36.pyc | Bin 0 -> 19776 bytes .../contrib/__pycache__/socks.cpython-36.pyc | Bin 0 -> 5566 bytes .../urllib3/contrib/_appengine_environ.py | 36 + .../contrib/_securetransport/__init__.py | 0 .../__pycache__/__init__.cpython-36.pyc | Bin 0 -> 267 bytes .../__pycache__/bindings.cpython-36.pyc | Bin 0 -> 10767 bytes .../__pycache__/low_level.cpython-36.pyc | Bin 0 -> 7511 bytes .../contrib/_securetransport/bindings.py | 510 + .../contrib/_securetransport/low_level.py | 328 + .../urllib3/contrib/appengine.py | 314 + .../site-packages/urllib3/contrib/ntlmpool.py | 121 + .../urllib3/contrib/pyopenssl.py | 501 + .../urllib3/contrib/securetransport.py | 864 ++ .../site-packages/urllib3/contrib/socks.py | 210 + .../packages => }/urllib3/exceptions.py | 77 +- venv/Lib/site-packages/urllib3/fields.py | 273 + .../packages => }/urllib3/filepost.py | 22 +- .../urllib3/packages/__init__.py | 2 +- .../__pycache__/__init__.cpython-36.pyc | Bin 0 -> 376 bytes .../packages/__pycache__/six.cpython-36.pyc | Bin 0 -> 26603 bytes .../urllib3/packages/backports/__init__.py | 0 .../__pycache__/__init__.cpython-36.pyc | Bin 0 -> 261 bytes .../__pycache__/makefile.cpython-36.pyc | Bin 0 -> 1351 bytes .../urllib3/packages/backports/makefile.py | 52 + .../packages => }/urllib3/packages/six.py | 323 +- .../packages/ssl_match_hostname/__init__.py | 10 +- .../__pycache__/__init__.cpython-36.pyc | Bin 0 -> 637 bytes .../_implementation.cpython-36.pyc | Bin 0 -> 3344 bytes .../ssl_match_hostname/_implementation.py | 160 + venv/Lib/site-packages/urllib3/poolmanager.py | 492 + .../packages => }/urllib3/request.py | 90 +- .../packages => }/urllib3/response.py | 434 +- .../site-packages/urllib3/util/__init__.py | 46 + .../util/__pycache__/__init__.cpython-36.pyc | Bin 0 -> 1215 bytes .../__pycache__/connection.cpython-36.pyc | Bin 0 -> 3219 bytes .../util/__pycache__/queue.cpython-36.pyc | Bin 0 -> 1091 bytes .../util/__pycache__/request.cpython-36.pyc | Bin 0 -> 3385 bytes .../util/__pycache__/response.cpython-36.pyc | Bin 0 -> 2018 bytes .../util/__pycache__/retry.cpython-36.pyc | Bin 0 -> 13001 bytes .../util/__pycache__/ssl_.cpython-36.pyc | Bin 0 -> 10214 bytes .../util/__pycache__/timeout.cpython-36.pyc | Bin 8838 -> 8895 bytes .../util/__pycache__/url.cpython-36.pyc | Bin 0 -> 10660 bytes .../util/__pycache__/wait.cpython-36.pyc | Bin 0 -> 3201 bytes .../packages => }/urllib3/util/connection.py | 58 +- venv/Lib/site-packages/urllib3/util/queue.py | 21 + .../Lib/site-packages/urllib3/util/request.py | 135 + .../packages => }/urllib3/util/response.py | 26 +- .../packages => }/urllib3/util/retry.py | 227 +- venv/Lib/site-packages/urllib3/util/ssl_.py | 421 + .../packages => }/urllib3/util/timeout.py | 99 +- venv/Lib/site-packages/urllib3/util/url.py | 430 + venv/Lib/site-packages/urllib3/util/wait.py | 153 + venv/Scripts/chardetect.exe | Bin 0 -> 97237 bytes venv/Scripts/doesitcache.exe | Bin 0 -> 97232 bytes 1868 files changed, 192402 insertions(+), 13278 deletions(-) create mode 100644 vehicleantitheftrecognition-firebase-adminsdk-krrgw-05da515de5.json create mode 100644 venv/Lib/site-packages/CacheControl-0.12.6.dist-info/DESCRIPTION.rst rename venv/Lib/site-packages/{requests-2.11.1.dist-info => CacheControl-0.12.6.dist-info}/INSTALLER (100%) create mode 100644 venv/Lib/site-packages/CacheControl-0.12.6.dist-info/METADATA create mode 100644 venv/Lib/site-packages/CacheControl-0.12.6.dist-info/RECORD rename venv/Lib/site-packages/{requests-2.11.1.dist-info => CacheControl-0.12.6.dist-info}/WHEEL (70%) create mode 100644 venv/Lib/site-packages/CacheControl-0.12.6.dist-info/entry_points.txt create mode 100644 venv/Lib/site-packages/CacheControl-0.12.6.dist-info/metadata.json create mode 100644 venv/Lib/site-packages/CacheControl-0.12.6.dist-info/top_level.txt create mode 100644 venv/Lib/site-packages/__pycache__/google_auth_httplib2.cpython-36.pyc create mode 100644 venv/Lib/site-packages/_cffi_backend.cp36-win32.pyd create mode 100644 venv/Lib/site-packages/apiclient/__init__.py create mode 100644 venv/Lib/site-packages/apiclient/__pycache__/__init__.cpython-36.pyc create mode 100644 venv/Lib/site-packages/cachecontrol/__init__.py create mode 100644 venv/Lib/site-packages/cachecontrol/__pycache__/__init__.cpython-36.pyc create mode 100644 venv/Lib/site-packages/cachecontrol/__pycache__/_cmd.cpython-36.pyc create mode 100644 venv/Lib/site-packages/cachecontrol/__pycache__/adapter.cpython-36.pyc create mode 100644 venv/Lib/site-packages/cachecontrol/__pycache__/cache.cpython-36.pyc create mode 100644 venv/Lib/site-packages/cachecontrol/__pycache__/compat.cpython-36.pyc create mode 100644 venv/Lib/site-packages/cachecontrol/__pycache__/controller.cpython-36.pyc create mode 100644 venv/Lib/site-packages/cachecontrol/__pycache__/filewrapper.cpython-36.pyc create mode 100644 venv/Lib/site-packages/cachecontrol/__pycache__/heuristics.cpython-36.pyc create mode 100644 venv/Lib/site-packages/cachecontrol/__pycache__/serialize.cpython-36.pyc create mode 100644 venv/Lib/site-packages/cachecontrol/__pycache__/wrapper.cpython-36.pyc create mode 100644 venv/Lib/site-packages/cachecontrol/_cmd.py create mode 100644 venv/Lib/site-packages/cachecontrol/adapter.py create mode 100644 venv/Lib/site-packages/cachecontrol/cache.py create mode 100644 venv/Lib/site-packages/cachecontrol/caches/__init__.py create mode 100644 venv/Lib/site-packages/cachecontrol/caches/__pycache__/__init__.cpython-36.pyc create mode 100644 venv/Lib/site-packages/cachecontrol/caches/__pycache__/file_cache.cpython-36.pyc create mode 100644 venv/Lib/site-packages/cachecontrol/caches/__pycache__/redis_cache.cpython-36.pyc create mode 100644 venv/Lib/site-packages/cachecontrol/caches/file_cache.py create mode 100644 venv/Lib/site-packages/cachecontrol/caches/redis_cache.py create mode 100644 venv/Lib/site-packages/cachecontrol/compat.py create mode 100644 venv/Lib/site-packages/cachecontrol/controller.py create mode 100644 venv/Lib/site-packages/cachecontrol/filewrapper.py create mode 100644 venv/Lib/site-packages/cachecontrol/heuristics.py create mode 100644 venv/Lib/site-packages/cachecontrol/serialize.py create mode 100644 venv/Lib/site-packages/cachecontrol/wrapper.py create mode 100644 venv/Lib/site-packages/cachetools-4.1.1.dist-info/INSTALLER create mode 100644 venv/Lib/site-packages/cachetools-4.1.1.dist-info/LICENSE create mode 100644 venv/Lib/site-packages/cachetools-4.1.1.dist-info/METADATA create mode 100644 venv/Lib/site-packages/cachetools-4.1.1.dist-info/RECORD create mode 100644 venv/Lib/site-packages/cachetools-4.1.1.dist-info/WHEEL create mode 100644 venv/Lib/site-packages/cachetools-4.1.1.dist-info/top_level.txt create mode 100644 venv/Lib/site-packages/cachetools/__init__.py create mode 100644 venv/Lib/site-packages/cachetools/__pycache__/__init__.cpython-36.pyc create mode 100644 venv/Lib/site-packages/cachetools/__pycache__/abc.cpython-36.pyc create mode 100644 venv/Lib/site-packages/cachetools/__pycache__/cache.cpython-36.pyc create mode 100644 venv/Lib/site-packages/cachetools/__pycache__/decorators.cpython-36.pyc create mode 100644 venv/Lib/site-packages/cachetools/__pycache__/func.cpython-36.pyc create mode 100644 venv/Lib/site-packages/cachetools/__pycache__/keys.cpython-36.pyc create mode 100644 venv/Lib/site-packages/cachetools/__pycache__/lfu.cpython-36.pyc create mode 100644 venv/Lib/site-packages/cachetools/__pycache__/lru.cpython-36.pyc create mode 100644 venv/Lib/site-packages/cachetools/__pycache__/rr.cpython-36.pyc create mode 100644 venv/Lib/site-packages/cachetools/__pycache__/ttl.cpython-36.pyc create mode 100644 venv/Lib/site-packages/cachetools/abc.py create mode 100644 venv/Lib/site-packages/cachetools/cache.py create mode 100644 venv/Lib/site-packages/cachetools/decorators.py create mode 100644 venv/Lib/site-packages/cachetools/func.py create mode 100644 venv/Lib/site-packages/cachetools/keys.py create mode 100644 venv/Lib/site-packages/cachetools/lfu.py create mode 100644 venv/Lib/site-packages/cachetools/lru.py create mode 100644 venv/Lib/site-packages/cachetools/rr.py create mode 100644 venv/Lib/site-packages/cachetools/ttl.py create mode 100644 venv/Lib/site-packages/certifi-2020.6.20.dist-info/INSTALLER create mode 100644 venv/Lib/site-packages/certifi-2020.6.20.dist-info/LICENSE create mode 100644 venv/Lib/site-packages/certifi-2020.6.20.dist-info/METADATA create mode 100644 venv/Lib/site-packages/certifi-2020.6.20.dist-info/RECORD create mode 100644 venv/Lib/site-packages/certifi-2020.6.20.dist-info/WHEEL create mode 100644 venv/Lib/site-packages/certifi-2020.6.20.dist-info/top_level.txt create mode 100644 venv/Lib/site-packages/certifi/__init__.py create mode 100644 venv/Lib/site-packages/certifi/__main__.py create mode 100644 venv/Lib/site-packages/certifi/__pycache__/__init__.cpython-36.pyc create mode 100644 venv/Lib/site-packages/certifi/__pycache__/__main__.cpython-36.pyc create mode 100644 venv/Lib/site-packages/certifi/__pycache__/core.cpython-36.pyc create mode 100644 venv/Lib/site-packages/certifi/cacert.pem create mode 100644 venv/Lib/site-packages/certifi/core.py create mode 100644 venv/Lib/site-packages/cffi-1.14.3.dist-info/INSTALLER create mode 100644 venv/Lib/site-packages/cffi-1.14.3.dist-info/LICENSE create mode 100644 venv/Lib/site-packages/cffi-1.14.3.dist-info/METADATA create mode 100644 venv/Lib/site-packages/cffi-1.14.3.dist-info/RECORD create mode 100644 venv/Lib/site-packages/cffi-1.14.3.dist-info/WHEEL create mode 100644 venv/Lib/site-packages/cffi-1.14.3.dist-info/entry_points.txt create mode 100644 venv/Lib/site-packages/cffi-1.14.3.dist-info/top_level.txt create mode 100644 venv/Lib/site-packages/cffi/__init__.py create mode 100644 venv/Lib/site-packages/cffi/__pycache__/__init__.cpython-36.pyc create mode 100644 venv/Lib/site-packages/cffi/__pycache__/api.cpython-36.pyc create mode 100644 venv/Lib/site-packages/cffi/__pycache__/backend_ctypes.cpython-36.pyc create mode 100644 venv/Lib/site-packages/cffi/__pycache__/cffi_opcode.cpython-36.pyc create mode 100644 venv/Lib/site-packages/cffi/__pycache__/commontypes.cpython-36.pyc create mode 100644 venv/Lib/site-packages/cffi/__pycache__/cparser.cpython-36.pyc create mode 100644 venv/Lib/site-packages/cffi/__pycache__/error.cpython-36.pyc create mode 100644 venv/Lib/site-packages/cffi/__pycache__/ffiplatform.cpython-36.pyc create mode 100644 venv/Lib/site-packages/cffi/__pycache__/lock.cpython-36.pyc create mode 100644 venv/Lib/site-packages/cffi/__pycache__/model.cpython-36.pyc create mode 100644 venv/Lib/site-packages/cffi/__pycache__/pkgconfig.cpython-36.pyc create mode 100644 venv/Lib/site-packages/cffi/__pycache__/recompiler.cpython-36.pyc create mode 100644 venv/Lib/site-packages/cffi/__pycache__/setuptools_ext.cpython-36.pyc create mode 100644 venv/Lib/site-packages/cffi/__pycache__/vengine_cpy.cpython-36.pyc create mode 100644 venv/Lib/site-packages/cffi/__pycache__/vengine_gen.cpython-36.pyc create mode 100644 venv/Lib/site-packages/cffi/__pycache__/verifier.cpython-36.pyc create mode 100644 venv/Lib/site-packages/cffi/_cffi_errors.h create mode 100644 venv/Lib/site-packages/cffi/_cffi_include.h create mode 100644 venv/Lib/site-packages/cffi/_embedding.h create mode 100644 venv/Lib/site-packages/cffi/api.py create mode 100644 venv/Lib/site-packages/cffi/backend_ctypes.py create mode 100644 venv/Lib/site-packages/cffi/cffi_opcode.py create mode 100644 venv/Lib/site-packages/cffi/commontypes.py create mode 100644 venv/Lib/site-packages/cffi/cparser.py create mode 100644 venv/Lib/site-packages/cffi/error.py create mode 100644 venv/Lib/site-packages/cffi/ffiplatform.py create mode 100644 venv/Lib/site-packages/cffi/lock.py create mode 100644 venv/Lib/site-packages/cffi/model.py create mode 100644 venv/Lib/site-packages/cffi/parse_c_type.h create mode 100644 venv/Lib/site-packages/cffi/pkgconfig.py create mode 100644 venv/Lib/site-packages/cffi/recompiler.py create mode 100644 venv/Lib/site-packages/cffi/setuptools_ext.py create mode 100644 venv/Lib/site-packages/cffi/vengine_cpy.py create mode 100644 venv/Lib/site-packages/cffi/vengine_gen.py create mode 100644 venv/Lib/site-packages/cffi/verifier.py create mode 100644 venv/Lib/site-packages/chardet-3.0.4.dist-info/DESCRIPTION.rst create mode 100644 venv/Lib/site-packages/chardet-3.0.4.dist-info/INSTALLER create mode 100644 venv/Lib/site-packages/chardet-3.0.4.dist-info/METADATA create mode 100644 venv/Lib/site-packages/chardet-3.0.4.dist-info/RECORD create mode 100644 venv/Lib/site-packages/chardet-3.0.4.dist-info/WHEEL create mode 100644 venv/Lib/site-packages/chardet-3.0.4.dist-info/entry_points.txt create mode 100644 venv/Lib/site-packages/chardet-3.0.4.dist-info/metadata.json create mode 100644 venv/Lib/site-packages/chardet-3.0.4.dist-info/top_level.txt rename venv/Lib/site-packages/{requests/packages => }/chardet/__init__.py (55%) create mode 100644 venv/Lib/site-packages/chardet/__pycache__/__init__.cpython-36.pyc create mode 100644 venv/Lib/site-packages/chardet/__pycache__/big5freq.cpython-36.pyc create mode 100644 venv/Lib/site-packages/chardet/__pycache__/big5prober.cpython-36.pyc create mode 100644 venv/Lib/site-packages/chardet/__pycache__/chardistribution.cpython-36.pyc create mode 100644 venv/Lib/site-packages/chardet/__pycache__/charsetgroupprober.cpython-36.pyc create mode 100644 venv/Lib/site-packages/chardet/__pycache__/charsetprober.cpython-36.pyc create mode 100644 venv/Lib/site-packages/chardet/__pycache__/codingstatemachine.cpython-36.pyc create mode 100644 venv/Lib/site-packages/chardet/__pycache__/compat.cpython-36.pyc create mode 100644 venv/Lib/site-packages/chardet/__pycache__/cp949prober.cpython-36.pyc create mode 100644 venv/Lib/site-packages/chardet/__pycache__/enums.cpython-36.pyc create mode 100644 venv/Lib/site-packages/chardet/__pycache__/escprober.cpython-36.pyc create mode 100644 venv/Lib/site-packages/chardet/__pycache__/escsm.cpython-36.pyc create mode 100644 venv/Lib/site-packages/chardet/__pycache__/eucjpprober.cpython-36.pyc create mode 100644 venv/Lib/site-packages/chardet/__pycache__/euckrfreq.cpython-36.pyc create mode 100644 venv/Lib/site-packages/chardet/__pycache__/euckrprober.cpython-36.pyc rename venv/Lib/site-packages/{requests/packages => }/chardet/__pycache__/euctwfreq.cpython-36.pyc (87%) create mode 100644 venv/Lib/site-packages/chardet/__pycache__/euctwprober.cpython-36.pyc rename venv/Lib/site-packages/{requests/packages => }/chardet/__pycache__/gb2312freq.cpython-36.pyc (54%) create mode 100644 venv/Lib/site-packages/chardet/__pycache__/gb2312prober.cpython-36.pyc create mode 100644 venv/Lib/site-packages/chardet/__pycache__/hebrewprober.cpython-36.pyc rename venv/Lib/site-packages/{requests/packages => }/chardet/__pycache__/jisfreq.cpython-36.pyc (52%) create mode 100644 venv/Lib/site-packages/chardet/__pycache__/jpcntx.cpython-36.pyc rename venv/Lib/site-packages/{requests/packages => }/chardet/__pycache__/langbulgarianmodel.cpython-36.pyc (93%) rename venv/Lib/site-packages/{requests/packages => }/chardet/__pycache__/langcyrillicmodel.cpython-36.pyc (94%) rename venv/Lib/site-packages/{requests/packages => }/chardet/__pycache__/langgreekmodel.cpython-36.pyc (93%) rename venv/Lib/site-packages/{requests/packages => }/chardet/__pycache__/langhebrewmodel.cpython-36.pyc (92%) rename venv/Lib/site-packages/{requests/packages => }/chardet/__pycache__/langhungarianmodel.cpython-36.pyc (95%) rename venv/Lib/site-packages/{requests/packages => }/chardet/__pycache__/langthaimodel.cpython-36.pyc (93%) create mode 100644 venv/Lib/site-packages/chardet/__pycache__/langturkishmodel.cpython-36.pyc create mode 100644 venv/Lib/site-packages/chardet/__pycache__/latin1prober.cpython-36.pyc create mode 100644 venv/Lib/site-packages/chardet/__pycache__/mbcharsetprober.cpython-36.pyc create mode 100644 venv/Lib/site-packages/chardet/__pycache__/mbcsgroupprober.cpython-36.pyc create mode 100644 venv/Lib/site-packages/chardet/__pycache__/mbcssm.cpython-36.pyc create mode 100644 venv/Lib/site-packages/chardet/__pycache__/sbcharsetprober.cpython-36.pyc create mode 100644 venv/Lib/site-packages/chardet/__pycache__/sbcsgroupprober.cpython-36.pyc create mode 100644 venv/Lib/site-packages/chardet/__pycache__/sjisprober.cpython-36.pyc create mode 100644 venv/Lib/site-packages/chardet/__pycache__/universaldetector.cpython-36.pyc create mode 100644 venv/Lib/site-packages/chardet/__pycache__/utf8prober.cpython-36.pyc create mode 100644 venv/Lib/site-packages/chardet/__pycache__/version.cpython-36.pyc create mode 100644 venv/Lib/site-packages/chardet/big5freq.py rename venv/Lib/site-packages/{requests/packages => }/chardet/big5prober.py (82%) rename venv/Lib/site-packages/{requests/packages => }/chardet/chardistribution.py (61%) create mode 100644 venv/Lib/site-packages/chardet/charsetgroupprober.py create mode 100644 venv/Lib/site-packages/chardet/charsetprober.py create mode 100644 venv/Lib/site-packages/chardet/cli/__init__.py create mode 100644 venv/Lib/site-packages/chardet/cli/__pycache__/__init__.cpython-36.pyc create mode 100644 venv/Lib/site-packages/chardet/cli/__pycache__/chardetect.cpython-36.pyc rename venv/Lib/site-packages/{requests/packages/chardet => chardet/cli}/chardetect.py (83%) create mode 100644 venv/Lib/site-packages/chardet/codingstatemachine.py rename venv/Lib/site-packages/{requests/packages => }/chardet/compat.py (85%) rename venv/Lib/site-packages/{requests/packages => }/chardet/cp949prober.py (83%) create mode 100644 venv/Lib/site-packages/chardet/enums.py create mode 100644 venv/Lib/site-packages/chardet/escprober.py create mode 100644 venv/Lib/site-packages/chardet/escsm.py create mode 100644 venv/Lib/site-packages/chardet/eucjpprober.py create mode 100644 venv/Lib/site-packages/chardet/euckrfreq.py rename venv/Lib/site-packages/{requests/packages => }/chardet/euckrprober.py (82%) rename venv/Lib/site-packages/{requests/packages => }/chardet/euctwfreq.py (66%) rename venv/Lib/site-packages/{requests/packages => }/chardet/euctwprober.py (82%) rename venv/Lib/site-packages/{requests/packages => }/chardet/gb2312freq.py (57%) rename venv/Lib/site-packages/{requests/packages => }/chardet/gb2312prober.py (81%) rename venv/Lib/site-packages/{requests/packages => }/chardet/hebrewprober.py (76%) rename venv/Lib/site-packages/{requests/packages => }/chardet/jisfreq.py (54%) rename venv/Lib/site-packages/{requests/packages => }/chardet/jpcntx.py (87%) rename venv/Lib/site-packages/{requests/packages => }/chardet/langbulgarianmodel.py (96%) rename venv/Lib/site-packages/{requests/packages => }/chardet/langcyrillicmodel.py (91%) rename venv/Lib/site-packages/{requests/packages => }/chardet/langgreekmodel.py (96%) rename venv/Lib/site-packages/{requests/packages => }/chardet/langhebrewmodel.py (97%) rename venv/Lib/site-packages/{requests/packages => }/chardet/langhungarianmodel.py (96%) rename venv/Lib/site-packages/{requests/packages => }/chardet/langthaimodel.py (98%) create mode 100644 venv/Lib/site-packages/chardet/langturkishmodel.py rename venv/Lib/site-packages/{requests/packages => }/chardet/latin1prober.py (81%) create mode 100644 venv/Lib/site-packages/chardet/mbcharsetprober.py rename venv/Lib/site-packages/{requests/packages => }/chardet/mbcsgroupprober.py (93%) create mode 100644 venv/Lib/site-packages/chardet/mbcssm.py create mode 100644 venv/Lib/site-packages/chardet/sbcharsetprober.py rename venv/Lib/site-packages/{requests/packages => }/chardet/sbcsgroupprober.py (70%) create mode 100644 venv/Lib/site-packages/chardet/sjisprober.py create mode 100644 venv/Lib/site-packages/chardet/universaldetector.py rename venv/Lib/site-packages/{requests/packages => }/chardet/utf8prober.py (56%) create mode 100644 venv/Lib/site-packages/chardet/version.py create mode 100644 venv/Lib/site-packages/firebase_admin-4.4.0.dist-info/INSTALLER create mode 100644 venv/Lib/site-packages/firebase_admin-4.4.0.dist-info/LICENSE create mode 100644 venv/Lib/site-packages/firebase_admin-4.4.0.dist-info/METADATA create mode 100644 venv/Lib/site-packages/firebase_admin-4.4.0.dist-info/RECORD rename venv/Lib/site-packages/{requests/packages/urllib3/contrib/__init__.py => firebase_admin-4.4.0.dist-info/REQUESTED} (100%) create mode 100644 venv/Lib/site-packages/firebase_admin-4.4.0.dist-info/WHEEL create mode 100644 venv/Lib/site-packages/firebase_admin-4.4.0.dist-info/top_level.txt create mode 100644 venv/Lib/site-packages/firebase_admin/__about__.py create mode 100644 venv/Lib/site-packages/firebase_admin/__init__.py create mode 100644 venv/Lib/site-packages/firebase_admin/__pycache__/__about__.cpython-36.pyc create mode 100644 venv/Lib/site-packages/firebase_admin/__pycache__/__init__.cpython-36.pyc create mode 100644 venv/Lib/site-packages/firebase_admin/__pycache__/_auth_client.cpython-36.pyc create mode 100644 venv/Lib/site-packages/firebase_admin/__pycache__/_auth_providers.cpython-36.pyc create mode 100644 venv/Lib/site-packages/firebase_admin/__pycache__/_auth_utils.cpython-36.pyc create mode 100644 venv/Lib/site-packages/firebase_admin/__pycache__/_http_client.cpython-36.pyc create mode 100644 venv/Lib/site-packages/firebase_admin/__pycache__/_messaging_encoder.cpython-36.pyc create mode 100644 venv/Lib/site-packages/firebase_admin/__pycache__/_messaging_utils.cpython-36.pyc create mode 100644 venv/Lib/site-packages/firebase_admin/__pycache__/_rfc3339.cpython-36.pyc create mode 100644 venv/Lib/site-packages/firebase_admin/__pycache__/_sseclient.cpython-36.pyc create mode 100644 venv/Lib/site-packages/firebase_admin/__pycache__/_token_gen.cpython-36.pyc create mode 100644 venv/Lib/site-packages/firebase_admin/__pycache__/_user_identifier.cpython-36.pyc create mode 100644 venv/Lib/site-packages/firebase_admin/__pycache__/_user_import.cpython-36.pyc create mode 100644 venv/Lib/site-packages/firebase_admin/__pycache__/_user_mgt.cpython-36.pyc create mode 100644 venv/Lib/site-packages/firebase_admin/__pycache__/_utils.cpython-36.pyc create mode 100644 venv/Lib/site-packages/firebase_admin/__pycache__/auth.cpython-36.pyc create mode 100644 venv/Lib/site-packages/firebase_admin/__pycache__/credentials.cpython-36.pyc create mode 100644 venv/Lib/site-packages/firebase_admin/__pycache__/db.cpython-36.pyc create mode 100644 venv/Lib/site-packages/firebase_admin/__pycache__/exceptions.cpython-36.pyc create mode 100644 venv/Lib/site-packages/firebase_admin/__pycache__/firestore.cpython-36.pyc create mode 100644 venv/Lib/site-packages/firebase_admin/__pycache__/instance_id.cpython-36.pyc create mode 100644 venv/Lib/site-packages/firebase_admin/__pycache__/messaging.cpython-36.pyc create mode 100644 venv/Lib/site-packages/firebase_admin/__pycache__/ml.cpython-36.pyc create mode 100644 venv/Lib/site-packages/firebase_admin/__pycache__/project_management.cpython-36.pyc create mode 100644 venv/Lib/site-packages/firebase_admin/__pycache__/storage.cpython-36.pyc create mode 100644 venv/Lib/site-packages/firebase_admin/__pycache__/tenant_mgt.cpython-36.pyc create mode 100644 venv/Lib/site-packages/firebase_admin/_auth_client.py create mode 100644 venv/Lib/site-packages/firebase_admin/_auth_providers.py create mode 100644 venv/Lib/site-packages/firebase_admin/_auth_utils.py create mode 100644 venv/Lib/site-packages/firebase_admin/_http_client.py create mode 100644 venv/Lib/site-packages/firebase_admin/_messaging_encoder.py create mode 100644 venv/Lib/site-packages/firebase_admin/_messaging_utils.py create mode 100644 venv/Lib/site-packages/firebase_admin/_rfc3339.py create mode 100644 venv/Lib/site-packages/firebase_admin/_sseclient.py create mode 100644 venv/Lib/site-packages/firebase_admin/_token_gen.py create mode 100644 venv/Lib/site-packages/firebase_admin/_user_identifier.py create mode 100644 venv/Lib/site-packages/firebase_admin/_user_import.py create mode 100644 venv/Lib/site-packages/firebase_admin/_user_mgt.py create mode 100644 venv/Lib/site-packages/firebase_admin/_utils.py create mode 100644 venv/Lib/site-packages/firebase_admin/auth.py create mode 100644 venv/Lib/site-packages/firebase_admin/credentials.py create mode 100644 venv/Lib/site-packages/firebase_admin/db.py create mode 100644 venv/Lib/site-packages/firebase_admin/exceptions.py create mode 100644 venv/Lib/site-packages/firebase_admin/firestore.py create mode 100644 venv/Lib/site-packages/firebase_admin/instance_id.py create mode 100644 venv/Lib/site-packages/firebase_admin/messaging.py create mode 100644 venv/Lib/site-packages/firebase_admin/ml.py create mode 100644 venv/Lib/site-packages/firebase_admin/project_management.py create mode 100644 venv/Lib/site-packages/firebase_admin/storage.py create mode 100644 venv/Lib/site-packages/firebase_admin/tenant_mgt.py create mode 100644 venv/Lib/site-packages/google/_async_resumable_media/__init__.py create mode 100644 venv/Lib/site-packages/google/_async_resumable_media/__pycache__/__init__.cpython-36.pyc create mode 100644 venv/Lib/site-packages/google/_async_resumable_media/__pycache__/_download.cpython-36.pyc create mode 100644 venv/Lib/site-packages/google/_async_resumable_media/__pycache__/_helpers.cpython-36.pyc create mode 100644 venv/Lib/site-packages/google/_async_resumable_media/__pycache__/_upload.cpython-36.pyc create mode 100644 venv/Lib/site-packages/google/_async_resumable_media/_download.py create mode 100644 venv/Lib/site-packages/google/_async_resumable_media/_helpers.py create mode 100644 venv/Lib/site-packages/google/_async_resumable_media/_upload.py create mode 100644 venv/Lib/site-packages/google/_async_resumable_media/requests/__init__.py create mode 100644 venv/Lib/site-packages/google/_async_resumable_media/requests/__pycache__/__init__.cpython-36.pyc create mode 100644 venv/Lib/site-packages/google/_async_resumable_media/requests/__pycache__/_request_helpers.cpython-36.pyc create mode 100644 venv/Lib/site-packages/google/_async_resumable_media/requests/__pycache__/download.cpython-36.pyc create mode 100644 venv/Lib/site-packages/google/_async_resumable_media/requests/__pycache__/upload.cpython-36.pyc create mode 100644 venv/Lib/site-packages/google/_async_resumable_media/requests/_request_helpers.py create mode 100644 venv/Lib/site-packages/google/_async_resumable_media/requests/download.py create mode 100644 venv/Lib/site-packages/google/_async_resumable_media/requests/upload.py create mode 100644 venv/Lib/site-packages/google/api_core/__init__.py create mode 100644 venv/Lib/site-packages/google/api_core/__pycache__/__init__.cpython-36.pyc create mode 100644 venv/Lib/site-packages/google/api_core/__pycache__/bidi.cpython-36.pyc create mode 100644 venv/Lib/site-packages/google/api_core/__pycache__/client_info.cpython-36.pyc create mode 100644 venv/Lib/site-packages/google/api_core/__pycache__/client_options.cpython-36.pyc create mode 100644 venv/Lib/site-packages/google/api_core/__pycache__/datetime_helpers.cpython-36.pyc create mode 100644 venv/Lib/site-packages/google/api_core/__pycache__/exceptions.cpython-36.pyc create mode 100644 venv/Lib/site-packages/google/api_core/__pycache__/general_helpers.cpython-36.pyc create mode 100644 venv/Lib/site-packages/google/api_core/__pycache__/grpc_helpers.cpython-36.pyc create mode 100644 venv/Lib/site-packages/google/api_core/__pycache__/grpc_helpers_async.cpython-36.pyc create mode 100644 venv/Lib/site-packages/google/api_core/__pycache__/iam.cpython-36.pyc create mode 100644 venv/Lib/site-packages/google/api_core/__pycache__/operation.cpython-36.pyc create mode 100644 venv/Lib/site-packages/google/api_core/__pycache__/operation_async.cpython-36.pyc create mode 100644 venv/Lib/site-packages/google/api_core/__pycache__/page_iterator.cpython-36.pyc create mode 100644 venv/Lib/site-packages/google/api_core/__pycache__/page_iterator_async.cpython-36.pyc create mode 100644 venv/Lib/site-packages/google/api_core/__pycache__/path_template.cpython-36.pyc create mode 100644 venv/Lib/site-packages/google/api_core/__pycache__/protobuf_helpers.cpython-36.pyc create mode 100644 venv/Lib/site-packages/google/api_core/__pycache__/retry.cpython-36.pyc create mode 100644 venv/Lib/site-packages/google/api_core/__pycache__/retry_async.cpython-36.pyc create mode 100644 venv/Lib/site-packages/google/api_core/__pycache__/timeout.cpython-36.pyc create mode 100644 venv/Lib/site-packages/google/api_core/__pycache__/version.cpython-36.pyc create mode 100644 venv/Lib/site-packages/google/api_core/bidi.py create mode 100644 venv/Lib/site-packages/google/api_core/client_info.py create mode 100644 venv/Lib/site-packages/google/api_core/client_options.py create mode 100644 venv/Lib/site-packages/google/api_core/datetime_helpers.py create mode 100644 venv/Lib/site-packages/google/api_core/exceptions.py create mode 100644 venv/Lib/site-packages/google/api_core/future/__init__.py create mode 100644 venv/Lib/site-packages/google/api_core/future/__pycache__/__init__.cpython-36.pyc create mode 100644 venv/Lib/site-packages/google/api_core/future/__pycache__/_helpers.cpython-36.pyc create mode 100644 venv/Lib/site-packages/google/api_core/future/__pycache__/async_future.cpython-36.pyc create mode 100644 venv/Lib/site-packages/google/api_core/future/__pycache__/base.cpython-36.pyc create mode 100644 venv/Lib/site-packages/google/api_core/future/__pycache__/polling.cpython-36.pyc create mode 100644 venv/Lib/site-packages/google/api_core/future/_helpers.py create mode 100644 venv/Lib/site-packages/google/api_core/future/async_future.py create mode 100644 venv/Lib/site-packages/google/api_core/future/base.py create mode 100644 venv/Lib/site-packages/google/api_core/future/polling.py create mode 100644 venv/Lib/site-packages/google/api_core/gapic_v1/__init__.py create mode 100644 venv/Lib/site-packages/google/api_core/gapic_v1/__pycache__/__init__.cpython-36.pyc create mode 100644 venv/Lib/site-packages/google/api_core/gapic_v1/__pycache__/client_info.cpython-36.pyc create mode 100644 venv/Lib/site-packages/google/api_core/gapic_v1/__pycache__/config.cpython-36.pyc create mode 100644 venv/Lib/site-packages/google/api_core/gapic_v1/__pycache__/config_async.cpython-36.pyc create mode 100644 venv/Lib/site-packages/google/api_core/gapic_v1/__pycache__/method.cpython-36.pyc create mode 100644 venv/Lib/site-packages/google/api_core/gapic_v1/__pycache__/method_async.cpython-36.pyc create mode 100644 venv/Lib/site-packages/google/api_core/gapic_v1/__pycache__/routing_header.cpython-36.pyc create mode 100644 venv/Lib/site-packages/google/api_core/gapic_v1/client_info.py create mode 100644 venv/Lib/site-packages/google/api_core/gapic_v1/config.py create mode 100644 venv/Lib/site-packages/google/api_core/gapic_v1/config_async.py create mode 100644 venv/Lib/site-packages/google/api_core/gapic_v1/method.py create mode 100644 venv/Lib/site-packages/google/api_core/gapic_v1/method_async.py create mode 100644 venv/Lib/site-packages/google/api_core/gapic_v1/routing_header.py create mode 100644 venv/Lib/site-packages/google/api_core/general_helpers.py create mode 100644 venv/Lib/site-packages/google/api_core/grpc_helpers.py create mode 100644 venv/Lib/site-packages/google/api_core/grpc_helpers_async.py create mode 100644 venv/Lib/site-packages/google/api_core/iam.py create mode 100644 venv/Lib/site-packages/google/api_core/operation.py create mode 100644 venv/Lib/site-packages/google/api_core/operation_async.py create mode 100644 venv/Lib/site-packages/google/api_core/operations_v1/__init__.py create mode 100644 venv/Lib/site-packages/google/api_core/operations_v1/__pycache__/__init__.cpython-36.pyc create mode 100644 venv/Lib/site-packages/google/api_core/operations_v1/__pycache__/operations_async_client.cpython-36.pyc create mode 100644 venv/Lib/site-packages/google/api_core/operations_v1/__pycache__/operations_client.cpython-36.pyc create mode 100644 venv/Lib/site-packages/google/api_core/operations_v1/__pycache__/operations_client_config.cpython-36.pyc create mode 100644 venv/Lib/site-packages/google/api_core/operations_v1/operations_async_client.py create mode 100644 venv/Lib/site-packages/google/api_core/operations_v1/operations_client.py create mode 100644 venv/Lib/site-packages/google/api_core/operations_v1/operations_client_config.py create mode 100644 venv/Lib/site-packages/google/api_core/page_iterator.py create mode 100644 venv/Lib/site-packages/google/api_core/page_iterator_async.py create mode 100644 venv/Lib/site-packages/google/api_core/path_template.py create mode 100644 venv/Lib/site-packages/google/api_core/protobuf_helpers.py create mode 100644 venv/Lib/site-packages/google/api_core/retry.py create mode 100644 venv/Lib/site-packages/google/api_core/retry_async.py create mode 100644 venv/Lib/site-packages/google/api_core/timeout.py create mode 100644 venv/Lib/site-packages/google/api_core/version.py create mode 100644 venv/Lib/site-packages/google/auth/__init__.py create mode 100644 venv/Lib/site-packages/google/auth/__pycache__/__init__.cpython-36.pyc create mode 100644 venv/Lib/site-packages/google/auth/__pycache__/_cloud_sdk.cpython-36.pyc create mode 100644 venv/Lib/site-packages/google/auth/__pycache__/_credentials_async.cpython-36.pyc create mode 100644 venv/Lib/site-packages/google/auth/__pycache__/_default.cpython-36.pyc create mode 100644 venv/Lib/site-packages/google/auth/__pycache__/_default_async.cpython-36.pyc create mode 100644 venv/Lib/site-packages/google/auth/__pycache__/_helpers.cpython-36.pyc create mode 100644 venv/Lib/site-packages/google/auth/__pycache__/_jwt_async.cpython-36.pyc create mode 100644 venv/Lib/site-packages/google/auth/__pycache__/_oauth2client.cpython-36.pyc create mode 100644 venv/Lib/site-packages/google/auth/__pycache__/_service_account_info.cpython-36.pyc create mode 100644 venv/Lib/site-packages/google/auth/__pycache__/app_engine.cpython-36.pyc create mode 100644 venv/Lib/site-packages/google/auth/__pycache__/credentials.cpython-36.pyc create mode 100644 venv/Lib/site-packages/google/auth/__pycache__/environment_vars.cpython-36.pyc create mode 100644 venv/Lib/site-packages/google/auth/__pycache__/exceptions.cpython-36.pyc create mode 100644 venv/Lib/site-packages/google/auth/__pycache__/iam.cpython-36.pyc create mode 100644 venv/Lib/site-packages/google/auth/__pycache__/impersonated_credentials.cpython-36.pyc create mode 100644 venv/Lib/site-packages/google/auth/__pycache__/jwt.cpython-36.pyc create mode 100644 venv/Lib/site-packages/google/auth/_cloud_sdk.py create mode 100644 venv/Lib/site-packages/google/auth/_credentials_async.py create mode 100644 venv/Lib/site-packages/google/auth/_default.py create mode 100644 venv/Lib/site-packages/google/auth/_default_async.py create mode 100644 venv/Lib/site-packages/google/auth/_helpers.py create mode 100644 venv/Lib/site-packages/google/auth/_jwt_async.py create mode 100644 venv/Lib/site-packages/google/auth/_oauth2client.py create mode 100644 venv/Lib/site-packages/google/auth/_service_account_info.py create mode 100644 venv/Lib/site-packages/google/auth/app_engine.py create mode 100644 venv/Lib/site-packages/google/auth/compute_engine/__init__.py create mode 100644 venv/Lib/site-packages/google/auth/compute_engine/__pycache__/__init__.cpython-36.pyc create mode 100644 venv/Lib/site-packages/google/auth/compute_engine/__pycache__/_metadata.cpython-36.pyc create mode 100644 venv/Lib/site-packages/google/auth/compute_engine/__pycache__/credentials.cpython-36.pyc create mode 100644 venv/Lib/site-packages/google/auth/compute_engine/_metadata.py create mode 100644 venv/Lib/site-packages/google/auth/compute_engine/credentials.py create mode 100644 venv/Lib/site-packages/google/auth/credentials.py create mode 100644 venv/Lib/site-packages/google/auth/crypt/__init__.py create mode 100644 venv/Lib/site-packages/google/auth/crypt/__pycache__/__init__.cpython-36.pyc create mode 100644 venv/Lib/site-packages/google/auth/crypt/__pycache__/_cryptography_rsa.cpython-36.pyc create mode 100644 venv/Lib/site-packages/google/auth/crypt/__pycache__/_helpers.cpython-36.pyc create mode 100644 venv/Lib/site-packages/google/auth/crypt/__pycache__/_python_rsa.cpython-36.pyc create mode 100644 venv/Lib/site-packages/google/auth/crypt/__pycache__/base.cpython-36.pyc create mode 100644 venv/Lib/site-packages/google/auth/crypt/__pycache__/es256.cpython-36.pyc create mode 100644 venv/Lib/site-packages/google/auth/crypt/__pycache__/rsa.cpython-36.pyc create mode 100644 venv/Lib/site-packages/google/auth/crypt/_cryptography_rsa.py create mode 100644 venv/Lib/site-packages/google/auth/crypt/_helpers.py create mode 100644 venv/Lib/site-packages/google/auth/crypt/_python_rsa.py create mode 100644 venv/Lib/site-packages/google/auth/crypt/base.py create mode 100644 venv/Lib/site-packages/google/auth/crypt/es256.py create mode 100644 venv/Lib/site-packages/google/auth/crypt/rsa.py create mode 100644 venv/Lib/site-packages/google/auth/environment_vars.py create mode 100644 venv/Lib/site-packages/google/auth/exceptions.py create mode 100644 venv/Lib/site-packages/google/auth/iam.py create mode 100644 venv/Lib/site-packages/google/auth/impersonated_credentials.py create mode 100644 venv/Lib/site-packages/google/auth/jwt.py create mode 100644 venv/Lib/site-packages/google/auth/transport/__init__.py create mode 100644 venv/Lib/site-packages/google/auth/transport/__pycache__/__init__.cpython-36.pyc create mode 100644 venv/Lib/site-packages/google/auth/transport/__pycache__/_aiohttp_requests.cpython-36.pyc create mode 100644 venv/Lib/site-packages/google/auth/transport/__pycache__/_http_client.cpython-36.pyc create mode 100644 venv/Lib/site-packages/google/auth/transport/__pycache__/_mtls_helper.cpython-36.pyc create mode 100644 venv/Lib/site-packages/google/auth/transport/__pycache__/grpc.cpython-36.pyc create mode 100644 venv/Lib/site-packages/google/auth/transport/__pycache__/mtls.cpython-36.pyc create mode 100644 venv/Lib/site-packages/google/auth/transport/__pycache__/requests.cpython-36.pyc create mode 100644 venv/Lib/site-packages/google/auth/transport/__pycache__/urllib3.cpython-36.pyc create mode 100644 venv/Lib/site-packages/google/auth/transport/_aiohttp_requests.py create mode 100644 venv/Lib/site-packages/google/auth/transport/_http_client.py create mode 100644 venv/Lib/site-packages/google/auth/transport/_mtls_helper.py create mode 100644 venv/Lib/site-packages/google/auth/transport/grpc.py create mode 100644 venv/Lib/site-packages/google/auth/transport/mtls.py create mode 100644 venv/Lib/site-packages/google/auth/transport/requests.py create mode 100644 venv/Lib/site-packages/google/auth/transport/urllib3.py create mode 100644 venv/Lib/site-packages/google/cloud/__pycache__/_helpers.cpython-36.pyc create mode 100644 venv/Lib/site-packages/google/cloud/__pycache__/_http.cpython-36.pyc create mode 100644 venv/Lib/site-packages/google/cloud/__pycache__/_testing.cpython-36.pyc create mode 100644 venv/Lib/site-packages/google/cloud/__pycache__/client.cpython-36.pyc create mode 100644 venv/Lib/site-packages/google/cloud/__pycache__/environment_vars.cpython-36.pyc create mode 100644 venv/Lib/site-packages/google/cloud/__pycache__/exceptions.cpython-36.pyc create mode 100644 venv/Lib/site-packages/google/cloud/__pycache__/firestore.cpython-36.pyc create mode 100644 venv/Lib/site-packages/google/cloud/__pycache__/obsolete.cpython-36.pyc create mode 100644 venv/Lib/site-packages/google/cloud/__pycache__/operation.cpython-36.pyc create mode 100644 venv/Lib/site-packages/google/cloud/__pycache__/version.cpython-36.pyc create mode 100644 venv/Lib/site-packages/google/cloud/_helpers.py create mode 100644 venv/Lib/site-packages/google/cloud/_http.py create mode 100644 venv/Lib/site-packages/google/cloud/_testing.py create mode 100644 venv/Lib/site-packages/google/cloud/client.py create mode 100644 venv/Lib/site-packages/google/cloud/environment_vars.py create mode 100644 venv/Lib/site-packages/google/cloud/exceptions.py create mode 100644 venv/Lib/site-packages/google/cloud/firestore.py create mode 100644 venv/Lib/site-packages/google/cloud/firestore_admin_v1/__init__.py create mode 100644 venv/Lib/site-packages/google/cloud/firestore_admin_v1/__pycache__/__init__.cpython-36.pyc create mode 100644 venv/Lib/site-packages/google/cloud/firestore_admin_v1/__pycache__/types.cpython-36.pyc create mode 100644 venv/Lib/site-packages/google/cloud/firestore_admin_v1/gapic/__init__.py create mode 100644 venv/Lib/site-packages/google/cloud/firestore_admin_v1/gapic/__pycache__/__init__.cpython-36.pyc create mode 100644 venv/Lib/site-packages/google/cloud/firestore_admin_v1/gapic/__pycache__/enums.cpython-36.pyc create mode 100644 venv/Lib/site-packages/google/cloud/firestore_admin_v1/gapic/__pycache__/firestore_admin_client.cpython-36.pyc create mode 100644 venv/Lib/site-packages/google/cloud/firestore_admin_v1/gapic/__pycache__/firestore_admin_client_config.cpython-36.pyc create mode 100644 venv/Lib/site-packages/google/cloud/firestore_admin_v1/gapic/enums.py create mode 100644 venv/Lib/site-packages/google/cloud/firestore_admin_v1/gapic/firestore_admin_client.py create mode 100644 venv/Lib/site-packages/google/cloud/firestore_admin_v1/gapic/firestore_admin_client_config.py create mode 100644 venv/Lib/site-packages/google/cloud/firestore_admin_v1/gapic/transports/__init__.py create mode 100644 venv/Lib/site-packages/google/cloud/firestore_admin_v1/gapic/transports/__pycache__/__init__.cpython-36.pyc create mode 100644 venv/Lib/site-packages/google/cloud/firestore_admin_v1/gapic/transports/__pycache__/firestore_admin_grpc_transport.cpython-36.pyc create mode 100644 venv/Lib/site-packages/google/cloud/firestore_admin_v1/gapic/transports/firestore_admin_grpc_transport.py create mode 100644 venv/Lib/site-packages/google/cloud/firestore_admin_v1/proto/__init__.py create mode 100644 venv/Lib/site-packages/google/cloud/firestore_admin_v1/proto/__pycache__/__init__.cpython-36.pyc create mode 100644 venv/Lib/site-packages/google/cloud/firestore_admin_v1/proto/__pycache__/field_pb2.cpython-36.pyc create mode 100644 venv/Lib/site-packages/google/cloud/firestore_admin_v1/proto/__pycache__/field_pb2_grpc.cpython-36.pyc create mode 100644 venv/Lib/site-packages/google/cloud/firestore_admin_v1/proto/__pycache__/firestore_admin_pb2.cpython-36.pyc create mode 100644 venv/Lib/site-packages/google/cloud/firestore_admin_v1/proto/__pycache__/firestore_admin_pb2_grpc.cpython-36.pyc create mode 100644 venv/Lib/site-packages/google/cloud/firestore_admin_v1/proto/__pycache__/index_pb2.cpython-36.pyc create mode 100644 venv/Lib/site-packages/google/cloud/firestore_admin_v1/proto/__pycache__/index_pb2_grpc.cpython-36.pyc create mode 100644 venv/Lib/site-packages/google/cloud/firestore_admin_v1/proto/__pycache__/location_pb2.cpython-36.pyc create mode 100644 venv/Lib/site-packages/google/cloud/firestore_admin_v1/proto/__pycache__/location_pb2_grpc.cpython-36.pyc create mode 100644 venv/Lib/site-packages/google/cloud/firestore_admin_v1/proto/__pycache__/operation_pb2.cpython-36.pyc create mode 100644 venv/Lib/site-packages/google/cloud/firestore_admin_v1/proto/__pycache__/operation_pb2_grpc.cpython-36.pyc create mode 100644 venv/Lib/site-packages/google/cloud/firestore_admin_v1/proto/field.proto create mode 100644 venv/Lib/site-packages/google/cloud/firestore_admin_v1/proto/field_pb2.py create mode 100644 venv/Lib/site-packages/google/cloud/firestore_admin_v1/proto/field_pb2_grpc.py create mode 100644 venv/Lib/site-packages/google/cloud/firestore_admin_v1/proto/firestore_admin.proto create mode 100644 venv/Lib/site-packages/google/cloud/firestore_admin_v1/proto/firestore_admin_pb2.py create mode 100644 venv/Lib/site-packages/google/cloud/firestore_admin_v1/proto/firestore_admin_pb2_grpc.py create mode 100644 venv/Lib/site-packages/google/cloud/firestore_admin_v1/proto/index.proto create mode 100644 venv/Lib/site-packages/google/cloud/firestore_admin_v1/proto/index_pb2.py create mode 100644 venv/Lib/site-packages/google/cloud/firestore_admin_v1/proto/index_pb2_grpc.py create mode 100644 venv/Lib/site-packages/google/cloud/firestore_admin_v1/proto/location.proto create mode 100644 venv/Lib/site-packages/google/cloud/firestore_admin_v1/proto/location_pb2.py create mode 100644 venv/Lib/site-packages/google/cloud/firestore_admin_v1/proto/location_pb2_grpc.py create mode 100644 venv/Lib/site-packages/google/cloud/firestore_admin_v1/proto/operation.proto create mode 100644 venv/Lib/site-packages/google/cloud/firestore_admin_v1/proto/operation_pb2.py create mode 100644 venv/Lib/site-packages/google/cloud/firestore_admin_v1/proto/operation_pb2_grpc.py create mode 100644 venv/Lib/site-packages/google/cloud/firestore_admin_v1/types.py create mode 100644 venv/Lib/site-packages/google/cloud/firestore_v1/__init__.py create mode 100644 venv/Lib/site-packages/google/cloud/firestore_v1/__pycache__/__init__.cpython-36.pyc create mode 100644 venv/Lib/site-packages/google/cloud/firestore_v1/__pycache__/_helpers.cpython-36.pyc create mode 100644 venv/Lib/site-packages/google/cloud/firestore_v1/__pycache__/batch.cpython-36.pyc create mode 100644 venv/Lib/site-packages/google/cloud/firestore_v1/__pycache__/client.cpython-36.pyc create mode 100644 venv/Lib/site-packages/google/cloud/firestore_v1/__pycache__/collection.cpython-36.pyc create mode 100644 venv/Lib/site-packages/google/cloud/firestore_v1/__pycache__/document.cpython-36.pyc create mode 100644 venv/Lib/site-packages/google/cloud/firestore_v1/__pycache__/field_path.cpython-36.pyc create mode 100644 venv/Lib/site-packages/google/cloud/firestore_v1/__pycache__/order.cpython-36.pyc create mode 100644 venv/Lib/site-packages/google/cloud/firestore_v1/__pycache__/query.cpython-36.pyc create mode 100644 venv/Lib/site-packages/google/cloud/firestore_v1/__pycache__/transaction.cpython-36.pyc create mode 100644 venv/Lib/site-packages/google/cloud/firestore_v1/__pycache__/transforms.cpython-36.pyc create mode 100644 venv/Lib/site-packages/google/cloud/firestore_v1/__pycache__/types.cpython-36.pyc create mode 100644 venv/Lib/site-packages/google/cloud/firestore_v1/__pycache__/watch.cpython-36.pyc create mode 100644 venv/Lib/site-packages/google/cloud/firestore_v1/_helpers.py create mode 100644 venv/Lib/site-packages/google/cloud/firestore_v1/batch.py create mode 100644 venv/Lib/site-packages/google/cloud/firestore_v1/client.py create mode 100644 venv/Lib/site-packages/google/cloud/firestore_v1/collection.py create mode 100644 venv/Lib/site-packages/google/cloud/firestore_v1/document.py create mode 100644 venv/Lib/site-packages/google/cloud/firestore_v1/field_path.py create mode 100644 venv/Lib/site-packages/google/cloud/firestore_v1/gapic/__init__.py create mode 100644 venv/Lib/site-packages/google/cloud/firestore_v1/gapic/__pycache__/__init__.cpython-36.pyc create mode 100644 venv/Lib/site-packages/google/cloud/firestore_v1/gapic/__pycache__/enums.cpython-36.pyc create mode 100644 venv/Lib/site-packages/google/cloud/firestore_v1/gapic/__pycache__/firestore_client.cpython-36.pyc create mode 100644 venv/Lib/site-packages/google/cloud/firestore_v1/gapic/__pycache__/firestore_client_config.cpython-36.pyc create mode 100644 venv/Lib/site-packages/google/cloud/firestore_v1/gapic/enums.py create mode 100644 venv/Lib/site-packages/google/cloud/firestore_v1/gapic/firestore_client.py create mode 100644 venv/Lib/site-packages/google/cloud/firestore_v1/gapic/firestore_client_config.py create mode 100644 venv/Lib/site-packages/google/cloud/firestore_v1/gapic/transports/__init__.py create mode 100644 venv/Lib/site-packages/google/cloud/firestore_v1/gapic/transports/__pycache__/__init__.cpython-36.pyc create mode 100644 venv/Lib/site-packages/google/cloud/firestore_v1/gapic/transports/__pycache__/firestore_grpc_transport.cpython-36.pyc create mode 100644 venv/Lib/site-packages/google/cloud/firestore_v1/gapic/transports/firestore_grpc_transport.py create mode 100644 venv/Lib/site-packages/google/cloud/firestore_v1/order.py create mode 100644 venv/Lib/site-packages/google/cloud/firestore_v1/proto/__init__.py create mode 100644 venv/Lib/site-packages/google/cloud/firestore_v1/proto/__pycache__/__init__.cpython-36.pyc create mode 100644 venv/Lib/site-packages/google/cloud/firestore_v1/proto/__pycache__/common_pb2.cpython-36.pyc create mode 100644 venv/Lib/site-packages/google/cloud/firestore_v1/proto/__pycache__/common_pb2_grpc.cpython-36.pyc create mode 100644 venv/Lib/site-packages/google/cloud/firestore_v1/proto/__pycache__/document_pb2.cpython-36.pyc create mode 100644 venv/Lib/site-packages/google/cloud/firestore_v1/proto/__pycache__/document_pb2_grpc.cpython-36.pyc create mode 100644 venv/Lib/site-packages/google/cloud/firestore_v1/proto/__pycache__/firestore_pb2.cpython-36.pyc create mode 100644 venv/Lib/site-packages/google/cloud/firestore_v1/proto/__pycache__/firestore_pb2_grpc.cpython-36.pyc create mode 100644 venv/Lib/site-packages/google/cloud/firestore_v1/proto/__pycache__/query_pb2.cpython-36.pyc create mode 100644 venv/Lib/site-packages/google/cloud/firestore_v1/proto/__pycache__/query_pb2_grpc.cpython-36.pyc create mode 100644 venv/Lib/site-packages/google/cloud/firestore_v1/proto/__pycache__/test_v1_pb2.cpython-36.pyc create mode 100644 venv/Lib/site-packages/google/cloud/firestore_v1/proto/__pycache__/tests_pb2.cpython-36.pyc create mode 100644 venv/Lib/site-packages/google/cloud/firestore_v1/proto/__pycache__/write_pb2.cpython-36.pyc create mode 100644 venv/Lib/site-packages/google/cloud/firestore_v1/proto/__pycache__/write_pb2_grpc.cpython-36.pyc create mode 100644 venv/Lib/site-packages/google/cloud/firestore_v1/proto/common.proto create mode 100644 venv/Lib/site-packages/google/cloud/firestore_v1/proto/common_pb2.py create mode 100644 venv/Lib/site-packages/google/cloud/firestore_v1/proto/common_pb2_grpc.py create mode 100644 venv/Lib/site-packages/google/cloud/firestore_v1/proto/document.proto create mode 100644 venv/Lib/site-packages/google/cloud/firestore_v1/proto/document_pb2.py create mode 100644 venv/Lib/site-packages/google/cloud/firestore_v1/proto/document_pb2_grpc.py create mode 100644 venv/Lib/site-packages/google/cloud/firestore_v1/proto/firestore.proto create mode 100644 venv/Lib/site-packages/google/cloud/firestore_v1/proto/firestore_pb2.py create mode 100644 venv/Lib/site-packages/google/cloud/firestore_v1/proto/firestore_pb2_grpc.py create mode 100644 venv/Lib/site-packages/google/cloud/firestore_v1/proto/query.proto create mode 100644 venv/Lib/site-packages/google/cloud/firestore_v1/proto/query_pb2.py create mode 100644 venv/Lib/site-packages/google/cloud/firestore_v1/proto/query_pb2_grpc.py create mode 100644 venv/Lib/site-packages/google/cloud/firestore_v1/proto/test_v1_pb2.py create mode 100644 venv/Lib/site-packages/google/cloud/firestore_v1/proto/tests_pb2.py create mode 100644 venv/Lib/site-packages/google/cloud/firestore_v1/proto/write.proto create mode 100644 venv/Lib/site-packages/google/cloud/firestore_v1/proto/write_pb2.py create mode 100644 venv/Lib/site-packages/google/cloud/firestore_v1/proto/write_pb2_grpc.py create mode 100644 venv/Lib/site-packages/google/cloud/firestore_v1/query.py create mode 100644 venv/Lib/site-packages/google/cloud/firestore_v1/transaction.py create mode 100644 venv/Lib/site-packages/google/cloud/firestore_v1/transforms.py create mode 100644 venv/Lib/site-packages/google/cloud/firestore_v1/types.py create mode 100644 venv/Lib/site-packages/google/cloud/firestore_v1/watch.py create mode 100644 venv/Lib/site-packages/google/cloud/firestore_v1beta1/__init__.py create mode 100644 venv/Lib/site-packages/google/cloud/firestore_v1beta1/__pycache__/__init__.cpython-36.pyc create mode 100644 venv/Lib/site-packages/google/cloud/firestore_v1beta1/__pycache__/_helpers.cpython-36.pyc create mode 100644 venv/Lib/site-packages/google/cloud/firestore_v1beta1/__pycache__/batch.cpython-36.pyc create mode 100644 venv/Lib/site-packages/google/cloud/firestore_v1beta1/__pycache__/client.cpython-36.pyc create mode 100644 venv/Lib/site-packages/google/cloud/firestore_v1beta1/__pycache__/collection.cpython-36.pyc create mode 100644 venv/Lib/site-packages/google/cloud/firestore_v1beta1/__pycache__/document.cpython-36.pyc create mode 100644 venv/Lib/site-packages/google/cloud/firestore_v1beta1/__pycache__/field_path.cpython-36.pyc create mode 100644 venv/Lib/site-packages/google/cloud/firestore_v1beta1/__pycache__/order.cpython-36.pyc create mode 100644 venv/Lib/site-packages/google/cloud/firestore_v1beta1/__pycache__/query.cpython-36.pyc create mode 100644 venv/Lib/site-packages/google/cloud/firestore_v1beta1/__pycache__/transaction.cpython-36.pyc create mode 100644 venv/Lib/site-packages/google/cloud/firestore_v1beta1/__pycache__/transforms.cpython-36.pyc create mode 100644 venv/Lib/site-packages/google/cloud/firestore_v1beta1/__pycache__/types.cpython-36.pyc create mode 100644 venv/Lib/site-packages/google/cloud/firestore_v1beta1/__pycache__/watch.cpython-36.pyc create mode 100644 venv/Lib/site-packages/google/cloud/firestore_v1beta1/_helpers.py create mode 100644 venv/Lib/site-packages/google/cloud/firestore_v1beta1/batch.py create mode 100644 venv/Lib/site-packages/google/cloud/firestore_v1beta1/client.py create mode 100644 venv/Lib/site-packages/google/cloud/firestore_v1beta1/collection.py create mode 100644 venv/Lib/site-packages/google/cloud/firestore_v1beta1/document.py create mode 100644 venv/Lib/site-packages/google/cloud/firestore_v1beta1/field_path.py create mode 100644 venv/Lib/site-packages/google/cloud/firestore_v1beta1/gapic/__init__.py create mode 100644 venv/Lib/site-packages/google/cloud/firestore_v1beta1/gapic/__pycache__/__init__.cpython-36.pyc create mode 100644 venv/Lib/site-packages/google/cloud/firestore_v1beta1/gapic/__pycache__/enums.cpython-36.pyc create mode 100644 venv/Lib/site-packages/google/cloud/firestore_v1beta1/gapic/__pycache__/firestore_client.cpython-36.pyc create mode 100644 venv/Lib/site-packages/google/cloud/firestore_v1beta1/gapic/__pycache__/firestore_client_config.cpython-36.pyc create mode 100644 venv/Lib/site-packages/google/cloud/firestore_v1beta1/gapic/enums.py create mode 100644 venv/Lib/site-packages/google/cloud/firestore_v1beta1/gapic/firestore_client.py create mode 100644 venv/Lib/site-packages/google/cloud/firestore_v1beta1/gapic/firestore_client_config.py create mode 100644 venv/Lib/site-packages/google/cloud/firestore_v1beta1/gapic/transports/__init__.py create mode 100644 venv/Lib/site-packages/google/cloud/firestore_v1beta1/gapic/transports/__pycache__/__init__.cpython-36.pyc create mode 100644 venv/Lib/site-packages/google/cloud/firestore_v1beta1/gapic/transports/__pycache__/firestore_grpc_transport.cpython-36.pyc create mode 100644 venv/Lib/site-packages/google/cloud/firestore_v1beta1/gapic/transports/firestore_grpc_transport.py create mode 100644 venv/Lib/site-packages/google/cloud/firestore_v1beta1/order.py create mode 100644 venv/Lib/site-packages/google/cloud/firestore_v1beta1/proto/__init__.py create mode 100644 venv/Lib/site-packages/google/cloud/firestore_v1beta1/proto/__pycache__/__init__.cpython-36.pyc create mode 100644 venv/Lib/site-packages/google/cloud/firestore_v1beta1/proto/__pycache__/common_pb2.cpython-36.pyc create mode 100644 venv/Lib/site-packages/google/cloud/firestore_v1beta1/proto/__pycache__/common_pb2_grpc.cpython-36.pyc create mode 100644 venv/Lib/site-packages/google/cloud/firestore_v1beta1/proto/__pycache__/document_pb2.cpython-36.pyc create mode 100644 venv/Lib/site-packages/google/cloud/firestore_v1beta1/proto/__pycache__/document_pb2_grpc.cpython-36.pyc create mode 100644 venv/Lib/site-packages/google/cloud/firestore_v1beta1/proto/__pycache__/event_flow_document_change_pb2.cpython-36.pyc create mode 100644 venv/Lib/site-packages/google/cloud/firestore_v1beta1/proto/__pycache__/event_flow_document_change_pb2_grpc.cpython-36.pyc create mode 100644 venv/Lib/site-packages/google/cloud/firestore_v1beta1/proto/__pycache__/firestore_pb2.cpython-36.pyc create mode 100644 venv/Lib/site-packages/google/cloud/firestore_v1beta1/proto/__pycache__/firestore_pb2_grpc.cpython-36.pyc create mode 100644 venv/Lib/site-packages/google/cloud/firestore_v1beta1/proto/__pycache__/query_pb2.cpython-36.pyc create mode 100644 venv/Lib/site-packages/google/cloud/firestore_v1beta1/proto/__pycache__/query_pb2_grpc.cpython-36.pyc create mode 100644 venv/Lib/site-packages/google/cloud/firestore_v1beta1/proto/__pycache__/test_v1beta1_pb2.cpython-36.pyc create mode 100644 venv/Lib/site-packages/google/cloud/firestore_v1beta1/proto/__pycache__/write_pb2.cpython-36.pyc create mode 100644 venv/Lib/site-packages/google/cloud/firestore_v1beta1/proto/__pycache__/write_pb2_grpc.cpython-36.pyc create mode 100644 venv/Lib/site-packages/google/cloud/firestore_v1beta1/proto/admin/__init__.py create mode 100644 venv/Lib/site-packages/google/cloud/firestore_v1beta1/proto/admin/__pycache__/__init__.cpython-36.pyc create mode 100644 venv/Lib/site-packages/google/cloud/firestore_v1beta1/proto/admin/__pycache__/firestore_admin_pb2.cpython-36.pyc create mode 100644 venv/Lib/site-packages/google/cloud/firestore_v1beta1/proto/admin/__pycache__/firestore_admin_pb2_grpc.cpython-36.pyc create mode 100644 venv/Lib/site-packages/google/cloud/firestore_v1beta1/proto/admin/__pycache__/index_pb2.cpython-36.pyc create mode 100644 venv/Lib/site-packages/google/cloud/firestore_v1beta1/proto/admin/__pycache__/index_pb2_grpc.cpython-36.pyc create mode 100644 venv/Lib/site-packages/google/cloud/firestore_v1beta1/proto/admin/firestore_admin_pb2.py create mode 100644 venv/Lib/site-packages/google/cloud/firestore_v1beta1/proto/admin/firestore_admin_pb2_grpc.py create mode 100644 venv/Lib/site-packages/google/cloud/firestore_v1beta1/proto/admin/index_pb2.py create mode 100644 venv/Lib/site-packages/google/cloud/firestore_v1beta1/proto/admin/index_pb2_grpc.py create mode 100644 venv/Lib/site-packages/google/cloud/firestore_v1beta1/proto/common.proto create mode 100644 venv/Lib/site-packages/google/cloud/firestore_v1beta1/proto/common_pb2.py create mode 100644 venv/Lib/site-packages/google/cloud/firestore_v1beta1/proto/common_pb2_grpc.py create mode 100644 venv/Lib/site-packages/google/cloud/firestore_v1beta1/proto/document.proto create mode 100644 venv/Lib/site-packages/google/cloud/firestore_v1beta1/proto/document_pb2.py create mode 100644 venv/Lib/site-packages/google/cloud/firestore_v1beta1/proto/document_pb2_grpc.py create mode 100644 venv/Lib/site-packages/google/cloud/firestore_v1beta1/proto/event_flow_document_change_pb2.py create mode 100644 venv/Lib/site-packages/google/cloud/firestore_v1beta1/proto/event_flow_document_change_pb2_grpc.py create mode 100644 venv/Lib/site-packages/google/cloud/firestore_v1beta1/proto/field.proto create mode 100644 venv/Lib/site-packages/google/cloud/firestore_v1beta1/proto/firestore.proto create mode 100644 venv/Lib/site-packages/google/cloud/firestore_v1beta1/proto/firestore_admin.proto create mode 100644 venv/Lib/site-packages/google/cloud/firestore_v1beta1/proto/firestore_pb2.py create mode 100644 venv/Lib/site-packages/google/cloud/firestore_v1beta1/proto/firestore_pb2_grpc.py create mode 100644 venv/Lib/site-packages/google/cloud/firestore_v1beta1/proto/index.proto create mode 100644 venv/Lib/site-packages/google/cloud/firestore_v1beta1/proto/location.proto create mode 100644 venv/Lib/site-packages/google/cloud/firestore_v1beta1/proto/operation.proto create mode 100644 venv/Lib/site-packages/google/cloud/firestore_v1beta1/proto/query.proto create mode 100644 venv/Lib/site-packages/google/cloud/firestore_v1beta1/proto/query_pb2.py create mode 100644 venv/Lib/site-packages/google/cloud/firestore_v1beta1/proto/query_pb2_grpc.py create mode 100644 venv/Lib/site-packages/google/cloud/firestore_v1beta1/proto/test_v1beta1_pb2.py create mode 100644 venv/Lib/site-packages/google/cloud/firestore_v1beta1/proto/write.proto create mode 100644 venv/Lib/site-packages/google/cloud/firestore_v1beta1/proto/write_pb2.py create mode 100644 venv/Lib/site-packages/google/cloud/firestore_v1beta1/proto/write_pb2_grpc.py create mode 100644 venv/Lib/site-packages/google/cloud/firestore_v1beta1/query.py create mode 100644 venv/Lib/site-packages/google/cloud/firestore_v1beta1/transaction.py create mode 100644 venv/Lib/site-packages/google/cloud/firestore_v1beta1/transforms.py create mode 100644 venv/Lib/site-packages/google/cloud/firestore_v1beta1/types.py create mode 100644 venv/Lib/site-packages/google/cloud/firestore_v1beta1/watch.py create mode 100644 venv/Lib/site-packages/google/cloud/obsolete.py create mode 100644 venv/Lib/site-packages/google/cloud/operation.py create mode 100644 venv/Lib/site-packages/google/cloud/storage/__init__.py create mode 100644 venv/Lib/site-packages/google/cloud/storage/__pycache__/__init__.cpython-36.pyc create mode 100644 venv/Lib/site-packages/google/cloud/storage/__pycache__/_helpers.cpython-36.pyc create mode 100644 venv/Lib/site-packages/google/cloud/storage/__pycache__/_http.cpython-36.pyc create mode 100644 venv/Lib/site-packages/google/cloud/storage/__pycache__/_signing.cpython-36.pyc create mode 100644 venv/Lib/site-packages/google/cloud/storage/__pycache__/acl.cpython-36.pyc create mode 100644 venv/Lib/site-packages/google/cloud/storage/__pycache__/batch.cpython-36.pyc create mode 100644 venv/Lib/site-packages/google/cloud/storage/__pycache__/blob.cpython-36.pyc create mode 100644 venv/Lib/site-packages/google/cloud/storage/__pycache__/bucket.cpython-36.pyc create mode 100644 venv/Lib/site-packages/google/cloud/storage/__pycache__/client.cpython-36.pyc create mode 100644 venv/Lib/site-packages/google/cloud/storage/__pycache__/constants.cpython-36.pyc create mode 100644 venv/Lib/site-packages/google/cloud/storage/__pycache__/hmac_key.cpython-36.pyc create mode 100644 venv/Lib/site-packages/google/cloud/storage/__pycache__/iam.cpython-36.pyc create mode 100644 venv/Lib/site-packages/google/cloud/storage/__pycache__/notification.cpython-36.pyc create mode 100644 venv/Lib/site-packages/google/cloud/storage/_helpers.py create mode 100644 venv/Lib/site-packages/google/cloud/storage/_http.py create mode 100644 venv/Lib/site-packages/google/cloud/storage/_signing.py create mode 100644 venv/Lib/site-packages/google/cloud/storage/acl.py create mode 100644 venv/Lib/site-packages/google/cloud/storage/batch.py create mode 100644 venv/Lib/site-packages/google/cloud/storage/blob.py create mode 100644 venv/Lib/site-packages/google/cloud/storage/bucket.py create mode 100644 venv/Lib/site-packages/google/cloud/storage/client.py create mode 100644 venv/Lib/site-packages/google/cloud/storage/constants.py create mode 100644 venv/Lib/site-packages/google/cloud/storage/hmac_key.py create mode 100644 venv/Lib/site-packages/google/cloud/storage/iam.py create mode 100644 venv/Lib/site-packages/google/cloud/storage/notification.py create mode 100644 venv/Lib/site-packages/google/cloud/version.py create mode 100644 venv/Lib/site-packages/google/oauth2/__init__.py create mode 100644 venv/Lib/site-packages/google/oauth2/__pycache__/__init__.cpython-36.pyc create mode 100644 venv/Lib/site-packages/google/oauth2/__pycache__/_client.cpython-36.pyc create mode 100644 venv/Lib/site-packages/google/oauth2/__pycache__/_client_async.cpython-36.pyc create mode 100644 venv/Lib/site-packages/google/oauth2/__pycache__/_credentials_async.cpython-36.pyc create mode 100644 venv/Lib/site-packages/google/oauth2/__pycache__/_id_token_async.cpython-36.pyc create mode 100644 venv/Lib/site-packages/google/oauth2/__pycache__/_service_account_async.cpython-36.pyc create mode 100644 venv/Lib/site-packages/google/oauth2/__pycache__/credentials.cpython-36.pyc create mode 100644 venv/Lib/site-packages/google/oauth2/__pycache__/id_token.cpython-36.pyc create mode 100644 venv/Lib/site-packages/google/oauth2/__pycache__/service_account.cpython-36.pyc create mode 100644 venv/Lib/site-packages/google/oauth2/_client.py create mode 100644 venv/Lib/site-packages/google/oauth2/_client_async.py create mode 100644 venv/Lib/site-packages/google/oauth2/_credentials_async.py create mode 100644 venv/Lib/site-packages/google/oauth2/_id_token_async.py create mode 100644 venv/Lib/site-packages/google/oauth2/_service_account_async.py create mode 100644 venv/Lib/site-packages/google/oauth2/credentials.py create mode 100644 venv/Lib/site-packages/google/oauth2/id_token.py create mode 100644 venv/Lib/site-packages/google/oauth2/service_account.py create mode 100644 venv/Lib/site-packages/google/resumable_media/__init__.py create mode 100644 venv/Lib/site-packages/google/resumable_media/__pycache__/__init__.cpython-36.pyc create mode 100644 venv/Lib/site-packages/google/resumable_media/__pycache__/_download.cpython-36.pyc create mode 100644 venv/Lib/site-packages/google/resumable_media/__pycache__/_helpers.cpython-36.pyc create mode 100644 venv/Lib/site-packages/google/resumable_media/__pycache__/_upload.cpython-36.pyc create mode 100644 venv/Lib/site-packages/google/resumable_media/__pycache__/common.cpython-36.pyc create mode 100644 venv/Lib/site-packages/google/resumable_media/_download.py create mode 100644 venv/Lib/site-packages/google/resumable_media/_helpers.py create mode 100644 venv/Lib/site-packages/google/resumable_media/_upload.py create mode 100644 venv/Lib/site-packages/google/resumable_media/common.py create mode 100644 venv/Lib/site-packages/google/resumable_media/requests/__init__.py create mode 100644 venv/Lib/site-packages/google/resumable_media/requests/__pycache__/__init__.cpython-36.pyc create mode 100644 venv/Lib/site-packages/google/resumable_media/requests/__pycache__/_request_helpers.cpython-36.pyc create mode 100644 venv/Lib/site-packages/google/resumable_media/requests/__pycache__/download.cpython-36.pyc create mode 100644 venv/Lib/site-packages/google/resumable_media/requests/__pycache__/upload.cpython-36.pyc create mode 100644 venv/Lib/site-packages/google/resumable_media/requests/_request_helpers.py create mode 100644 venv/Lib/site-packages/google/resumable_media/requests/download.py create mode 100644 venv/Lib/site-packages/google/resumable_media/requests/upload.py create mode 100644 venv/Lib/site-packages/google_api_core-1.22.4-py3.8-nspkg.pth create mode 100644 venv/Lib/site-packages/google_api_core-1.22.4.dist-info/INSTALLER create mode 100644 venv/Lib/site-packages/google_api_core-1.22.4.dist-info/LICENSE create mode 100644 venv/Lib/site-packages/google_api_core-1.22.4.dist-info/METADATA create mode 100644 venv/Lib/site-packages/google_api_core-1.22.4.dist-info/RECORD create mode 100644 venv/Lib/site-packages/google_api_core-1.22.4.dist-info/WHEEL create mode 100644 venv/Lib/site-packages/google_api_core-1.22.4.dist-info/namespace_packages.txt create mode 100644 venv/Lib/site-packages/google_api_core-1.22.4.dist-info/top_level.txt create mode 100644 venv/Lib/site-packages/google_api_python_client-1.12.3.dist-info/INSTALLER create mode 100644 venv/Lib/site-packages/google_api_python_client-1.12.3.dist-info/LICENSE create mode 100644 venv/Lib/site-packages/google_api_python_client-1.12.3.dist-info/METADATA create mode 100644 venv/Lib/site-packages/google_api_python_client-1.12.3.dist-info/RECORD create mode 100644 venv/Lib/site-packages/google_api_python_client-1.12.3.dist-info/WHEEL create mode 100644 venv/Lib/site-packages/google_api_python_client-1.12.3.dist-info/top_level.txt create mode 100644 venv/Lib/site-packages/google_auth-1.22.1-py3.8-nspkg.pth create mode 100644 venv/Lib/site-packages/google_auth-1.22.1.dist-info/INSTALLER create mode 100644 venv/Lib/site-packages/google_auth-1.22.1.dist-info/LICENSE create mode 100644 venv/Lib/site-packages/google_auth-1.22.1.dist-info/METADATA create mode 100644 venv/Lib/site-packages/google_auth-1.22.1.dist-info/RECORD create mode 100644 venv/Lib/site-packages/google_auth-1.22.1.dist-info/WHEEL create mode 100644 venv/Lib/site-packages/google_auth-1.22.1.dist-info/namespace_packages.txt create mode 100644 venv/Lib/site-packages/google_auth-1.22.1.dist-info/top_level.txt create mode 100644 venv/Lib/site-packages/google_auth_httplib2-0.0.4.dist-info/INSTALLER create mode 100644 venv/Lib/site-packages/google_auth_httplib2-0.0.4.dist-info/LICENSE create mode 100644 venv/Lib/site-packages/google_auth_httplib2-0.0.4.dist-info/METADATA create mode 100644 venv/Lib/site-packages/google_auth_httplib2-0.0.4.dist-info/RECORD create mode 100644 venv/Lib/site-packages/google_auth_httplib2-0.0.4.dist-info/WHEEL create mode 100644 venv/Lib/site-packages/google_auth_httplib2-0.0.4.dist-info/top_level.txt create mode 100644 venv/Lib/site-packages/google_auth_httplib2.py create mode 100644 venv/Lib/site-packages/google_cloud_core-1.4.3-py3.8-nspkg.pth create mode 100644 venv/Lib/site-packages/google_cloud_core-1.4.3.dist-info/INSTALLER create mode 100644 venv/Lib/site-packages/google_cloud_core-1.4.3.dist-info/LICENSE create mode 100644 venv/Lib/site-packages/google_cloud_core-1.4.3.dist-info/METADATA create mode 100644 venv/Lib/site-packages/google_cloud_core-1.4.3.dist-info/RECORD create mode 100644 venv/Lib/site-packages/google_cloud_core-1.4.3.dist-info/WHEEL create mode 100644 venv/Lib/site-packages/google_cloud_core-1.4.3.dist-info/namespace_packages.txt create mode 100644 venv/Lib/site-packages/google_cloud_core-1.4.3.dist-info/top_level.txt create mode 100644 venv/Lib/site-packages/google_cloud_firestore-1.9.0-py3.8-nspkg.pth create mode 100644 venv/Lib/site-packages/google_cloud_firestore-1.9.0.dist-info/INSTALLER create mode 100644 venv/Lib/site-packages/google_cloud_firestore-1.9.0.dist-info/LICENSE create mode 100644 venv/Lib/site-packages/google_cloud_firestore-1.9.0.dist-info/METADATA create mode 100644 venv/Lib/site-packages/google_cloud_firestore-1.9.0.dist-info/RECORD create mode 100644 venv/Lib/site-packages/google_cloud_firestore-1.9.0.dist-info/WHEEL create mode 100644 venv/Lib/site-packages/google_cloud_firestore-1.9.0.dist-info/namespace_packages.txt create mode 100644 venv/Lib/site-packages/google_cloud_firestore-1.9.0.dist-info/top_level.txt create mode 100644 venv/Lib/site-packages/google_cloud_storage-1.31.2-py3.8-nspkg.pth create mode 100644 venv/Lib/site-packages/google_cloud_storage-1.31.2.dist-info/INSTALLER create mode 100644 venv/Lib/site-packages/google_cloud_storage-1.31.2.dist-info/LICENSE create mode 100644 venv/Lib/site-packages/google_cloud_storage-1.31.2.dist-info/METADATA create mode 100644 venv/Lib/site-packages/google_cloud_storage-1.31.2.dist-info/RECORD create mode 100644 venv/Lib/site-packages/google_cloud_storage-1.31.2.dist-info/WHEEL create mode 100644 venv/Lib/site-packages/google_cloud_storage-1.31.2.dist-info/namespace_packages.txt create mode 100644 venv/Lib/site-packages/google_cloud_storage-1.31.2.dist-info/top_level.txt create mode 100644 venv/Lib/site-packages/google_crc32c-1.0.0.dist-info/INSTALLER create mode 100644 venv/Lib/site-packages/google_crc32c-1.0.0.dist-info/LICENSE create mode 100644 venv/Lib/site-packages/google_crc32c-1.0.0.dist-info/METADATA create mode 100644 venv/Lib/site-packages/google_crc32c-1.0.0.dist-info/RECORD create mode 100644 venv/Lib/site-packages/google_crc32c-1.0.0.dist-info/WHEEL create mode 100644 venv/Lib/site-packages/google_crc32c-1.0.0.dist-info/top_level.txt create mode 100644 venv/Lib/site-packages/google_crc32c-1.0.0.dist-info/zip-safe create mode 100644 venv/Lib/site-packages/google_crc32c/__config__.py create mode 100644 venv/Lib/site-packages/google_crc32c/__init__.py create mode 100644 venv/Lib/site-packages/google_crc32c/__pycache__/__config__.cpython-36.pyc create mode 100644 venv/Lib/site-packages/google_crc32c/__pycache__/__init__.cpython-36.pyc create mode 100644 venv/Lib/site-packages/google_crc32c/__pycache__/_checksum.cpython-36.pyc create mode 100644 venv/Lib/site-packages/google_crc32c/__pycache__/cffi.cpython-36.pyc create mode 100644 venv/Lib/site-packages/google_crc32c/__pycache__/python.cpython-36.pyc create mode 100644 venv/Lib/site-packages/google_crc32c/_checksum.py create mode 100644 venv/Lib/site-packages/google_crc32c/_crc32c_cffi.cp36-win32.pyd create mode 100644 venv/Lib/site-packages/google_crc32c/cffi.py create mode 100644 venv/Lib/site-packages/google_crc32c/extra-dll/crc32c.dll create mode 100644 venv/Lib/site-packages/google_crc32c/python.py create mode 100644 venv/Lib/site-packages/google_resumable_media-1.1.0-py3.8-nspkg.pth create mode 100644 venv/Lib/site-packages/google_resumable_media-1.1.0.dist-info/INSTALLER create mode 100644 venv/Lib/site-packages/google_resumable_media-1.1.0.dist-info/LICENSE create mode 100644 venv/Lib/site-packages/google_resumable_media-1.1.0.dist-info/METADATA create mode 100644 venv/Lib/site-packages/google_resumable_media-1.1.0.dist-info/RECORD create mode 100644 venv/Lib/site-packages/google_resumable_media-1.1.0.dist-info/WHEEL create mode 100644 venv/Lib/site-packages/google_resumable_media-1.1.0.dist-info/namespace_packages.txt create mode 100644 venv/Lib/site-packages/google_resumable_media-1.1.0.dist-info/top_level.txt create mode 100644 venv/Lib/site-packages/googleapiclient/__init__.py create mode 100644 venv/Lib/site-packages/googleapiclient/__pycache__/__init__.cpython-36.pyc create mode 100644 venv/Lib/site-packages/googleapiclient/__pycache__/_auth.cpython-36.pyc create mode 100644 venv/Lib/site-packages/googleapiclient/__pycache__/_helpers.cpython-36.pyc create mode 100644 venv/Lib/site-packages/googleapiclient/__pycache__/channel.cpython-36.pyc create mode 100644 venv/Lib/site-packages/googleapiclient/__pycache__/discovery.cpython-36.pyc create mode 100644 venv/Lib/site-packages/googleapiclient/__pycache__/errors.cpython-36.pyc create mode 100644 venv/Lib/site-packages/googleapiclient/__pycache__/http.cpython-36.pyc create mode 100644 venv/Lib/site-packages/googleapiclient/__pycache__/mimeparse.cpython-36.pyc create mode 100644 venv/Lib/site-packages/googleapiclient/__pycache__/model.cpython-36.pyc create mode 100644 venv/Lib/site-packages/googleapiclient/__pycache__/sample_tools.cpython-36.pyc create mode 100644 venv/Lib/site-packages/googleapiclient/__pycache__/schema.cpython-36.pyc create mode 100644 venv/Lib/site-packages/googleapiclient/_auth.py create mode 100644 venv/Lib/site-packages/googleapiclient/_helpers.py create mode 100644 venv/Lib/site-packages/googleapiclient/channel.py create mode 100644 venv/Lib/site-packages/googleapiclient/discovery.py create mode 100644 venv/Lib/site-packages/googleapiclient/discovery_cache/__init__.py create mode 100644 venv/Lib/site-packages/googleapiclient/discovery_cache/__pycache__/__init__.cpython-36.pyc create mode 100644 venv/Lib/site-packages/googleapiclient/discovery_cache/__pycache__/appengine_memcache.cpython-36.pyc create mode 100644 venv/Lib/site-packages/googleapiclient/discovery_cache/__pycache__/base.cpython-36.pyc create mode 100644 venv/Lib/site-packages/googleapiclient/discovery_cache/__pycache__/file_cache.cpython-36.pyc create mode 100644 venv/Lib/site-packages/googleapiclient/discovery_cache/appengine_memcache.py create mode 100644 venv/Lib/site-packages/googleapiclient/discovery_cache/base.py create mode 100644 venv/Lib/site-packages/googleapiclient/discovery_cache/file_cache.py create mode 100644 venv/Lib/site-packages/googleapiclient/errors.py create mode 100644 venv/Lib/site-packages/googleapiclient/http.py create mode 100644 venv/Lib/site-packages/googleapiclient/mimeparse.py create mode 100644 venv/Lib/site-packages/googleapiclient/model.py create mode 100644 venv/Lib/site-packages/googleapiclient/sample_tools.py create mode 100644 venv/Lib/site-packages/googleapiclient/schema.py create mode 100644 venv/Lib/site-packages/grpc/__init__.py create mode 100644 venv/Lib/site-packages/grpc/__pycache__/__init__.cpython-36.pyc create mode 100644 venv/Lib/site-packages/grpc/__pycache__/_auth.cpython-36.pyc create mode 100644 venv/Lib/site-packages/grpc/__pycache__/_channel.cpython-36.pyc create mode 100644 venv/Lib/site-packages/grpc/__pycache__/_common.cpython-36.pyc create mode 100644 venv/Lib/site-packages/grpc/__pycache__/_compression.cpython-36.pyc create mode 100644 venv/Lib/site-packages/grpc/__pycache__/_grpcio_metadata.cpython-36.pyc create mode 100644 venv/Lib/site-packages/grpc/__pycache__/_interceptor.cpython-36.pyc create mode 100644 venv/Lib/site-packages/grpc/__pycache__/_plugin_wrapping.cpython-36.pyc create mode 100644 venv/Lib/site-packages/grpc/__pycache__/_runtime_protos.cpython-36.pyc create mode 100644 venv/Lib/site-packages/grpc/__pycache__/_server.cpython-36.pyc create mode 100644 venv/Lib/site-packages/grpc/__pycache__/_simple_stubs.cpython-36.pyc create mode 100644 venv/Lib/site-packages/grpc/__pycache__/_utilities.cpython-36.pyc create mode 100644 venv/Lib/site-packages/grpc/_auth.py create mode 100644 venv/Lib/site-packages/grpc/_channel.py create mode 100644 venv/Lib/site-packages/grpc/_common.py create mode 100644 venv/Lib/site-packages/grpc/_compression.py create mode 100644 venv/Lib/site-packages/grpc/_cython/__init__.py create mode 100644 venv/Lib/site-packages/grpc/_cython/__pycache__/__init__.cpython-36.pyc rename venv/Lib/site-packages/{requests/cacert.pem => grpc/_cython/_credentials/roots.pem} (61%) create mode 100644 venv/Lib/site-packages/grpc/_cython/_cygrpc/__init__.py create mode 100644 venv/Lib/site-packages/grpc/_cython/_cygrpc/__pycache__/__init__.cpython-36.pyc create mode 100644 venv/Lib/site-packages/grpc/_cython/cygrpc.cp36-win32.pyd create mode 100644 venv/Lib/site-packages/grpc/_grpcio_metadata.py create mode 100644 venv/Lib/site-packages/grpc/_interceptor.py create mode 100644 venv/Lib/site-packages/grpc/_plugin_wrapping.py create mode 100644 venv/Lib/site-packages/grpc/_runtime_protos.py create mode 100644 venv/Lib/site-packages/grpc/_server.py create mode 100644 venv/Lib/site-packages/grpc/_simple_stubs.py create mode 100644 venv/Lib/site-packages/grpc/_utilities.py create mode 100644 venv/Lib/site-packages/grpc/aio/__init__.py create mode 100644 venv/Lib/site-packages/grpc/aio/__pycache__/__init__.cpython-36.pyc create mode 100644 venv/Lib/site-packages/grpc/aio/__pycache__/_base_call.cpython-36.pyc create mode 100644 venv/Lib/site-packages/grpc/aio/__pycache__/_base_channel.cpython-36.pyc create mode 100644 venv/Lib/site-packages/grpc/aio/__pycache__/_base_server.cpython-36.pyc create mode 100644 venv/Lib/site-packages/grpc/aio/__pycache__/_call.cpython-36.pyc create mode 100644 venv/Lib/site-packages/grpc/aio/__pycache__/_channel.cpython-36.pyc create mode 100644 venv/Lib/site-packages/grpc/aio/__pycache__/_interceptor.cpython-36.pyc create mode 100644 venv/Lib/site-packages/grpc/aio/__pycache__/_metadata.cpython-36.pyc create mode 100644 venv/Lib/site-packages/grpc/aio/__pycache__/_server.cpython-36.pyc create mode 100644 venv/Lib/site-packages/grpc/aio/__pycache__/_typing.cpython-36.pyc create mode 100644 venv/Lib/site-packages/grpc/aio/__pycache__/_utils.cpython-36.pyc create mode 100644 venv/Lib/site-packages/grpc/aio/_base_call.py create mode 100644 venv/Lib/site-packages/grpc/aio/_base_channel.py create mode 100644 venv/Lib/site-packages/grpc/aio/_base_server.py create mode 100644 venv/Lib/site-packages/grpc/aio/_call.py create mode 100644 venv/Lib/site-packages/grpc/aio/_channel.py create mode 100644 venv/Lib/site-packages/grpc/aio/_interceptor.py create mode 100644 venv/Lib/site-packages/grpc/aio/_metadata.py create mode 100644 venv/Lib/site-packages/grpc/aio/_server.py create mode 100644 venv/Lib/site-packages/grpc/aio/_typing.py create mode 100644 venv/Lib/site-packages/grpc/aio/_utils.py create mode 100644 venv/Lib/site-packages/grpc/beta/__init__.py create mode 100644 venv/Lib/site-packages/grpc/beta/__pycache__/__init__.cpython-36.pyc create mode 100644 venv/Lib/site-packages/grpc/beta/__pycache__/_client_adaptations.cpython-36.pyc create mode 100644 venv/Lib/site-packages/grpc/beta/__pycache__/_metadata.cpython-36.pyc create mode 100644 venv/Lib/site-packages/grpc/beta/__pycache__/_server_adaptations.cpython-36.pyc create mode 100644 venv/Lib/site-packages/grpc/beta/__pycache__/implementations.cpython-36.pyc create mode 100644 venv/Lib/site-packages/grpc/beta/__pycache__/interfaces.cpython-36.pyc create mode 100644 venv/Lib/site-packages/grpc/beta/__pycache__/utilities.cpython-36.pyc create mode 100644 venv/Lib/site-packages/grpc/beta/_client_adaptations.py create mode 100644 venv/Lib/site-packages/grpc/beta/_metadata.py create mode 100644 venv/Lib/site-packages/grpc/beta/_server_adaptations.py create mode 100644 venv/Lib/site-packages/grpc/beta/implementations.py create mode 100644 venv/Lib/site-packages/grpc/beta/interfaces.py create mode 100644 venv/Lib/site-packages/grpc/beta/utilities.py create mode 100644 venv/Lib/site-packages/grpc/experimental/__init__.py create mode 100644 venv/Lib/site-packages/grpc/experimental/__pycache__/__init__.cpython-36.pyc create mode 100644 venv/Lib/site-packages/grpc/experimental/__pycache__/gevent.cpython-36.pyc create mode 100644 venv/Lib/site-packages/grpc/experimental/__pycache__/session_cache.cpython-36.pyc create mode 100644 venv/Lib/site-packages/grpc/experimental/aio/__init__.py create mode 100644 venv/Lib/site-packages/grpc/experimental/aio/__pycache__/__init__.cpython-36.pyc create mode 100644 venv/Lib/site-packages/grpc/experimental/gevent.py create mode 100644 venv/Lib/site-packages/grpc/experimental/session_cache.py create mode 100644 venv/Lib/site-packages/grpc/framework/__init__.py create mode 100644 venv/Lib/site-packages/grpc/framework/__pycache__/__init__.cpython-36.pyc create mode 100644 venv/Lib/site-packages/grpc/framework/common/__init__.py create mode 100644 venv/Lib/site-packages/grpc/framework/common/__pycache__/__init__.cpython-36.pyc create mode 100644 venv/Lib/site-packages/grpc/framework/common/__pycache__/cardinality.cpython-36.pyc create mode 100644 venv/Lib/site-packages/grpc/framework/common/__pycache__/style.cpython-36.pyc create mode 100644 venv/Lib/site-packages/grpc/framework/common/cardinality.py create mode 100644 venv/Lib/site-packages/grpc/framework/common/style.py create mode 100644 venv/Lib/site-packages/grpc/framework/foundation/__init__.py create mode 100644 venv/Lib/site-packages/grpc/framework/foundation/__pycache__/__init__.cpython-36.pyc create mode 100644 venv/Lib/site-packages/grpc/framework/foundation/__pycache__/abandonment.cpython-36.pyc create mode 100644 venv/Lib/site-packages/grpc/framework/foundation/__pycache__/callable_util.cpython-36.pyc create mode 100644 venv/Lib/site-packages/grpc/framework/foundation/__pycache__/future.cpython-36.pyc create mode 100644 venv/Lib/site-packages/grpc/framework/foundation/__pycache__/logging_pool.cpython-36.pyc create mode 100644 venv/Lib/site-packages/grpc/framework/foundation/__pycache__/stream.cpython-36.pyc create mode 100644 venv/Lib/site-packages/grpc/framework/foundation/__pycache__/stream_util.cpython-36.pyc create mode 100644 venv/Lib/site-packages/grpc/framework/foundation/abandonment.py create mode 100644 venv/Lib/site-packages/grpc/framework/foundation/callable_util.py create mode 100644 venv/Lib/site-packages/grpc/framework/foundation/future.py create mode 100644 venv/Lib/site-packages/grpc/framework/foundation/logging_pool.py create mode 100644 venv/Lib/site-packages/grpc/framework/foundation/stream.py create mode 100644 venv/Lib/site-packages/grpc/framework/foundation/stream_util.py create mode 100644 venv/Lib/site-packages/grpc/framework/interfaces/__init__.py create mode 100644 venv/Lib/site-packages/grpc/framework/interfaces/__pycache__/__init__.cpython-36.pyc create mode 100644 venv/Lib/site-packages/grpc/framework/interfaces/base/__init__.py create mode 100644 venv/Lib/site-packages/grpc/framework/interfaces/base/__pycache__/__init__.cpython-36.pyc create mode 100644 venv/Lib/site-packages/grpc/framework/interfaces/base/__pycache__/base.cpython-36.pyc create mode 100644 venv/Lib/site-packages/grpc/framework/interfaces/base/__pycache__/utilities.cpython-36.pyc create mode 100644 venv/Lib/site-packages/grpc/framework/interfaces/base/base.py create mode 100644 venv/Lib/site-packages/grpc/framework/interfaces/base/utilities.py create mode 100644 venv/Lib/site-packages/grpc/framework/interfaces/face/__init__.py create mode 100644 venv/Lib/site-packages/grpc/framework/interfaces/face/__pycache__/__init__.cpython-36.pyc create mode 100644 venv/Lib/site-packages/grpc/framework/interfaces/face/__pycache__/face.cpython-36.pyc create mode 100644 venv/Lib/site-packages/grpc/framework/interfaces/face/__pycache__/utilities.cpython-36.pyc create mode 100644 venv/Lib/site-packages/grpc/framework/interfaces/face/face.py create mode 100644 venv/Lib/site-packages/grpc/framework/interfaces/face/utilities.py create mode 100644 venv/Lib/site-packages/grpcio-1.32.0.dist-info/DESCRIPTION.rst create mode 100644 venv/Lib/site-packages/grpcio-1.32.0.dist-info/INSTALLER create mode 100644 venv/Lib/site-packages/grpcio-1.32.0.dist-info/METADATA create mode 100644 venv/Lib/site-packages/grpcio-1.32.0.dist-info/RECORD create mode 100644 venv/Lib/site-packages/grpcio-1.32.0.dist-info/WHEEL create mode 100644 venv/Lib/site-packages/grpcio-1.32.0.dist-info/metadata.json create mode 100644 venv/Lib/site-packages/grpcio-1.32.0.dist-info/top_level.txt create mode 100644 venv/Lib/site-packages/idna-2.10.dist-info/INSTALLER create mode 100644 venv/Lib/site-packages/idna-2.10.dist-info/LICENSE.rst create mode 100644 venv/Lib/site-packages/idna-2.10.dist-info/METADATA create mode 100644 venv/Lib/site-packages/idna-2.10.dist-info/RECORD create mode 100644 venv/Lib/site-packages/idna-2.10.dist-info/WHEEL create mode 100644 venv/Lib/site-packages/idna-2.10.dist-info/top_level.txt create mode 100644 venv/Lib/site-packages/idna/__init__.py create mode 100644 venv/Lib/site-packages/idna/__pycache__/__init__.cpython-36.pyc create mode 100644 venv/Lib/site-packages/idna/__pycache__/codec.cpython-36.pyc create mode 100644 venv/Lib/site-packages/idna/__pycache__/compat.cpython-36.pyc create mode 100644 venv/Lib/site-packages/idna/__pycache__/core.cpython-36.pyc create mode 100644 venv/Lib/site-packages/idna/__pycache__/idnadata.cpython-36.pyc create mode 100644 venv/Lib/site-packages/idna/__pycache__/intranges.cpython-36.pyc create mode 100644 venv/Lib/site-packages/idna/__pycache__/package_data.cpython-36.pyc create mode 100644 venv/Lib/site-packages/idna/__pycache__/uts46data.cpython-36.pyc create mode 100644 venv/Lib/site-packages/idna/codec.py create mode 100644 venv/Lib/site-packages/idna/compat.py create mode 100644 venv/Lib/site-packages/idna/core.py create mode 100644 venv/Lib/site-packages/idna/idnadata.py create mode 100644 venv/Lib/site-packages/idna/intranges.py create mode 100644 venv/Lib/site-packages/idna/package_data.py create mode 100644 venv/Lib/site-packages/idna/uts46data.py create mode 100644 venv/Lib/site-packages/msgpack-1.0.0.dist-info/COPYING create mode 100644 venv/Lib/site-packages/msgpack-1.0.0.dist-info/INSTALLER create mode 100644 venv/Lib/site-packages/msgpack-1.0.0.dist-info/METADATA create mode 100644 venv/Lib/site-packages/msgpack-1.0.0.dist-info/RECORD create mode 100644 venv/Lib/site-packages/msgpack-1.0.0.dist-info/WHEEL create mode 100644 venv/Lib/site-packages/msgpack-1.0.0.dist-info/top_level.txt create mode 100644 venv/Lib/site-packages/msgpack/__init__.py create mode 100644 venv/Lib/site-packages/msgpack/__pycache__/__init__.cpython-36.pyc create mode 100644 venv/Lib/site-packages/msgpack/__pycache__/_version.cpython-36.pyc create mode 100644 venv/Lib/site-packages/msgpack/__pycache__/exceptions.cpython-36.pyc create mode 100644 venv/Lib/site-packages/msgpack/__pycache__/ext.cpython-36.pyc create mode 100644 venv/Lib/site-packages/msgpack/__pycache__/fallback.cpython-36.pyc create mode 100644 venv/Lib/site-packages/msgpack/_cmsgpack.cp36-win32.pyd create mode 100644 venv/Lib/site-packages/msgpack/_version.py create mode 100644 venv/Lib/site-packages/msgpack/exceptions.py create mode 100644 venv/Lib/site-packages/msgpack/ext.py create mode 100644 venv/Lib/site-packages/msgpack/fallback.py create mode 100644 venv/Lib/site-packages/pycparser-2.20.dist-info/INSTALLER create mode 100644 venv/Lib/site-packages/pycparser-2.20.dist-info/LICENSE create mode 100644 venv/Lib/site-packages/pycparser-2.20.dist-info/METADATA create mode 100644 venv/Lib/site-packages/pycparser-2.20.dist-info/RECORD create mode 100644 venv/Lib/site-packages/pycparser-2.20.dist-info/WHEEL create mode 100644 venv/Lib/site-packages/pycparser-2.20.dist-info/top_level.txt create mode 100644 venv/Lib/site-packages/pycparser/__init__.py create mode 100644 venv/Lib/site-packages/pycparser/__pycache__/__init__.cpython-36.pyc create mode 100644 venv/Lib/site-packages/pycparser/__pycache__/_ast_gen.cpython-36.pyc create mode 100644 venv/Lib/site-packages/pycparser/__pycache__/_build_tables.cpython-36.pyc create mode 100644 venv/Lib/site-packages/pycparser/__pycache__/ast_transforms.cpython-36.pyc create mode 100644 venv/Lib/site-packages/pycparser/__pycache__/c_ast.cpython-36.pyc create mode 100644 venv/Lib/site-packages/pycparser/__pycache__/c_generator.cpython-36.pyc create mode 100644 venv/Lib/site-packages/pycparser/__pycache__/c_lexer.cpython-36.pyc create mode 100644 venv/Lib/site-packages/pycparser/__pycache__/c_parser.cpython-36.pyc create mode 100644 venv/Lib/site-packages/pycparser/__pycache__/lextab.cpython-36.pyc create mode 100644 venv/Lib/site-packages/pycparser/__pycache__/plyparser.cpython-36.pyc create mode 100644 venv/Lib/site-packages/pycparser/__pycache__/yacctab.cpython-36.pyc create mode 100644 venv/Lib/site-packages/pycparser/_ast_gen.py create mode 100644 venv/Lib/site-packages/pycparser/_build_tables.py create mode 100644 venv/Lib/site-packages/pycparser/_c_ast.cfg create mode 100644 venv/Lib/site-packages/pycparser/ast_transforms.py create mode 100644 venv/Lib/site-packages/pycparser/c_ast.py create mode 100644 venv/Lib/site-packages/pycparser/c_generator.py create mode 100644 venv/Lib/site-packages/pycparser/c_lexer.py create mode 100644 venv/Lib/site-packages/pycparser/c_parser.py create mode 100644 venv/Lib/site-packages/pycparser/lextab.py create mode 100644 venv/Lib/site-packages/pycparser/ply/__init__.py create mode 100644 venv/Lib/site-packages/pycparser/ply/__pycache__/__init__.cpython-36.pyc create mode 100644 venv/Lib/site-packages/pycparser/ply/__pycache__/cpp.cpython-36.pyc create mode 100644 venv/Lib/site-packages/pycparser/ply/__pycache__/ctokens.cpython-36.pyc create mode 100644 venv/Lib/site-packages/pycparser/ply/__pycache__/lex.cpython-36.pyc create mode 100644 venv/Lib/site-packages/pycparser/ply/__pycache__/yacc.cpython-36.pyc create mode 100644 venv/Lib/site-packages/pycparser/ply/__pycache__/ygen.cpython-36.pyc create mode 100644 venv/Lib/site-packages/pycparser/ply/cpp.py create mode 100644 venv/Lib/site-packages/pycparser/ply/ctokens.py create mode 100644 venv/Lib/site-packages/pycparser/ply/lex.py create mode 100644 venv/Lib/site-packages/pycparser/ply/yacc.py create mode 100644 venv/Lib/site-packages/pycparser/ply/ygen.py create mode 100644 venv/Lib/site-packages/pycparser/plyparser.py create mode 100644 venv/Lib/site-packages/pycparser/yacctab.py create mode 100644 venv/Lib/site-packages/pytz-2020.1.dist-info/DESCRIPTION.rst create mode 100644 venv/Lib/site-packages/pytz-2020.1.dist-info/INSTALLER create mode 100644 venv/Lib/site-packages/pytz-2020.1.dist-info/LICENSE.txt create mode 100644 venv/Lib/site-packages/pytz-2020.1.dist-info/METADATA create mode 100644 venv/Lib/site-packages/pytz-2020.1.dist-info/RECORD create mode 100644 venv/Lib/site-packages/pytz-2020.1.dist-info/WHEEL create mode 100644 venv/Lib/site-packages/pytz-2020.1.dist-info/metadata.json create mode 100644 venv/Lib/site-packages/pytz-2020.1.dist-info/top_level.txt create mode 100644 venv/Lib/site-packages/pytz-2020.1.dist-info/zip-safe create mode 100644 venv/Lib/site-packages/pytz/__init__.py create mode 100644 venv/Lib/site-packages/pytz/__pycache__/__init__.cpython-36.pyc create mode 100644 venv/Lib/site-packages/pytz/__pycache__/exceptions.cpython-36.pyc create mode 100644 venv/Lib/site-packages/pytz/__pycache__/lazy.cpython-36.pyc create mode 100644 venv/Lib/site-packages/pytz/__pycache__/reference.cpython-36.pyc create mode 100644 venv/Lib/site-packages/pytz/__pycache__/tzfile.cpython-36.pyc create mode 100644 venv/Lib/site-packages/pytz/__pycache__/tzinfo.cpython-36.pyc create mode 100644 venv/Lib/site-packages/pytz/exceptions.py create mode 100644 venv/Lib/site-packages/pytz/lazy.py create mode 100644 venv/Lib/site-packages/pytz/reference.py create mode 100644 venv/Lib/site-packages/pytz/tzfile.py create mode 100644 venv/Lib/site-packages/pytz/tzinfo.py create mode 100644 venv/Lib/site-packages/pytz/zoneinfo/Africa/Abidjan create mode 100644 venv/Lib/site-packages/pytz/zoneinfo/Africa/Accra create mode 100644 venv/Lib/site-packages/pytz/zoneinfo/Africa/Addis_Ababa create mode 100644 venv/Lib/site-packages/pytz/zoneinfo/Africa/Algiers create mode 100644 venv/Lib/site-packages/pytz/zoneinfo/Africa/Asmara create mode 100644 venv/Lib/site-packages/pytz/zoneinfo/Africa/Asmera create mode 100644 venv/Lib/site-packages/pytz/zoneinfo/Africa/Bamako create mode 100644 venv/Lib/site-packages/pytz/zoneinfo/Africa/Bangui create mode 100644 venv/Lib/site-packages/pytz/zoneinfo/Africa/Banjul create mode 100644 venv/Lib/site-packages/pytz/zoneinfo/Africa/Bissau create mode 100644 venv/Lib/site-packages/pytz/zoneinfo/Africa/Blantyre create mode 100644 venv/Lib/site-packages/pytz/zoneinfo/Africa/Brazzaville create mode 100644 venv/Lib/site-packages/pytz/zoneinfo/Africa/Bujumbura create mode 100644 venv/Lib/site-packages/pytz/zoneinfo/Africa/Cairo create mode 100644 venv/Lib/site-packages/pytz/zoneinfo/Africa/Casablanca create mode 100644 venv/Lib/site-packages/pytz/zoneinfo/Africa/Ceuta create mode 100644 venv/Lib/site-packages/pytz/zoneinfo/Africa/Conakry create mode 100644 venv/Lib/site-packages/pytz/zoneinfo/Africa/Dakar create mode 100644 venv/Lib/site-packages/pytz/zoneinfo/Africa/Dar_es_Salaam create mode 100644 venv/Lib/site-packages/pytz/zoneinfo/Africa/Djibouti create mode 100644 venv/Lib/site-packages/pytz/zoneinfo/Africa/Douala create mode 100644 venv/Lib/site-packages/pytz/zoneinfo/Africa/El_Aaiun create mode 100644 venv/Lib/site-packages/pytz/zoneinfo/Africa/Freetown create mode 100644 venv/Lib/site-packages/pytz/zoneinfo/Africa/Gaborone create mode 100644 venv/Lib/site-packages/pytz/zoneinfo/Africa/Harare create mode 100644 venv/Lib/site-packages/pytz/zoneinfo/Africa/Johannesburg create mode 100644 venv/Lib/site-packages/pytz/zoneinfo/Africa/Juba create mode 100644 venv/Lib/site-packages/pytz/zoneinfo/Africa/Kampala create mode 100644 venv/Lib/site-packages/pytz/zoneinfo/Africa/Khartoum create mode 100644 venv/Lib/site-packages/pytz/zoneinfo/Africa/Kigali create mode 100644 venv/Lib/site-packages/pytz/zoneinfo/Africa/Kinshasa create mode 100644 venv/Lib/site-packages/pytz/zoneinfo/Africa/Lagos create mode 100644 venv/Lib/site-packages/pytz/zoneinfo/Africa/Libreville create mode 100644 venv/Lib/site-packages/pytz/zoneinfo/Africa/Lome create mode 100644 venv/Lib/site-packages/pytz/zoneinfo/Africa/Luanda create mode 100644 venv/Lib/site-packages/pytz/zoneinfo/Africa/Lubumbashi create mode 100644 venv/Lib/site-packages/pytz/zoneinfo/Africa/Lusaka create mode 100644 venv/Lib/site-packages/pytz/zoneinfo/Africa/Malabo create mode 100644 venv/Lib/site-packages/pytz/zoneinfo/Africa/Maputo create mode 100644 venv/Lib/site-packages/pytz/zoneinfo/Africa/Maseru create mode 100644 venv/Lib/site-packages/pytz/zoneinfo/Africa/Mbabane create mode 100644 venv/Lib/site-packages/pytz/zoneinfo/Africa/Mogadishu create mode 100644 venv/Lib/site-packages/pytz/zoneinfo/Africa/Monrovia create mode 100644 venv/Lib/site-packages/pytz/zoneinfo/Africa/Nairobi create mode 100644 venv/Lib/site-packages/pytz/zoneinfo/Africa/Ndjamena create mode 100644 venv/Lib/site-packages/pytz/zoneinfo/Africa/Niamey create mode 100644 venv/Lib/site-packages/pytz/zoneinfo/Africa/Nouakchott create mode 100644 venv/Lib/site-packages/pytz/zoneinfo/Africa/Ouagadougou create mode 100644 venv/Lib/site-packages/pytz/zoneinfo/Africa/Porto-Novo create mode 100644 venv/Lib/site-packages/pytz/zoneinfo/Africa/Sao_Tome create mode 100644 venv/Lib/site-packages/pytz/zoneinfo/Africa/Timbuktu create mode 100644 venv/Lib/site-packages/pytz/zoneinfo/Africa/Tripoli create mode 100644 venv/Lib/site-packages/pytz/zoneinfo/Africa/Tunis create mode 100644 venv/Lib/site-packages/pytz/zoneinfo/Africa/Windhoek create mode 100644 venv/Lib/site-packages/pytz/zoneinfo/America/Adak create mode 100644 venv/Lib/site-packages/pytz/zoneinfo/America/Anchorage create mode 100644 venv/Lib/site-packages/pytz/zoneinfo/America/Anguilla create mode 100644 venv/Lib/site-packages/pytz/zoneinfo/America/Antigua create mode 100644 venv/Lib/site-packages/pytz/zoneinfo/America/Araguaina create mode 100644 venv/Lib/site-packages/pytz/zoneinfo/America/Argentina/Buenos_Aires create mode 100644 venv/Lib/site-packages/pytz/zoneinfo/America/Argentina/Catamarca create mode 100644 venv/Lib/site-packages/pytz/zoneinfo/America/Argentina/ComodRivadavia create mode 100644 venv/Lib/site-packages/pytz/zoneinfo/America/Argentina/Cordoba create mode 100644 venv/Lib/site-packages/pytz/zoneinfo/America/Argentina/Jujuy create mode 100644 venv/Lib/site-packages/pytz/zoneinfo/America/Argentina/La_Rioja create mode 100644 venv/Lib/site-packages/pytz/zoneinfo/America/Argentina/Mendoza create mode 100644 venv/Lib/site-packages/pytz/zoneinfo/America/Argentina/Rio_Gallegos create mode 100644 venv/Lib/site-packages/pytz/zoneinfo/America/Argentina/Salta create mode 100644 venv/Lib/site-packages/pytz/zoneinfo/America/Argentina/San_Juan create mode 100644 venv/Lib/site-packages/pytz/zoneinfo/America/Argentina/San_Luis create mode 100644 venv/Lib/site-packages/pytz/zoneinfo/America/Argentina/Tucuman create mode 100644 venv/Lib/site-packages/pytz/zoneinfo/America/Argentina/Ushuaia create mode 100644 venv/Lib/site-packages/pytz/zoneinfo/America/Aruba create mode 100644 venv/Lib/site-packages/pytz/zoneinfo/America/Asuncion create mode 100644 venv/Lib/site-packages/pytz/zoneinfo/America/Atikokan create mode 100644 venv/Lib/site-packages/pytz/zoneinfo/America/Atka create mode 100644 venv/Lib/site-packages/pytz/zoneinfo/America/Bahia create mode 100644 venv/Lib/site-packages/pytz/zoneinfo/America/Bahia_Banderas create mode 100644 venv/Lib/site-packages/pytz/zoneinfo/America/Barbados create mode 100644 venv/Lib/site-packages/pytz/zoneinfo/America/Belem create mode 100644 venv/Lib/site-packages/pytz/zoneinfo/America/Belize create mode 100644 venv/Lib/site-packages/pytz/zoneinfo/America/Blanc-Sablon create mode 100644 venv/Lib/site-packages/pytz/zoneinfo/America/Boa_Vista create mode 100644 venv/Lib/site-packages/pytz/zoneinfo/America/Bogota create mode 100644 venv/Lib/site-packages/pytz/zoneinfo/America/Boise create mode 100644 venv/Lib/site-packages/pytz/zoneinfo/America/Buenos_Aires create mode 100644 venv/Lib/site-packages/pytz/zoneinfo/America/Cambridge_Bay create mode 100644 venv/Lib/site-packages/pytz/zoneinfo/America/Campo_Grande create mode 100644 venv/Lib/site-packages/pytz/zoneinfo/America/Cancun create mode 100644 venv/Lib/site-packages/pytz/zoneinfo/America/Caracas create mode 100644 venv/Lib/site-packages/pytz/zoneinfo/America/Catamarca create mode 100644 venv/Lib/site-packages/pytz/zoneinfo/America/Cayenne create mode 100644 venv/Lib/site-packages/pytz/zoneinfo/America/Cayman create mode 100644 venv/Lib/site-packages/pytz/zoneinfo/America/Chicago create mode 100644 venv/Lib/site-packages/pytz/zoneinfo/America/Chihuahua create mode 100644 venv/Lib/site-packages/pytz/zoneinfo/America/Coral_Harbour create mode 100644 venv/Lib/site-packages/pytz/zoneinfo/America/Cordoba create mode 100644 venv/Lib/site-packages/pytz/zoneinfo/America/Costa_Rica create mode 100644 venv/Lib/site-packages/pytz/zoneinfo/America/Creston create mode 100644 venv/Lib/site-packages/pytz/zoneinfo/America/Cuiaba create mode 100644 venv/Lib/site-packages/pytz/zoneinfo/America/Curacao create mode 100644 venv/Lib/site-packages/pytz/zoneinfo/America/Danmarkshavn create mode 100644 venv/Lib/site-packages/pytz/zoneinfo/America/Dawson create mode 100644 venv/Lib/site-packages/pytz/zoneinfo/America/Dawson_Creek create mode 100644 venv/Lib/site-packages/pytz/zoneinfo/America/Denver create mode 100644 venv/Lib/site-packages/pytz/zoneinfo/America/Detroit create mode 100644 venv/Lib/site-packages/pytz/zoneinfo/America/Dominica create mode 100644 venv/Lib/site-packages/pytz/zoneinfo/America/Edmonton create mode 100644 venv/Lib/site-packages/pytz/zoneinfo/America/Eirunepe create mode 100644 venv/Lib/site-packages/pytz/zoneinfo/America/El_Salvador create mode 100644 venv/Lib/site-packages/pytz/zoneinfo/America/Ensenada create mode 100644 venv/Lib/site-packages/pytz/zoneinfo/America/Fort_Nelson create mode 100644 venv/Lib/site-packages/pytz/zoneinfo/America/Fort_Wayne create mode 100644 venv/Lib/site-packages/pytz/zoneinfo/America/Fortaleza create mode 100644 venv/Lib/site-packages/pytz/zoneinfo/America/Glace_Bay create mode 100644 venv/Lib/site-packages/pytz/zoneinfo/America/Godthab create mode 100644 venv/Lib/site-packages/pytz/zoneinfo/America/Goose_Bay create mode 100644 venv/Lib/site-packages/pytz/zoneinfo/America/Grand_Turk create mode 100644 venv/Lib/site-packages/pytz/zoneinfo/America/Grenada create mode 100644 venv/Lib/site-packages/pytz/zoneinfo/America/Guadeloupe create mode 100644 venv/Lib/site-packages/pytz/zoneinfo/America/Guatemala create mode 100644 venv/Lib/site-packages/pytz/zoneinfo/America/Guayaquil create mode 100644 venv/Lib/site-packages/pytz/zoneinfo/America/Guyana create mode 100644 venv/Lib/site-packages/pytz/zoneinfo/America/Halifax create mode 100644 venv/Lib/site-packages/pytz/zoneinfo/America/Havana create mode 100644 venv/Lib/site-packages/pytz/zoneinfo/America/Hermosillo create mode 100644 venv/Lib/site-packages/pytz/zoneinfo/America/Indiana/Indianapolis create mode 100644 venv/Lib/site-packages/pytz/zoneinfo/America/Indiana/Knox create mode 100644 venv/Lib/site-packages/pytz/zoneinfo/America/Indiana/Marengo create mode 100644 venv/Lib/site-packages/pytz/zoneinfo/America/Indiana/Petersburg create mode 100644 venv/Lib/site-packages/pytz/zoneinfo/America/Indiana/Tell_City create mode 100644 venv/Lib/site-packages/pytz/zoneinfo/America/Indiana/Vevay create mode 100644 venv/Lib/site-packages/pytz/zoneinfo/America/Indiana/Vincennes create mode 100644 venv/Lib/site-packages/pytz/zoneinfo/America/Indiana/Winamac create mode 100644 venv/Lib/site-packages/pytz/zoneinfo/America/Indianapolis create mode 100644 venv/Lib/site-packages/pytz/zoneinfo/America/Inuvik create mode 100644 venv/Lib/site-packages/pytz/zoneinfo/America/Iqaluit create mode 100644 venv/Lib/site-packages/pytz/zoneinfo/America/Jamaica create mode 100644 venv/Lib/site-packages/pytz/zoneinfo/America/Jujuy create mode 100644 venv/Lib/site-packages/pytz/zoneinfo/America/Juneau create mode 100644 venv/Lib/site-packages/pytz/zoneinfo/America/Kentucky/Louisville create mode 100644 venv/Lib/site-packages/pytz/zoneinfo/America/Kentucky/Monticello create mode 100644 venv/Lib/site-packages/pytz/zoneinfo/America/Knox_IN create mode 100644 venv/Lib/site-packages/pytz/zoneinfo/America/Kralendijk create mode 100644 venv/Lib/site-packages/pytz/zoneinfo/America/La_Paz create mode 100644 venv/Lib/site-packages/pytz/zoneinfo/America/Lima create mode 100644 venv/Lib/site-packages/pytz/zoneinfo/America/Los_Angeles create mode 100644 venv/Lib/site-packages/pytz/zoneinfo/America/Louisville create mode 100644 venv/Lib/site-packages/pytz/zoneinfo/America/Lower_Princes create mode 100644 venv/Lib/site-packages/pytz/zoneinfo/America/Maceio create mode 100644 venv/Lib/site-packages/pytz/zoneinfo/America/Managua create mode 100644 venv/Lib/site-packages/pytz/zoneinfo/America/Manaus create mode 100644 venv/Lib/site-packages/pytz/zoneinfo/America/Marigot create mode 100644 venv/Lib/site-packages/pytz/zoneinfo/America/Martinique create mode 100644 venv/Lib/site-packages/pytz/zoneinfo/America/Matamoros create mode 100644 venv/Lib/site-packages/pytz/zoneinfo/America/Mazatlan create mode 100644 venv/Lib/site-packages/pytz/zoneinfo/America/Mendoza create mode 100644 venv/Lib/site-packages/pytz/zoneinfo/America/Menominee create mode 100644 venv/Lib/site-packages/pytz/zoneinfo/America/Merida create mode 100644 venv/Lib/site-packages/pytz/zoneinfo/America/Metlakatla create mode 100644 venv/Lib/site-packages/pytz/zoneinfo/America/Mexico_City create mode 100644 venv/Lib/site-packages/pytz/zoneinfo/America/Miquelon create mode 100644 venv/Lib/site-packages/pytz/zoneinfo/America/Moncton create mode 100644 venv/Lib/site-packages/pytz/zoneinfo/America/Monterrey create mode 100644 venv/Lib/site-packages/pytz/zoneinfo/America/Montevideo create mode 100644 venv/Lib/site-packages/pytz/zoneinfo/America/Montreal create mode 100644 venv/Lib/site-packages/pytz/zoneinfo/America/Montserrat create mode 100644 venv/Lib/site-packages/pytz/zoneinfo/America/Nassau create mode 100644 venv/Lib/site-packages/pytz/zoneinfo/America/New_York create mode 100644 venv/Lib/site-packages/pytz/zoneinfo/America/Nipigon create mode 100644 venv/Lib/site-packages/pytz/zoneinfo/America/Nome create mode 100644 venv/Lib/site-packages/pytz/zoneinfo/America/Noronha create mode 100644 venv/Lib/site-packages/pytz/zoneinfo/America/North_Dakota/Beulah create mode 100644 venv/Lib/site-packages/pytz/zoneinfo/America/North_Dakota/Center create mode 100644 venv/Lib/site-packages/pytz/zoneinfo/America/North_Dakota/New_Salem create mode 100644 venv/Lib/site-packages/pytz/zoneinfo/America/Nuuk create mode 100644 venv/Lib/site-packages/pytz/zoneinfo/America/Ojinaga create mode 100644 venv/Lib/site-packages/pytz/zoneinfo/America/Panama create mode 100644 venv/Lib/site-packages/pytz/zoneinfo/America/Pangnirtung create mode 100644 venv/Lib/site-packages/pytz/zoneinfo/America/Paramaribo create mode 100644 venv/Lib/site-packages/pytz/zoneinfo/America/Phoenix create mode 100644 venv/Lib/site-packages/pytz/zoneinfo/America/Port-au-Prince create mode 100644 venv/Lib/site-packages/pytz/zoneinfo/America/Port_of_Spain create mode 100644 venv/Lib/site-packages/pytz/zoneinfo/America/Porto_Acre create mode 100644 venv/Lib/site-packages/pytz/zoneinfo/America/Porto_Velho create mode 100644 venv/Lib/site-packages/pytz/zoneinfo/America/Puerto_Rico create mode 100644 venv/Lib/site-packages/pytz/zoneinfo/America/Punta_Arenas create mode 100644 venv/Lib/site-packages/pytz/zoneinfo/America/Rainy_River create mode 100644 venv/Lib/site-packages/pytz/zoneinfo/America/Rankin_Inlet create mode 100644 venv/Lib/site-packages/pytz/zoneinfo/America/Recife create mode 100644 venv/Lib/site-packages/pytz/zoneinfo/America/Regina create mode 100644 venv/Lib/site-packages/pytz/zoneinfo/America/Resolute create mode 100644 venv/Lib/site-packages/pytz/zoneinfo/America/Rio_Branco create mode 100644 venv/Lib/site-packages/pytz/zoneinfo/America/Rosario create mode 100644 venv/Lib/site-packages/pytz/zoneinfo/America/Santa_Isabel create mode 100644 venv/Lib/site-packages/pytz/zoneinfo/America/Santarem create mode 100644 venv/Lib/site-packages/pytz/zoneinfo/America/Santiago create mode 100644 venv/Lib/site-packages/pytz/zoneinfo/America/Santo_Domingo create mode 100644 venv/Lib/site-packages/pytz/zoneinfo/America/Sao_Paulo create mode 100644 venv/Lib/site-packages/pytz/zoneinfo/America/Scoresbysund create mode 100644 venv/Lib/site-packages/pytz/zoneinfo/America/Shiprock create mode 100644 venv/Lib/site-packages/pytz/zoneinfo/America/Sitka create mode 100644 venv/Lib/site-packages/pytz/zoneinfo/America/St_Barthelemy create mode 100644 venv/Lib/site-packages/pytz/zoneinfo/America/St_Johns create mode 100644 venv/Lib/site-packages/pytz/zoneinfo/America/St_Kitts create mode 100644 venv/Lib/site-packages/pytz/zoneinfo/America/St_Lucia create mode 100644 venv/Lib/site-packages/pytz/zoneinfo/America/St_Thomas create mode 100644 venv/Lib/site-packages/pytz/zoneinfo/America/St_Vincent create mode 100644 venv/Lib/site-packages/pytz/zoneinfo/America/Swift_Current create mode 100644 venv/Lib/site-packages/pytz/zoneinfo/America/Tegucigalpa create mode 100644 venv/Lib/site-packages/pytz/zoneinfo/America/Thule create mode 100644 venv/Lib/site-packages/pytz/zoneinfo/America/Thunder_Bay create mode 100644 venv/Lib/site-packages/pytz/zoneinfo/America/Tijuana create mode 100644 venv/Lib/site-packages/pytz/zoneinfo/America/Toronto create mode 100644 venv/Lib/site-packages/pytz/zoneinfo/America/Tortola create mode 100644 venv/Lib/site-packages/pytz/zoneinfo/America/Vancouver create mode 100644 venv/Lib/site-packages/pytz/zoneinfo/America/Virgin create mode 100644 venv/Lib/site-packages/pytz/zoneinfo/America/Whitehorse create mode 100644 venv/Lib/site-packages/pytz/zoneinfo/America/Winnipeg create mode 100644 venv/Lib/site-packages/pytz/zoneinfo/America/Yakutat create mode 100644 venv/Lib/site-packages/pytz/zoneinfo/America/Yellowknife create mode 100644 venv/Lib/site-packages/pytz/zoneinfo/Antarctica/Casey create mode 100644 venv/Lib/site-packages/pytz/zoneinfo/Antarctica/Davis create mode 100644 venv/Lib/site-packages/pytz/zoneinfo/Antarctica/DumontDUrville create mode 100644 venv/Lib/site-packages/pytz/zoneinfo/Antarctica/Macquarie create mode 100644 venv/Lib/site-packages/pytz/zoneinfo/Antarctica/Mawson create mode 100644 venv/Lib/site-packages/pytz/zoneinfo/Antarctica/McMurdo create mode 100644 venv/Lib/site-packages/pytz/zoneinfo/Antarctica/Palmer create mode 100644 venv/Lib/site-packages/pytz/zoneinfo/Antarctica/Rothera create mode 100644 venv/Lib/site-packages/pytz/zoneinfo/Antarctica/South_Pole create mode 100644 venv/Lib/site-packages/pytz/zoneinfo/Antarctica/Syowa create mode 100644 venv/Lib/site-packages/pytz/zoneinfo/Antarctica/Troll create mode 100644 venv/Lib/site-packages/pytz/zoneinfo/Antarctica/Vostok create mode 100644 venv/Lib/site-packages/pytz/zoneinfo/Arctic/Longyearbyen create mode 100644 venv/Lib/site-packages/pytz/zoneinfo/Asia/Aden create mode 100644 venv/Lib/site-packages/pytz/zoneinfo/Asia/Almaty create mode 100644 venv/Lib/site-packages/pytz/zoneinfo/Asia/Amman create mode 100644 venv/Lib/site-packages/pytz/zoneinfo/Asia/Anadyr create mode 100644 venv/Lib/site-packages/pytz/zoneinfo/Asia/Aqtau create mode 100644 venv/Lib/site-packages/pytz/zoneinfo/Asia/Aqtobe create mode 100644 venv/Lib/site-packages/pytz/zoneinfo/Asia/Ashgabat create mode 100644 venv/Lib/site-packages/pytz/zoneinfo/Asia/Ashkhabad create mode 100644 venv/Lib/site-packages/pytz/zoneinfo/Asia/Atyrau create mode 100644 venv/Lib/site-packages/pytz/zoneinfo/Asia/Baghdad create mode 100644 venv/Lib/site-packages/pytz/zoneinfo/Asia/Bahrain create mode 100644 venv/Lib/site-packages/pytz/zoneinfo/Asia/Baku create mode 100644 venv/Lib/site-packages/pytz/zoneinfo/Asia/Bangkok create mode 100644 venv/Lib/site-packages/pytz/zoneinfo/Asia/Barnaul create mode 100644 venv/Lib/site-packages/pytz/zoneinfo/Asia/Beirut create mode 100644 venv/Lib/site-packages/pytz/zoneinfo/Asia/Bishkek create mode 100644 venv/Lib/site-packages/pytz/zoneinfo/Asia/Brunei create mode 100644 venv/Lib/site-packages/pytz/zoneinfo/Asia/Calcutta create mode 100644 venv/Lib/site-packages/pytz/zoneinfo/Asia/Chita create mode 100644 venv/Lib/site-packages/pytz/zoneinfo/Asia/Choibalsan create mode 100644 venv/Lib/site-packages/pytz/zoneinfo/Asia/Chongqing create mode 100644 venv/Lib/site-packages/pytz/zoneinfo/Asia/Chungking create mode 100644 venv/Lib/site-packages/pytz/zoneinfo/Asia/Colombo create mode 100644 venv/Lib/site-packages/pytz/zoneinfo/Asia/Dacca create mode 100644 venv/Lib/site-packages/pytz/zoneinfo/Asia/Damascus create mode 100644 venv/Lib/site-packages/pytz/zoneinfo/Asia/Dhaka create mode 100644 venv/Lib/site-packages/pytz/zoneinfo/Asia/Dili create mode 100644 venv/Lib/site-packages/pytz/zoneinfo/Asia/Dubai create mode 100644 venv/Lib/site-packages/pytz/zoneinfo/Asia/Dushanbe create mode 100644 venv/Lib/site-packages/pytz/zoneinfo/Asia/Famagusta create mode 100644 venv/Lib/site-packages/pytz/zoneinfo/Asia/Gaza create mode 100644 venv/Lib/site-packages/pytz/zoneinfo/Asia/Harbin create mode 100644 venv/Lib/site-packages/pytz/zoneinfo/Asia/Hebron create mode 100644 venv/Lib/site-packages/pytz/zoneinfo/Asia/Ho_Chi_Minh create mode 100644 venv/Lib/site-packages/pytz/zoneinfo/Asia/Hong_Kong create mode 100644 venv/Lib/site-packages/pytz/zoneinfo/Asia/Hovd create mode 100644 venv/Lib/site-packages/pytz/zoneinfo/Asia/Irkutsk create mode 100644 venv/Lib/site-packages/pytz/zoneinfo/Asia/Istanbul create mode 100644 venv/Lib/site-packages/pytz/zoneinfo/Asia/Jakarta create mode 100644 venv/Lib/site-packages/pytz/zoneinfo/Asia/Jayapura create mode 100644 venv/Lib/site-packages/pytz/zoneinfo/Asia/Jerusalem create mode 100644 venv/Lib/site-packages/pytz/zoneinfo/Asia/Kabul create mode 100644 venv/Lib/site-packages/pytz/zoneinfo/Asia/Kamchatka create mode 100644 venv/Lib/site-packages/pytz/zoneinfo/Asia/Karachi create mode 100644 venv/Lib/site-packages/pytz/zoneinfo/Asia/Kashgar create mode 100644 venv/Lib/site-packages/pytz/zoneinfo/Asia/Kathmandu create mode 100644 venv/Lib/site-packages/pytz/zoneinfo/Asia/Katmandu create mode 100644 venv/Lib/site-packages/pytz/zoneinfo/Asia/Khandyga create mode 100644 venv/Lib/site-packages/pytz/zoneinfo/Asia/Kolkata create mode 100644 venv/Lib/site-packages/pytz/zoneinfo/Asia/Krasnoyarsk create mode 100644 venv/Lib/site-packages/pytz/zoneinfo/Asia/Kuala_Lumpur create mode 100644 venv/Lib/site-packages/pytz/zoneinfo/Asia/Kuching create mode 100644 venv/Lib/site-packages/pytz/zoneinfo/Asia/Kuwait create mode 100644 venv/Lib/site-packages/pytz/zoneinfo/Asia/Macao create mode 100644 venv/Lib/site-packages/pytz/zoneinfo/Asia/Macau create mode 100644 venv/Lib/site-packages/pytz/zoneinfo/Asia/Magadan create mode 100644 venv/Lib/site-packages/pytz/zoneinfo/Asia/Makassar create mode 100644 venv/Lib/site-packages/pytz/zoneinfo/Asia/Manila create mode 100644 venv/Lib/site-packages/pytz/zoneinfo/Asia/Muscat create mode 100644 venv/Lib/site-packages/pytz/zoneinfo/Asia/Nicosia create mode 100644 venv/Lib/site-packages/pytz/zoneinfo/Asia/Novokuznetsk create mode 100644 venv/Lib/site-packages/pytz/zoneinfo/Asia/Novosibirsk create mode 100644 venv/Lib/site-packages/pytz/zoneinfo/Asia/Omsk create mode 100644 venv/Lib/site-packages/pytz/zoneinfo/Asia/Oral create mode 100644 venv/Lib/site-packages/pytz/zoneinfo/Asia/Phnom_Penh create mode 100644 venv/Lib/site-packages/pytz/zoneinfo/Asia/Pontianak create mode 100644 venv/Lib/site-packages/pytz/zoneinfo/Asia/Pyongyang create mode 100644 venv/Lib/site-packages/pytz/zoneinfo/Asia/Qatar create mode 100644 venv/Lib/site-packages/pytz/zoneinfo/Asia/Qostanay create mode 100644 venv/Lib/site-packages/pytz/zoneinfo/Asia/Qyzylorda create mode 100644 venv/Lib/site-packages/pytz/zoneinfo/Asia/Rangoon create mode 100644 venv/Lib/site-packages/pytz/zoneinfo/Asia/Riyadh create mode 100644 venv/Lib/site-packages/pytz/zoneinfo/Asia/Saigon create mode 100644 venv/Lib/site-packages/pytz/zoneinfo/Asia/Sakhalin create mode 100644 venv/Lib/site-packages/pytz/zoneinfo/Asia/Samarkand create mode 100644 venv/Lib/site-packages/pytz/zoneinfo/Asia/Seoul create mode 100644 venv/Lib/site-packages/pytz/zoneinfo/Asia/Shanghai create mode 100644 venv/Lib/site-packages/pytz/zoneinfo/Asia/Singapore create mode 100644 venv/Lib/site-packages/pytz/zoneinfo/Asia/Srednekolymsk create mode 100644 venv/Lib/site-packages/pytz/zoneinfo/Asia/Taipei create mode 100644 venv/Lib/site-packages/pytz/zoneinfo/Asia/Tashkent create mode 100644 venv/Lib/site-packages/pytz/zoneinfo/Asia/Tbilisi create mode 100644 venv/Lib/site-packages/pytz/zoneinfo/Asia/Tehran create mode 100644 venv/Lib/site-packages/pytz/zoneinfo/Asia/Tel_Aviv create mode 100644 venv/Lib/site-packages/pytz/zoneinfo/Asia/Thimbu create mode 100644 venv/Lib/site-packages/pytz/zoneinfo/Asia/Thimphu create mode 100644 venv/Lib/site-packages/pytz/zoneinfo/Asia/Tokyo create mode 100644 venv/Lib/site-packages/pytz/zoneinfo/Asia/Tomsk create mode 100644 venv/Lib/site-packages/pytz/zoneinfo/Asia/Ujung_Pandang create mode 100644 venv/Lib/site-packages/pytz/zoneinfo/Asia/Ulaanbaatar create mode 100644 venv/Lib/site-packages/pytz/zoneinfo/Asia/Ulan_Bator create mode 100644 venv/Lib/site-packages/pytz/zoneinfo/Asia/Urumqi create mode 100644 venv/Lib/site-packages/pytz/zoneinfo/Asia/Ust-Nera create mode 100644 venv/Lib/site-packages/pytz/zoneinfo/Asia/Vientiane create mode 100644 venv/Lib/site-packages/pytz/zoneinfo/Asia/Vladivostok create mode 100644 venv/Lib/site-packages/pytz/zoneinfo/Asia/Yakutsk create mode 100644 venv/Lib/site-packages/pytz/zoneinfo/Asia/Yangon create mode 100644 venv/Lib/site-packages/pytz/zoneinfo/Asia/Yekaterinburg create mode 100644 venv/Lib/site-packages/pytz/zoneinfo/Asia/Yerevan create mode 100644 venv/Lib/site-packages/pytz/zoneinfo/Atlantic/Azores create mode 100644 venv/Lib/site-packages/pytz/zoneinfo/Atlantic/Bermuda create mode 100644 venv/Lib/site-packages/pytz/zoneinfo/Atlantic/Canary create mode 100644 venv/Lib/site-packages/pytz/zoneinfo/Atlantic/Cape_Verde create mode 100644 venv/Lib/site-packages/pytz/zoneinfo/Atlantic/Faeroe create mode 100644 venv/Lib/site-packages/pytz/zoneinfo/Atlantic/Faroe create mode 100644 venv/Lib/site-packages/pytz/zoneinfo/Atlantic/Jan_Mayen create mode 100644 venv/Lib/site-packages/pytz/zoneinfo/Atlantic/Madeira create mode 100644 venv/Lib/site-packages/pytz/zoneinfo/Atlantic/Reykjavik create mode 100644 venv/Lib/site-packages/pytz/zoneinfo/Atlantic/South_Georgia create mode 100644 venv/Lib/site-packages/pytz/zoneinfo/Atlantic/St_Helena create mode 100644 venv/Lib/site-packages/pytz/zoneinfo/Atlantic/Stanley create mode 100644 venv/Lib/site-packages/pytz/zoneinfo/Australia/ACT create mode 100644 venv/Lib/site-packages/pytz/zoneinfo/Australia/Adelaide create mode 100644 venv/Lib/site-packages/pytz/zoneinfo/Australia/Brisbane create mode 100644 venv/Lib/site-packages/pytz/zoneinfo/Australia/Broken_Hill create mode 100644 venv/Lib/site-packages/pytz/zoneinfo/Australia/Canberra create mode 100644 venv/Lib/site-packages/pytz/zoneinfo/Australia/Currie create mode 100644 venv/Lib/site-packages/pytz/zoneinfo/Australia/Darwin create mode 100644 venv/Lib/site-packages/pytz/zoneinfo/Australia/Eucla create mode 100644 venv/Lib/site-packages/pytz/zoneinfo/Australia/Hobart create mode 100644 venv/Lib/site-packages/pytz/zoneinfo/Australia/LHI create mode 100644 venv/Lib/site-packages/pytz/zoneinfo/Australia/Lindeman create mode 100644 venv/Lib/site-packages/pytz/zoneinfo/Australia/Lord_Howe create mode 100644 venv/Lib/site-packages/pytz/zoneinfo/Australia/Melbourne create mode 100644 venv/Lib/site-packages/pytz/zoneinfo/Australia/NSW create mode 100644 venv/Lib/site-packages/pytz/zoneinfo/Australia/North create mode 100644 venv/Lib/site-packages/pytz/zoneinfo/Australia/Perth create mode 100644 venv/Lib/site-packages/pytz/zoneinfo/Australia/Queensland create mode 100644 venv/Lib/site-packages/pytz/zoneinfo/Australia/South create mode 100644 venv/Lib/site-packages/pytz/zoneinfo/Australia/Sydney create mode 100644 venv/Lib/site-packages/pytz/zoneinfo/Australia/Tasmania create mode 100644 venv/Lib/site-packages/pytz/zoneinfo/Australia/Victoria create mode 100644 venv/Lib/site-packages/pytz/zoneinfo/Australia/West create mode 100644 venv/Lib/site-packages/pytz/zoneinfo/Australia/Yancowinna create mode 100644 venv/Lib/site-packages/pytz/zoneinfo/Brazil/Acre create mode 100644 venv/Lib/site-packages/pytz/zoneinfo/Brazil/DeNoronha create mode 100644 venv/Lib/site-packages/pytz/zoneinfo/Brazil/East create mode 100644 venv/Lib/site-packages/pytz/zoneinfo/Brazil/West create mode 100644 venv/Lib/site-packages/pytz/zoneinfo/CET create mode 100644 venv/Lib/site-packages/pytz/zoneinfo/CST6CDT create mode 100644 venv/Lib/site-packages/pytz/zoneinfo/Canada/Atlantic create mode 100644 venv/Lib/site-packages/pytz/zoneinfo/Canada/Central create mode 100644 venv/Lib/site-packages/pytz/zoneinfo/Canada/Eastern create mode 100644 venv/Lib/site-packages/pytz/zoneinfo/Canada/Mountain create mode 100644 venv/Lib/site-packages/pytz/zoneinfo/Canada/Newfoundland create mode 100644 venv/Lib/site-packages/pytz/zoneinfo/Canada/Pacific create mode 100644 venv/Lib/site-packages/pytz/zoneinfo/Canada/Saskatchewan create mode 100644 venv/Lib/site-packages/pytz/zoneinfo/Canada/Yukon create mode 100644 venv/Lib/site-packages/pytz/zoneinfo/Chile/Continental create mode 100644 venv/Lib/site-packages/pytz/zoneinfo/Chile/EasterIsland create mode 100644 venv/Lib/site-packages/pytz/zoneinfo/Cuba create mode 100644 venv/Lib/site-packages/pytz/zoneinfo/EET create mode 100644 venv/Lib/site-packages/pytz/zoneinfo/EST create mode 100644 venv/Lib/site-packages/pytz/zoneinfo/EST5EDT create mode 100644 venv/Lib/site-packages/pytz/zoneinfo/Egypt create mode 100644 venv/Lib/site-packages/pytz/zoneinfo/Eire create mode 100644 venv/Lib/site-packages/pytz/zoneinfo/Etc/GMT create mode 100644 venv/Lib/site-packages/pytz/zoneinfo/Etc/GMT+0 create mode 100644 venv/Lib/site-packages/pytz/zoneinfo/Etc/GMT+1 create mode 100644 venv/Lib/site-packages/pytz/zoneinfo/Etc/GMT+10 create mode 100644 venv/Lib/site-packages/pytz/zoneinfo/Etc/GMT+11 create mode 100644 venv/Lib/site-packages/pytz/zoneinfo/Etc/GMT+12 create mode 100644 venv/Lib/site-packages/pytz/zoneinfo/Etc/GMT+2 create mode 100644 venv/Lib/site-packages/pytz/zoneinfo/Etc/GMT+3 create mode 100644 venv/Lib/site-packages/pytz/zoneinfo/Etc/GMT+4 create mode 100644 venv/Lib/site-packages/pytz/zoneinfo/Etc/GMT+5 create mode 100644 venv/Lib/site-packages/pytz/zoneinfo/Etc/GMT+6 create mode 100644 venv/Lib/site-packages/pytz/zoneinfo/Etc/GMT+7 create mode 100644 venv/Lib/site-packages/pytz/zoneinfo/Etc/GMT+8 create mode 100644 venv/Lib/site-packages/pytz/zoneinfo/Etc/GMT+9 create mode 100644 venv/Lib/site-packages/pytz/zoneinfo/Etc/GMT-0 create mode 100644 venv/Lib/site-packages/pytz/zoneinfo/Etc/GMT-1 create mode 100644 venv/Lib/site-packages/pytz/zoneinfo/Etc/GMT-10 create mode 100644 venv/Lib/site-packages/pytz/zoneinfo/Etc/GMT-11 create mode 100644 venv/Lib/site-packages/pytz/zoneinfo/Etc/GMT-12 create mode 100644 venv/Lib/site-packages/pytz/zoneinfo/Etc/GMT-13 create mode 100644 venv/Lib/site-packages/pytz/zoneinfo/Etc/GMT-14 create mode 100644 venv/Lib/site-packages/pytz/zoneinfo/Etc/GMT-2 create mode 100644 venv/Lib/site-packages/pytz/zoneinfo/Etc/GMT-3 create mode 100644 venv/Lib/site-packages/pytz/zoneinfo/Etc/GMT-4 create mode 100644 venv/Lib/site-packages/pytz/zoneinfo/Etc/GMT-5 create mode 100644 venv/Lib/site-packages/pytz/zoneinfo/Etc/GMT-6 create mode 100644 venv/Lib/site-packages/pytz/zoneinfo/Etc/GMT-7 create mode 100644 venv/Lib/site-packages/pytz/zoneinfo/Etc/GMT-8 create mode 100644 venv/Lib/site-packages/pytz/zoneinfo/Etc/GMT-9 create mode 100644 venv/Lib/site-packages/pytz/zoneinfo/Etc/GMT0 create mode 100644 venv/Lib/site-packages/pytz/zoneinfo/Etc/Greenwich create mode 100644 venv/Lib/site-packages/pytz/zoneinfo/Etc/UCT create mode 100644 venv/Lib/site-packages/pytz/zoneinfo/Etc/UTC create mode 100644 venv/Lib/site-packages/pytz/zoneinfo/Etc/Universal create mode 100644 venv/Lib/site-packages/pytz/zoneinfo/Etc/Zulu create mode 100644 venv/Lib/site-packages/pytz/zoneinfo/Europe/Amsterdam create mode 100644 venv/Lib/site-packages/pytz/zoneinfo/Europe/Andorra create mode 100644 venv/Lib/site-packages/pytz/zoneinfo/Europe/Astrakhan create mode 100644 venv/Lib/site-packages/pytz/zoneinfo/Europe/Athens create mode 100644 venv/Lib/site-packages/pytz/zoneinfo/Europe/Belfast create mode 100644 venv/Lib/site-packages/pytz/zoneinfo/Europe/Belgrade create mode 100644 venv/Lib/site-packages/pytz/zoneinfo/Europe/Berlin create mode 100644 venv/Lib/site-packages/pytz/zoneinfo/Europe/Bratislava create mode 100644 venv/Lib/site-packages/pytz/zoneinfo/Europe/Brussels create mode 100644 venv/Lib/site-packages/pytz/zoneinfo/Europe/Bucharest create mode 100644 venv/Lib/site-packages/pytz/zoneinfo/Europe/Budapest create mode 100644 venv/Lib/site-packages/pytz/zoneinfo/Europe/Busingen create mode 100644 venv/Lib/site-packages/pytz/zoneinfo/Europe/Chisinau create mode 100644 venv/Lib/site-packages/pytz/zoneinfo/Europe/Copenhagen create mode 100644 venv/Lib/site-packages/pytz/zoneinfo/Europe/Dublin create mode 100644 venv/Lib/site-packages/pytz/zoneinfo/Europe/Gibraltar create mode 100644 venv/Lib/site-packages/pytz/zoneinfo/Europe/Guernsey create mode 100644 venv/Lib/site-packages/pytz/zoneinfo/Europe/Helsinki create mode 100644 venv/Lib/site-packages/pytz/zoneinfo/Europe/Isle_of_Man create mode 100644 venv/Lib/site-packages/pytz/zoneinfo/Europe/Istanbul create mode 100644 venv/Lib/site-packages/pytz/zoneinfo/Europe/Jersey create mode 100644 venv/Lib/site-packages/pytz/zoneinfo/Europe/Kaliningrad create mode 100644 venv/Lib/site-packages/pytz/zoneinfo/Europe/Kiev create mode 100644 venv/Lib/site-packages/pytz/zoneinfo/Europe/Kirov create mode 100644 venv/Lib/site-packages/pytz/zoneinfo/Europe/Lisbon create mode 100644 venv/Lib/site-packages/pytz/zoneinfo/Europe/Ljubljana create mode 100644 venv/Lib/site-packages/pytz/zoneinfo/Europe/London create mode 100644 venv/Lib/site-packages/pytz/zoneinfo/Europe/Luxembourg create mode 100644 venv/Lib/site-packages/pytz/zoneinfo/Europe/Madrid create mode 100644 venv/Lib/site-packages/pytz/zoneinfo/Europe/Malta create mode 100644 venv/Lib/site-packages/pytz/zoneinfo/Europe/Mariehamn create mode 100644 venv/Lib/site-packages/pytz/zoneinfo/Europe/Minsk create mode 100644 venv/Lib/site-packages/pytz/zoneinfo/Europe/Monaco create mode 100644 venv/Lib/site-packages/pytz/zoneinfo/Europe/Moscow create mode 100644 venv/Lib/site-packages/pytz/zoneinfo/Europe/Nicosia create mode 100644 venv/Lib/site-packages/pytz/zoneinfo/Europe/Oslo create mode 100644 venv/Lib/site-packages/pytz/zoneinfo/Europe/Paris create mode 100644 venv/Lib/site-packages/pytz/zoneinfo/Europe/Podgorica create mode 100644 venv/Lib/site-packages/pytz/zoneinfo/Europe/Prague create mode 100644 venv/Lib/site-packages/pytz/zoneinfo/Europe/Riga create mode 100644 venv/Lib/site-packages/pytz/zoneinfo/Europe/Rome create mode 100644 venv/Lib/site-packages/pytz/zoneinfo/Europe/Samara create mode 100644 venv/Lib/site-packages/pytz/zoneinfo/Europe/San_Marino create mode 100644 venv/Lib/site-packages/pytz/zoneinfo/Europe/Sarajevo create mode 100644 venv/Lib/site-packages/pytz/zoneinfo/Europe/Saratov create mode 100644 venv/Lib/site-packages/pytz/zoneinfo/Europe/Simferopol create mode 100644 venv/Lib/site-packages/pytz/zoneinfo/Europe/Skopje create mode 100644 venv/Lib/site-packages/pytz/zoneinfo/Europe/Sofia create mode 100644 venv/Lib/site-packages/pytz/zoneinfo/Europe/Stockholm create mode 100644 venv/Lib/site-packages/pytz/zoneinfo/Europe/Tallinn create mode 100644 venv/Lib/site-packages/pytz/zoneinfo/Europe/Tirane create mode 100644 venv/Lib/site-packages/pytz/zoneinfo/Europe/Tiraspol create mode 100644 venv/Lib/site-packages/pytz/zoneinfo/Europe/Ulyanovsk create mode 100644 venv/Lib/site-packages/pytz/zoneinfo/Europe/Uzhgorod create mode 100644 venv/Lib/site-packages/pytz/zoneinfo/Europe/Vaduz create mode 100644 venv/Lib/site-packages/pytz/zoneinfo/Europe/Vatican create mode 100644 venv/Lib/site-packages/pytz/zoneinfo/Europe/Vienna create mode 100644 venv/Lib/site-packages/pytz/zoneinfo/Europe/Vilnius create mode 100644 venv/Lib/site-packages/pytz/zoneinfo/Europe/Volgograd create mode 100644 venv/Lib/site-packages/pytz/zoneinfo/Europe/Warsaw create mode 100644 venv/Lib/site-packages/pytz/zoneinfo/Europe/Zagreb create mode 100644 venv/Lib/site-packages/pytz/zoneinfo/Europe/Zaporozhye create mode 100644 venv/Lib/site-packages/pytz/zoneinfo/Europe/Zurich create mode 100644 venv/Lib/site-packages/pytz/zoneinfo/Factory create mode 100644 venv/Lib/site-packages/pytz/zoneinfo/GB create mode 100644 venv/Lib/site-packages/pytz/zoneinfo/GB-Eire create mode 100644 venv/Lib/site-packages/pytz/zoneinfo/GMT create mode 100644 venv/Lib/site-packages/pytz/zoneinfo/GMT+0 create mode 100644 venv/Lib/site-packages/pytz/zoneinfo/GMT-0 create mode 100644 venv/Lib/site-packages/pytz/zoneinfo/GMT0 create mode 100644 venv/Lib/site-packages/pytz/zoneinfo/Greenwich create mode 100644 venv/Lib/site-packages/pytz/zoneinfo/HST create mode 100644 venv/Lib/site-packages/pytz/zoneinfo/Hongkong create mode 100644 venv/Lib/site-packages/pytz/zoneinfo/Iceland create mode 100644 venv/Lib/site-packages/pytz/zoneinfo/Indian/Antananarivo create mode 100644 venv/Lib/site-packages/pytz/zoneinfo/Indian/Chagos create mode 100644 venv/Lib/site-packages/pytz/zoneinfo/Indian/Christmas create mode 100644 venv/Lib/site-packages/pytz/zoneinfo/Indian/Cocos create mode 100644 venv/Lib/site-packages/pytz/zoneinfo/Indian/Comoro create mode 100644 venv/Lib/site-packages/pytz/zoneinfo/Indian/Kerguelen create mode 100644 venv/Lib/site-packages/pytz/zoneinfo/Indian/Mahe create mode 100644 venv/Lib/site-packages/pytz/zoneinfo/Indian/Maldives create mode 100644 venv/Lib/site-packages/pytz/zoneinfo/Indian/Mauritius create mode 100644 venv/Lib/site-packages/pytz/zoneinfo/Indian/Mayotte create mode 100644 venv/Lib/site-packages/pytz/zoneinfo/Indian/Reunion create mode 100644 venv/Lib/site-packages/pytz/zoneinfo/Iran create mode 100644 venv/Lib/site-packages/pytz/zoneinfo/Israel create mode 100644 venv/Lib/site-packages/pytz/zoneinfo/Jamaica create mode 100644 venv/Lib/site-packages/pytz/zoneinfo/Japan create mode 100644 venv/Lib/site-packages/pytz/zoneinfo/Kwajalein create mode 100644 venv/Lib/site-packages/pytz/zoneinfo/Libya create mode 100644 venv/Lib/site-packages/pytz/zoneinfo/MET create mode 100644 venv/Lib/site-packages/pytz/zoneinfo/MST create mode 100644 venv/Lib/site-packages/pytz/zoneinfo/MST7MDT create mode 100644 venv/Lib/site-packages/pytz/zoneinfo/Mexico/BajaNorte create mode 100644 venv/Lib/site-packages/pytz/zoneinfo/Mexico/BajaSur create mode 100644 venv/Lib/site-packages/pytz/zoneinfo/Mexico/General create mode 100644 venv/Lib/site-packages/pytz/zoneinfo/NZ create mode 100644 venv/Lib/site-packages/pytz/zoneinfo/NZ-CHAT create mode 100644 venv/Lib/site-packages/pytz/zoneinfo/Navajo create mode 100644 venv/Lib/site-packages/pytz/zoneinfo/PRC create mode 100644 venv/Lib/site-packages/pytz/zoneinfo/PST8PDT create mode 100644 venv/Lib/site-packages/pytz/zoneinfo/Pacific/Apia create mode 100644 venv/Lib/site-packages/pytz/zoneinfo/Pacific/Auckland create mode 100644 venv/Lib/site-packages/pytz/zoneinfo/Pacific/Bougainville create mode 100644 venv/Lib/site-packages/pytz/zoneinfo/Pacific/Chatham create mode 100644 venv/Lib/site-packages/pytz/zoneinfo/Pacific/Chuuk create mode 100644 venv/Lib/site-packages/pytz/zoneinfo/Pacific/Easter create mode 100644 venv/Lib/site-packages/pytz/zoneinfo/Pacific/Efate create mode 100644 venv/Lib/site-packages/pytz/zoneinfo/Pacific/Enderbury create mode 100644 venv/Lib/site-packages/pytz/zoneinfo/Pacific/Fakaofo create mode 100644 venv/Lib/site-packages/pytz/zoneinfo/Pacific/Fiji create mode 100644 venv/Lib/site-packages/pytz/zoneinfo/Pacific/Funafuti create mode 100644 venv/Lib/site-packages/pytz/zoneinfo/Pacific/Galapagos create mode 100644 venv/Lib/site-packages/pytz/zoneinfo/Pacific/Gambier create mode 100644 venv/Lib/site-packages/pytz/zoneinfo/Pacific/Guadalcanal create mode 100644 venv/Lib/site-packages/pytz/zoneinfo/Pacific/Guam create mode 100644 venv/Lib/site-packages/pytz/zoneinfo/Pacific/Honolulu create mode 100644 venv/Lib/site-packages/pytz/zoneinfo/Pacific/Johnston create mode 100644 venv/Lib/site-packages/pytz/zoneinfo/Pacific/Kiritimati create mode 100644 venv/Lib/site-packages/pytz/zoneinfo/Pacific/Kosrae create mode 100644 venv/Lib/site-packages/pytz/zoneinfo/Pacific/Kwajalein create mode 100644 venv/Lib/site-packages/pytz/zoneinfo/Pacific/Majuro create mode 100644 venv/Lib/site-packages/pytz/zoneinfo/Pacific/Marquesas create mode 100644 venv/Lib/site-packages/pytz/zoneinfo/Pacific/Midway create mode 100644 venv/Lib/site-packages/pytz/zoneinfo/Pacific/Nauru create mode 100644 venv/Lib/site-packages/pytz/zoneinfo/Pacific/Niue create mode 100644 venv/Lib/site-packages/pytz/zoneinfo/Pacific/Norfolk create mode 100644 venv/Lib/site-packages/pytz/zoneinfo/Pacific/Noumea create mode 100644 venv/Lib/site-packages/pytz/zoneinfo/Pacific/Pago_Pago create mode 100644 venv/Lib/site-packages/pytz/zoneinfo/Pacific/Palau create mode 100644 venv/Lib/site-packages/pytz/zoneinfo/Pacific/Pitcairn create mode 100644 venv/Lib/site-packages/pytz/zoneinfo/Pacific/Pohnpei create mode 100644 venv/Lib/site-packages/pytz/zoneinfo/Pacific/Ponape create mode 100644 venv/Lib/site-packages/pytz/zoneinfo/Pacific/Port_Moresby create mode 100644 venv/Lib/site-packages/pytz/zoneinfo/Pacific/Rarotonga create mode 100644 venv/Lib/site-packages/pytz/zoneinfo/Pacific/Saipan create mode 100644 venv/Lib/site-packages/pytz/zoneinfo/Pacific/Samoa create mode 100644 venv/Lib/site-packages/pytz/zoneinfo/Pacific/Tahiti create mode 100644 venv/Lib/site-packages/pytz/zoneinfo/Pacific/Tarawa create mode 100644 venv/Lib/site-packages/pytz/zoneinfo/Pacific/Tongatapu create mode 100644 venv/Lib/site-packages/pytz/zoneinfo/Pacific/Truk create mode 100644 venv/Lib/site-packages/pytz/zoneinfo/Pacific/Wake create mode 100644 venv/Lib/site-packages/pytz/zoneinfo/Pacific/Wallis create mode 100644 venv/Lib/site-packages/pytz/zoneinfo/Pacific/Yap create mode 100644 venv/Lib/site-packages/pytz/zoneinfo/Poland create mode 100644 venv/Lib/site-packages/pytz/zoneinfo/Portugal create mode 100644 venv/Lib/site-packages/pytz/zoneinfo/ROC create mode 100644 venv/Lib/site-packages/pytz/zoneinfo/ROK create mode 100644 venv/Lib/site-packages/pytz/zoneinfo/Singapore create mode 100644 venv/Lib/site-packages/pytz/zoneinfo/Turkey create mode 100644 venv/Lib/site-packages/pytz/zoneinfo/UCT create mode 100644 venv/Lib/site-packages/pytz/zoneinfo/US/Alaska create mode 100644 venv/Lib/site-packages/pytz/zoneinfo/US/Aleutian create mode 100644 venv/Lib/site-packages/pytz/zoneinfo/US/Arizona create mode 100644 venv/Lib/site-packages/pytz/zoneinfo/US/Central create mode 100644 venv/Lib/site-packages/pytz/zoneinfo/US/East-Indiana create mode 100644 venv/Lib/site-packages/pytz/zoneinfo/US/Eastern create mode 100644 venv/Lib/site-packages/pytz/zoneinfo/US/Hawaii create mode 100644 venv/Lib/site-packages/pytz/zoneinfo/US/Indiana-Starke create mode 100644 venv/Lib/site-packages/pytz/zoneinfo/US/Michigan create mode 100644 venv/Lib/site-packages/pytz/zoneinfo/US/Mountain create mode 100644 venv/Lib/site-packages/pytz/zoneinfo/US/Pacific create mode 100644 venv/Lib/site-packages/pytz/zoneinfo/US/Samoa create mode 100644 venv/Lib/site-packages/pytz/zoneinfo/UTC create mode 100644 venv/Lib/site-packages/pytz/zoneinfo/Universal create mode 100644 venv/Lib/site-packages/pytz/zoneinfo/W-SU create mode 100644 venv/Lib/site-packages/pytz/zoneinfo/WET create mode 100644 venv/Lib/site-packages/pytz/zoneinfo/Zulu create mode 100644 venv/Lib/site-packages/pytz/zoneinfo/iso3166.tab create mode 100644 venv/Lib/site-packages/pytz/zoneinfo/leapseconds create mode 100644 venv/Lib/site-packages/pytz/zoneinfo/posixrules create mode 100644 venv/Lib/site-packages/pytz/zoneinfo/tzdata.zi create mode 100644 venv/Lib/site-packages/pytz/zoneinfo/zone.tab create mode 100644 venv/Lib/site-packages/pytz/zoneinfo/zone1970.tab delete mode 100644 venv/Lib/site-packages/requests-2.11.1.dist-info/DESCRIPTION.rst delete mode 100644 venv/Lib/site-packages/requests-2.11.1.dist-info/METADATA delete mode 100644 venv/Lib/site-packages/requests-2.11.1.dist-info/RECORD delete mode 100644 venv/Lib/site-packages/requests-2.11.1.dist-info/metadata.json create mode 100644 venv/Lib/site-packages/requests-2.24.0.dist-info/DESCRIPTION.rst create mode 100644 venv/Lib/site-packages/requests-2.24.0.dist-info/INSTALLER create mode 100644 venv/Lib/site-packages/requests-2.24.0.dist-info/LICENSE.txt create mode 100644 venv/Lib/site-packages/requests-2.24.0.dist-info/METADATA create mode 100644 venv/Lib/site-packages/requests-2.24.0.dist-info/RECORD create mode 100644 venv/Lib/site-packages/requests-2.24.0.dist-info/WHEEL create mode 100644 venv/Lib/site-packages/requests-2.24.0.dist-info/metadata.json rename venv/Lib/site-packages/{requests-2.11.1.dist-info => requests-2.24.0.dist-info}/top_level.txt (100%) create mode 100644 venv/Lib/site-packages/requests/__pycache__/__version__.cpython-36.pyc create mode 100644 venv/Lib/site-packages/requests/__pycache__/_internal_utils.cpython-36.pyc create mode 100644 venv/Lib/site-packages/requests/__pycache__/help.cpython-36.pyc create mode 100644 venv/Lib/site-packages/requests/__pycache__/packages.cpython-36.pyc create mode 100644 venv/Lib/site-packages/requests/__version__.py create mode 100644 venv/Lib/site-packages/requests/_internal_utils.py create mode 100644 venv/Lib/site-packages/requests/help.py create mode 100644 venv/Lib/site-packages/requests/packages.py delete mode 100644 venv/Lib/site-packages/requests/packages/__init__.py delete mode 100644 venv/Lib/site-packages/requests/packages/__pycache__/__init__.cpython-36.pyc delete mode 100644 venv/Lib/site-packages/requests/packages/chardet/__pycache__/__init__.cpython-36.pyc delete mode 100644 venv/Lib/site-packages/requests/packages/chardet/__pycache__/big5freq.cpython-36.pyc delete mode 100644 venv/Lib/site-packages/requests/packages/chardet/__pycache__/big5prober.cpython-36.pyc delete mode 100644 venv/Lib/site-packages/requests/packages/chardet/__pycache__/chardetect.cpython-36.pyc delete mode 100644 venv/Lib/site-packages/requests/packages/chardet/__pycache__/chardistribution.cpython-36.pyc delete mode 100644 venv/Lib/site-packages/requests/packages/chardet/__pycache__/charsetgroupprober.cpython-36.pyc delete mode 100644 venv/Lib/site-packages/requests/packages/chardet/__pycache__/charsetprober.cpython-36.pyc delete mode 100644 venv/Lib/site-packages/requests/packages/chardet/__pycache__/codingstatemachine.cpython-36.pyc delete mode 100644 venv/Lib/site-packages/requests/packages/chardet/__pycache__/compat.cpython-36.pyc delete mode 100644 venv/Lib/site-packages/requests/packages/chardet/__pycache__/constants.cpython-36.pyc delete mode 100644 venv/Lib/site-packages/requests/packages/chardet/__pycache__/cp949prober.cpython-36.pyc delete mode 100644 venv/Lib/site-packages/requests/packages/chardet/__pycache__/escprober.cpython-36.pyc delete mode 100644 venv/Lib/site-packages/requests/packages/chardet/__pycache__/escsm.cpython-36.pyc delete mode 100644 venv/Lib/site-packages/requests/packages/chardet/__pycache__/eucjpprober.cpython-36.pyc delete mode 100644 venv/Lib/site-packages/requests/packages/chardet/__pycache__/euckrfreq.cpython-36.pyc delete mode 100644 venv/Lib/site-packages/requests/packages/chardet/__pycache__/euckrprober.cpython-36.pyc delete mode 100644 venv/Lib/site-packages/requests/packages/chardet/__pycache__/euctwprober.cpython-36.pyc delete mode 100644 venv/Lib/site-packages/requests/packages/chardet/__pycache__/gb2312prober.cpython-36.pyc delete mode 100644 venv/Lib/site-packages/requests/packages/chardet/__pycache__/hebrewprober.cpython-36.pyc delete mode 100644 venv/Lib/site-packages/requests/packages/chardet/__pycache__/jpcntx.cpython-36.pyc delete mode 100644 venv/Lib/site-packages/requests/packages/chardet/__pycache__/latin1prober.cpython-36.pyc delete mode 100644 venv/Lib/site-packages/requests/packages/chardet/__pycache__/mbcharsetprober.cpython-36.pyc delete mode 100644 venv/Lib/site-packages/requests/packages/chardet/__pycache__/mbcsgroupprober.cpython-36.pyc delete mode 100644 venv/Lib/site-packages/requests/packages/chardet/__pycache__/mbcssm.cpython-36.pyc delete mode 100644 venv/Lib/site-packages/requests/packages/chardet/__pycache__/sbcharsetprober.cpython-36.pyc delete mode 100644 venv/Lib/site-packages/requests/packages/chardet/__pycache__/sbcsgroupprober.cpython-36.pyc delete mode 100644 venv/Lib/site-packages/requests/packages/chardet/__pycache__/sjisprober.cpython-36.pyc delete mode 100644 venv/Lib/site-packages/requests/packages/chardet/__pycache__/universaldetector.cpython-36.pyc delete mode 100644 venv/Lib/site-packages/requests/packages/chardet/__pycache__/utf8prober.cpython-36.pyc delete mode 100644 venv/Lib/site-packages/requests/packages/chardet/big5freq.py delete mode 100644 venv/Lib/site-packages/requests/packages/chardet/charsetgroupprober.py delete mode 100644 venv/Lib/site-packages/requests/packages/chardet/charsetprober.py delete mode 100644 venv/Lib/site-packages/requests/packages/chardet/codingstatemachine.py delete mode 100644 venv/Lib/site-packages/requests/packages/chardet/constants.py delete mode 100644 venv/Lib/site-packages/requests/packages/chardet/escprober.py delete mode 100644 venv/Lib/site-packages/requests/packages/chardet/escsm.py delete mode 100644 venv/Lib/site-packages/requests/packages/chardet/eucjpprober.py delete mode 100644 venv/Lib/site-packages/requests/packages/chardet/euckrfreq.py delete mode 100644 venv/Lib/site-packages/requests/packages/chardet/mbcharsetprober.py delete mode 100644 venv/Lib/site-packages/requests/packages/chardet/mbcssm.py delete mode 100644 venv/Lib/site-packages/requests/packages/chardet/sbcharsetprober.py delete mode 100644 venv/Lib/site-packages/requests/packages/chardet/sjisprober.py delete mode 100644 venv/Lib/site-packages/requests/packages/chardet/universaldetector.py delete mode 100644 venv/Lib/site-packages/requests/packages/urllib3/__pycache__/__init__.cpython-36.pyc delete mode 100644 venv/Lib/site-packages/requests/packages/urllib3/__pycache__/_collections.cpython-36.pyc delete mode 100644 venv/Lib/site-packages/requests/packages/urllib3/__pycache__/connection.cpython-36.pyc delete mode 100644 venv/Lib/site-packages/requests/packages/urllib3/__pycache__/connectionpool.cpython-36.pyc delete mode 100644 venv/Lib/site-packages/requests/packages/urllib3/__pycache__/exceptions.cpython-36.pyc delete mode 100644 venv/Lib/site-packages/requests/packages/urllib3/__pycache__/fields.cpython-36.pyc delete mode 100644 venv/Lib/site-packages/requests/packages/urllib3/__pycache__/filepost.cpython-36.pyc delete mode 100644 venv/Lib/site-packages/requests/packages/urllib3/__pycache__/poolmanager.cpython-36.pyc delete mode 100644 venv/Lib/site-packages/requests/packages/urllib3/__pycache__/response.cpython-36.pyc delete mode 100644 venv/Lib/site-packages/requests/packages/urllib3/connection.py delete mode 100644 venv/Lib/site-packages/requests/packages/urllib3/contrib/__pycache__/__init__.cpython-36.pyc delete mode 100644 venv/Lib/site-packages/requests/packages/urllib3/contrib/__pycache__/appengine.cpython-36.pyc delete mode 100644 venv/Lib/site-packages/requests/packages/urllib3/contrib/__pycache__/ntlmpool.cpython-36.pyc delete mode 100644 venv/Lib/site-packages/requests/packages/urllib3/contrib/__pycache__/pyopenssl.cpython-36.pyc delete mode 100644 venv/Lib/site-packages/requests/packages/urllib3/contrib/__pycache__/socks.cpython-36.pyc delete mode 100644 venv/Lib/site-packages/requests/packages/urllib3/contrib/appengine.py delete mode 100644 venv/Lib/site-packages/requests/packages/urllib3/contrib/ntlmpool.py delete mode 100644 venv/Lib/site-packages/requests/packages/urllib3/contrib/pyopenssl.py delete mode 100644 venv/Lib/site-packages/requests/packages/urllib3/contrib/socks.py delete mode 100644 venv/Lib/site-packages/requests/packages/urllib3/fields.py delete mode 100644 venv/Lib/site-packages/requests/packages/urllib3/packages/__pycache__/__init__.cpython-36.pyc delete mode 100644 venv/Lib/site-packages/requests/packages/urllib3/packages/__pycache__/ordered_dict.cpython-36.pyc delete mode 100644 venv/Lib/site-packages/requests/packages/urllib3/packages/__pycache__/six.cpython-36.pyc delete mode 100644 venv/Lib/site-packages/requests/packages/urllib3/packages/ordered_dict.py delete mode 100644 venv/Lib/site-packages/requests/packages/urllib3/packages/ssl_match_hostname/__pycache__/__init__.cpython-36.pyc delete mode 100644 venv/Lib/site-packages/requests/packages/urllib3/packages/ssl_match_hostname/__pycache__/_implementation.cpython-36.pyc delete mode 100644 venv/Lib/site-packages/requests/packages/urllib3/packages/ssl_match_hostname/_implementation.py delete mode 100644 venv/Lib/site-packages/requests/packages/urllib3/poolmanager.py delete mode 100644 venv/Lib/site-packages/requests/packages/urllib3/util/__init__.py delete mode 100644 venv/Lib/site-packages/requests/packages/urllib3/util/__pycache__/__init__.cpython-36.pyc delete mode 100644 venv/Lib/site-packages/requests/packages/urllib3/util/__pycache__/connection.cpython-36.pyc delete mode 100644 venv/Lib/site-packages/requests/packages/urllib3/util/__pycache__/request.cpython-36.pyc delete mode 100644 venv/Lib/site-packages/requests/packages/urllib3/util/__pycache__/response.cpython-36.pyc delete mode 100644 venv/Lib/site-packages/requests/packages/urllib3/util/__pycache__/retry.cpython-36.pyc delete mode 100644 venv/Lib/site-packages/requests/packages/urllib3/util/__pycache__/ssl_.cpython-36.pyc delete mode 100644 venv/Lib/site-packages/requests/packages/urllib3/util/__pycache__/url.cpython-36.pyc delete mode 100644 venv/Lib/site-packages/requests/packages/urllib3/util/request.py delete mode 100644 venv/Lib/site-packages/requests/packages/urllib3/util/ssl_.py delete mode 100644 venv/Lib/site-packages/requests/packages/urllib3/util/url.py create mode 100644 venv/Lib/site-packages/uritemplate-3.0.1.dist-info/AUTHORS.rst create mode 100644 venv/Lib/site-packages/uritemplate-3.0.1.dist-info/INSTALLER create mode 100644 venv/Lib/site-packages/uritemplate-3.0.1.dist-info/LICENSE create mode 100644 venv/Lib/site-packages/uritemplate-3.0.1.dist-info/LICENSE.APACHE create mode 100644 venv/Lib/site-packages/uritemplate-3.0.1.dist-info/LICENSE.BSD create mode 100644 venv/Lib/site-packages/uritemplate-3.0.1.dist-info/METADATA create mode 100644 venv/Lib/site-packages/uritemplate-3.0.1.dist-info/RECORD create mode 100644 venv/Lib/site-packages/uritemplate-3.0.1.dist-info/WHEEL create mode 100644 venv/Lib/site-packages/uritemplate-3.0.1.dist-info/top_level.txt create mode 100644 venv/Lib/site-packages/uritemplate/__init__.py create mode 100644 venv/Lib/site-packages/uritemplate/__pycache__/__init__.cpython-36.pyc create mode 100644 venv/Lib/site-packages/uritemplate/__pycache__/api.cpython-36.pyc create mode 100644 venv/Lib/site-packages/uritemplate/__pycache__/orderedset.cpython-36.pyc create mode 100644 venv/Lib/site-packages/uritemplate/__pycache__/template.cpython-36.pyc create mode 100644 venv/Lib/site-packages/uritemplate/__pycache__/variable.cpython-36.pyc create mode 100644 venv/Lib/site-packages/uritemplate/api.py create mode 100644 venv/Lib/site-packages/uritemplate/orderedset.py create mode 100644 venv/Lib/site-packages/uritemplate/template.py create mode 100644 venv/Lib/site-packages/uritemplate/variable.py create mode 100644 venv/Lib/site-packages/urllib3-1.25.10.dist-info/INSTALLER create mode 100644 venv/Lib/site-packages/urllib3-1.25.10.dist-info/LICENSE.txt create mode 100644 venv/Lib/site-packages/urllib3-1.25.10.dist-info/METADATA create mode 100644 venv/Lib/site-packages/urllib3-1.25.10.dist-info/RECORD create mode 100644 venv/Lib/site-packages/urllib3-1.25.10.dist-info/WHEEL create mode 100644 venv/Lib/site-packages/urllib3-1.25.10.dist-info/top_level.txt rename venv/Lib/site-packages/{requests/packages => }/urllib3/__init__.py (59%) create mode 100644 venv/Lib/site-packages/urllib3/__pycache__/__init__.cpython-36.pyc create mode 100644 venv/Lib/site-packages/urllib3/__pycache__/_collections.cpython-36.pyc create mode 100644 venv/Lib/site-packages/urllib3/__pycache__/_version.cpython-36.pyc create mode 100644 venv/Lib/site-packages/urllib3/__pycache__/connection.cpython-36.pyc create mode 100644 venv/Lib/site-packages/urllib3/__pycache__/connectionpool.cpython-36.pyc create mode 100644 venv/Lib/site-packages/urllib3/__pycache__/exceptions.cpython-36.pyc create mode 100644 venv/Lib/site-packages/urllib3/__pycache__/fields.cpython-36.pyc create mode 100644 venv/Lib/site-packages/urllib3/__pycache__/filepost.cpython-36.pyc create mode 100644 venv/Lib/site-packages/urllib3/__pycache__/poolmanager.cpython-36.pyc rename venv/Lib/site-packages/{requests/packages => }/urllib3/__pycache__/request.cpython-36.pyc (63%) create mode 100644 venv/Lib/site-packages/urllib3/__pycache__/response.cpython-36.pyc rename venv/Lib/site-packages/{requests/packages => }/urllib3/_collections.py (82%) create mode 100644 venv/Lib/site-packages/urllib3/_version.py create mode 100644 venv/Lib/site-packages/urllib3/connection.py rename venv/Lib/site-packages/{requests/packages => }/urllib3/connectionpool.py (67%) create mode 100644 venv/Lib/site-packages/urllib3/contrib/__init__.py create mode 100644 venv/Lib/site-packages/urllib3/contrib/__pycache__/__init__.cpython-36.pyc create mode 100644 venv/Lib/site-packages/urllib3/contrib/__pycache__/_appengine_environ.cpython-36.pyc create mode 100644 venv/Lib/site-packages/urllib3/contrib/__pycache__/appengine.cpython-36.pyc create mode 100644 venv/Lib/site-packages/urllib3/contrib/__pycache__/ntlmpool.cpython-36.pyc create mode 100644 venv/Lib/site-packages/urllib3/contrib/__pycache__/pyopenssl.cpython-36.pyc create mode 100644 venv/Lib/site-packages/urllib3/contrib/__pycache__/securetransport.cpython-36.pyc create mode 100644 venv/Lib/site-packages/urllib3/contrib/__pycache__/socks.cpython-36.pyc create mode 100644 venv/Lib/site-packages/urllib3/contrib/_appengine_environ.py create mode 100644 venv/Lib/site-packages/urllib3/contrib/_securetransport/__init__.py create mode 100644 venv/Lib/site-packages/urllib3/contrib/_securetransport/__pycache__/__init__.cpython-36.pyc create mode 100644 venv/Lib/site-packages/urllib3/contrib/_securetransport/__pycache__/bindings.cpython-36.pyc create mode 100644 venv/Lib/site-packages/urllib3/contrib/_securetransport/__pycache__/low_level.cpython-36.pyc create mode 100644 venv/Lib/site-packages/urllib3/contrib/_securetransport/bindings.py create mode 100644 venv/Lib/site-packages/urllib3/contrib/_securetransport/low_level.py create mode 100644 venv/Lib/site-packages/urllib3/contrib/appengine.py create mode 100644 venv/Lib/site-packages/urllib3/contrib/ntlmpool.py create mode 100644 venv/Lib/site-packages/urllib3/contrib/pyopenssl.py create mode 100644 venv/Lib/site-packages/urllib3/contrib/securetransport.py create mode 100644 venv/Lib/site-packages/urllib3/contrib/socks.py rename venv/Lib/site-packages/{requests/packages => }/urllib3/exceptions.py (74%) create mode 100644 venv/Lib/site-packages/urllib3/fields.py rename venv/Lib/site-packages/{requests/packages => }/urllib3/filepost.py (79%) rename venv/Lib/site-packages/{requests/packages => }/urllib3/packages/__init__.py (67%) create mode 100644 venv/Lib/site-packages/urllib3/packages/__pycache__/__init__.cpython-36.pyc create mode 100644 venv/Lib/site-packages/urllib3/packages/__pycache__/six.cpython-36.pyc create mode 100644 venv/Lib/site-packages/urllib3/packages/backports/__init__.py create mode 100644 venv/Lib/site-packages/urllib3/packages/backports/__pycache__/__init__.cpython-36.pyc create mode 100644 venv/Lib/site-packages/urllib3/packages/backports/__pycache__/makefile.cpython-36.pyc create mode 100644 venv/Lib/site-packages/urllib3/packages/backports/makefile.py rename venv/Lib/site-packages/{requests/packages => }/urllib3/packages/six.py (81%) rename venv/Lib/site-packages/{requests/packages => }/urllib3/packages/ssl_match_hostname/__init__.py (57%) create mode 100644 venv/Lib/site-packages/urllib3/packages/ssl_match_hostname/__pycache__/__init__.cpython-36.pyc create mode 100644 venv/Lib/site-packages/urllib3/packages/ssl_match_hostname/__pycache__/_implementation.cpython-36.pyc create mode 100644 venv/Lib/site-packages/urllib3/packages/ssl_match_hostname/_implementation.py create mode 100644 venv/Lib/site-packages/urllib3/poolmanager.py rename venv/Lib/site-packages/{requests/packages => }/urllib3/request.py (70%) rename venv/Lib/site-packages/{requests/packages => }/urllib3/response.py (54%) create mode 100644 venv/Lib/site-packages/urllib3/util/__init__.py create mode 100644 venv/Lib/site-packages/urllib3/util/__pycache__/__init__.cpython-36.pyc create mode 100644 venv/Lib/site-packages/urllib3/util/__pycache__/connection.cpython-36.pyc create mode 100644 venv/Lib/site-packages/urllib3/util/__pycache__/queue.cpython-36.pyc create mode 100644 venv/Lib/site-packages/urllib3/util/__pycache__/request.cpython-36.pyc create mode 100644 venv/Lib/site-packages/urllib3/util/__pycache__/response.cpython-36.pyc create mode 100644 venv/Lib/site-packages/urllib3/util/__pycache__/retry.cpython-36.pyc create mode 100644 venv/Lib/site-packages/urllib3/util/__pycache__/ssl_.cpython-36.pyc rename venv/Lib/site-packages/{requests/packages => }/urllib3/util/__pycache__/timeout.cpython-36.pyc (59%) create mode 100644 venv/Lib/site-packages/urllib3/util/__pycache__/url.cpython-36.pyc create mode 100644 venv/Lib/site-packages/urllib3/util/__pycache__/wait.cpython-36.pyc rename venv/Lib/site-packages/{requests/packages => }/urllib3/util/connection.py (77%) create mode 100644 venv/Lib/site-packages/urllib3/util/queue.py create mode 100644 venv/Lib/site-packages/urllib3/util/request.py rename venv/Lib/site-packages/{requests/packages => }/urllib3/util/response.py (71%) rename venv/Lib/site-packages/{requests/packages => }/urllib3/util/retry.py (55%) create mode 100644 venv/Lib/site-packages/urllib3/util/ssl_.py rename venv/Lib/site-packages/{requests/packages => }/urllib3/util/timeout.py (75%) create mode 100644 venv/Lib/site-packages/urllib3/util/url.py create mode 100644 venv/Lib/site-packages/urllib3/util/wait.py create mode 100644 venv/Scripts/chardetect.exe create mode 100644 venv/Scripts/doesitcache.exe diff --git a/DBHelper.py b/DBHelper.py index f781e0473..dcaed833d 100644 --- a/DBHelper.py +++ b/DBHelper.py @@ -1,4 +1,5 @@ import pyrebase +import firebase_admin firebaseConfig = { 'apiKey': "AIzaSyAdL0W5HscjEDFPK4BDi6Cnc7FLa30GPYY", @@ -8,7 +9,8 @@ firebaseConfig = { 'storageBucket': "vehicleantitheftrecognition.appspot.com", 'messagingSenderId': "163692530359", 'appId': "1:163692530359:web:b6dc7ccfc56a79afb11b32", - 'measurementId': "G-EPWP2LK89Q" + 'measurementId': "G-EPWP2LK89Q", + 'serviceAccount': 'vehicleantitheftrecognition-firebase-adminsdk-krrgw-05da515de5.json' } firebase = pyrebase.initialize_app(firebaseConfig) @@ -19,7 +21,7 @@ storage = firebase.storage() class DBHelper: # Create account function which creates a new authentication info. - def createaccount(username, password, confirmpassword): + def createAccount(username, password, confirmpassword): email = username + "@hotmail.com" if password == confirmpassword: auth.create_user_with_email_and_password(email,password) @@ -46,7 +48,7 @@ class DBHelper: db.child("Users").child(userID).remove() # Returns the first name or else an empty string. - def getfirstname(userID): + def getFirstName(userID): firstname = "" users = db.child("Users").get() for user in users.each(): @@ -55,7 +57,7 @@ class DBHelper: return firstname # Returns the last name or else an empty string. - def getlastname(userID): + def getLastName(userID): lastname = "" users = db.child("Users").get() for user in users.each(): @@ -64,7 +66,7 @@ class DBHelper: return lastname # Returns the e-mail or else an empty string. - def getemail(userID): + def getEmail(userID): email = "" users = db.child("Users").get() for user in users.each(): @@ -73,7 +75,7 @@ class DBHelper: return email # Returns the phone or else an empty string. - def getphone(userID): + def getPhone(userID): phone = "" users = db.child("Users").get() for user in users.each(): @@ -82,7 +84,7 @@ class DBHelper: return phone # Returns the address or else an empty string. - def getaddress(userID): + def getAddress(userID): address = "" users = db.child("Users").get() for user in users.each(): @@ -91,19 +93,24 @@ class DBHelper: return address # Uploads the photo of user, input should be something like "example.png" - def uploaduserphoto(userphoto): + def uploadUserPhoto(userphoto): userphoto_str = str(userphoto) storage.child("Photos_of_Users/" + str(userphoto)).put("Photos_of_Users/" + str(userphoto)) # Uploads the photo of thief, input should be something like "example.png" - def uploadthiefphoto(userphoto): + def uploadThiefPhoto(userphoto): userphoto_str = str(userphoto) storage.child("Photos_of_Thieves/" + str(userphoto)).put("Photos_of_Thieves/" + str(userphoto)) # Downloads all the user photos. - def downloadalluserphotos(self): + def downloadAllUserphotos(self): storage.child("Photos_of_Users").download("Storage_from_Database") # Downloads all the thief photos. - def downloadallthiefphotos(self): + def downloadAllThiefphotos(self): storage.child("Photos_of_Thieves").download("Storage_from_Thieves") + + # Deletes photo of the specified user. + def deleteUserPhoto(userphoto): + storage.delete('Photos_of_Users/' + userphoto) + diff --git a/vehicleantitheftrecognition-firebase-adminsdk-krrgw-05da515de5.json b/vehicleantitheftrecognition-firebase-adminsdk-krrgw-05da515de5.json new file mode 100644 index 000000000..4319726a6 --- /dev/null +++ b/vehicleantitheftrecognition-firebase-adminsdk-krrgw-05da515de5.json @@ -0,0 +1,12 @@ +{ + "type": "service_account", + "project_id": "vehicleantitheftrecognition", + "private_key_id": "05da515de56c8ac1f4882cca95e59b528327689d", + "private_key": "-----BEGIN PRIVATE KEY-----\nMIIEvgIBADANBgkqhkiG9w0BAQEFAASCBKgwggSkAgEAAoIBAQDEuXY99rdd3tUr\n478TMukS5x7nWXDHTFHZcxFXIyjkgjcm7a4JieJCuf7VtteAoJQ+8q4qLxypwkOA\nmVpGFXtP9xQCeoiL/lsZGUQ2GAZVmOOumlRMbDJ6bJANe4V7QnmdfLInjTks/ahr\nw6xBNBmbOXxk7adF3Qj3rp/1iUG54AHOkBvQkz53zCRVi2yX7PiwvARDErgj3LNn\nEoc/95P7HXgzuwGfwfziGqN1EtxcKzDsVi5Sg5L2cyjm5V17sEkFRKA2zXqjdOrM\nOQINL4UW4mcU7zyj8Iyu9IFTzWgEVS64+O2+mA9T2Rf325LNa46yqdtoQA8A40oZ\nYrV089bLAgMBAAECggEAAZ94vEDMI81yJhng5QBR2pgRhzMTsnE3aPssCh3+I7R3\nTq499fzZ4wG0eoA2/Zaq4my6HHBQZON3ZG40x8iRld1MoEtGfnErazpBd84cRJnY\nTFkgQj56RCGf0UdS7etkeXTNO3T3eHQ3RCb/Gs1FO3numXPkd2JqxTBUSCrztzGA\nMmk5ikE3giL+ZVB3TaKwkuDLNzxaQSKR+tHGrBPndb6exVfYEROk8HBeTmE+UfBY\nnKXM1uAk7dGXkjq3dFekv0CmEBydebx862/pWgo/a4o7eGDwmPPlxgu3mMJ7fVjB\nji70iusIDc7QCPWYCVCFW8BkZTNy/lGIGNMAEK5w0QKBgQDsl5FPJCOdERQCylcF\nxh6ECw6LqxioFRovXgtsfn/eXoLVCh3Vulqu6zL78qn0f7JQNdUMt9x++wIpNMWb\nV0GHJZVUnqzrvpTZdHWYVDj4tD9WC8vOjbCf5pDfrN4bTh0q4SJasm8tFcHUNcpW\nechUCQMdtxVoi2jgwHBJWlwXnQKBgQDU3KzASyuPZip2oELx+jbXBZ840P/8aekh\nNQUit2jG0twM7Qgk1M929fhY3xyAFKjptk8vLFZcmfi0p0FeNUYnF4bmORuz+bng\nxEW4+dzrf9eeekQcspUf8kwgUkzuuePwJJ4LDuL6d3I/wzClU7B74BAaDqzs9gTK\nFiOPSvb/hwKBgQDqcMKXppr3sA2hOjmDSi/A7mfqdI+JNufsmgc96hfxFLwWOOEZ\ngYEMpZmu2WYaFlNucfl8kdCXr0kT5ewOIyeWsOJJqLZ3IDHFTUadvI97urisHiJF\nuleUC1fxnQ22BvCWJeLx9rB9/3pDO04V5LViuE9zKZG4N7SkSWy68yQgbQKBgQCo\n0PsQ5oz9hYFX43I0hsTHc2X7oYXjofuKoooYJm2qgcCTX8l9rGl9Z0Y29Xuc+MWd\n1UCnoPo9Jr/gRmXJWWbxye7q14/pBL0uTXseYMuc2h8fSMiMGfW7CGbnm134VuU3\np1LQYlYRXnn1p9AEzoLBO8qJX+o1ZEgYHcbF9iY+MQKBgFWBolVPSddIGB/btoOA\nVncnhDSziXdbyEprCO0omsRLG+ciJwWXv4Rd+ftGD7fvFLFFBH/JR9L2lU9eKcF3\nBZA5KMb66zmQ2nVzRiJEUZmE6vxp8E7nXlfxTy76euZSkFDKvhhbYU1XLcPj2ES3\nMMy1jE3LrpNrAT6iHvsz/pt0\n-----END PRIVATE KEY-----\n", + "client_email": "firebase-adminsdk-krrgw@vehicleantitheftrecognition.iam.gserviceaccount.com", + "client_id": "105455250176735842254", + "auth_uri": "https://accounts.google.com/o/oauth2/auth", + "token_uri": "https://oauth2.googleapis.com/token", + "auth_provider_x509_cert_url": "https://www.googleapis.com/oauth2/v1/certs", + "client_x509_cert_url": "https://www.googleapis.com/robot/v1/metadata/x509/firebase-adminsdk-krrgw%40vehicleantitheftrecognition.iam.gserviceaccount.com" +} diff --git a/venv/Lib/site-packages/CacheControl-0.12.6.dist-info/DESCRIPTION.rst b/venv/Lib/site-packages/CacheControl-0.12.6.dist-info/DESCRIPTION.rst new file mode 100644 index 000000000..6e4ca7647 --- /dev/null +++ b/venv/Lib/site-packages/CacheControl-0.12.6.dist-info/DESCRIPTION.rst @@ -0,0 +1,44 @@ +============== + CacheControl +============== + +.. image:: https://img.shields.io/pypi/v/cachecontrol.svg + :target: https://pypi.python.org/pypi/cachecontrol + :alt: Latest Version + +.. image:: https://travis-ci.org/ionrock/cachecontrol.png?branch=master + :target: https://travis-ci.org/ionrock/cachecontrol + +CacheControl is a port of the caching algorithms in httplib2_ for use with +requests_ session object. + +It was written because httplib2's better support for caching is often +mitigated by its lack of thread safety. The same is true of requests in +terms of caching. + + +Quickstart +========== + +.. code-block:: python + + import requests + + from cachecontrol import CacheControl + + + sess = requests.session() + cached_sess = CacheControl(sess) + + response = cached_sess.get('http://google.com') + +If the URL contains any caching based headers, it will cache the +result in a simple dictionary. + +For more info, check out the docs_ + +.. _docs: http://cachecontrol.readthedocs.org/en/latest/ +.. _httplib2: https://github.com/jcgregorio/httplib2 +.. _requests: http://docs.python-requests.org/ + + diff --git a/venv/Lib/site-packages/requests-2.11.1.dist-info/INSTALLER b/venv/Lib/site-packages/CacheControl-0.12.6.dist-info/INSTALLER similarity index 100% rename from venv/Lib/site-packages/requests-2.11.1.dist-info/INSTALLER rename to venv/Lib/site-packages/CacheControl-0.12.6.dist-info/INSTALLER diff --git a/venv/Lib/site-packages/CacheControl-0.12.6.dist-info/METADATA b/venv/Lib/site-packages/CacheControl-0.12.6.dist-info/METADATA new file mode 100644 index 000000000..2f614f940 --- /dev/null +++ b/venv/Lib/site-packages/CacheControl-0.12.6.dist-info/METADATA @@ -0,0 +1,74 @@ +Metadata-Version: 2.0 +Name: CacheControl +Version: 0.12.6 +Summary: httplib2 caching for requests +Home-page: https://github.com/ionrock/cachecontrol +Author: Eric Larson +Author-email: eric@ionrock.org +License: UNKNOWN +Description-Content-Type: UNKNOWN +Keywords: requests http caching web +Platform: UNKNOWN +Classifier: Development Status :: 4 - Beta +Classifier: Environment :: Web Environment +Classifier: License :: OSI Approved :: Apache Software License +Classifier: Operating System :: OS Independent +Classifier: Programming Language :: Python :: 2 +Classifier: Programming Language :: Python :: 2.7 +Classifier: Programming Language :: Python :: 3 +Classifier: Programming Language :: Python :: 3.4 +Classifier: Programming Language :: Python :: 3.5 +Classifier: Programming Language :: Python :: 3.6 +Classifier: Topic :: Internet :: WWW/HTTP +Requires-Python: >=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.* +Requires-Dist: requests +Requires-Dist: msgpack (>=0.5.2) +Provides-Extra: filecache +Requires-Dist: lockfile (>=0.9); extra == 'filecache' +Provides-Extra: redis +Requires-Dist: redis (>=2.10.5); extra == 'redis' + +============== + CacheControl +============== + +.. image:: https://img.shields.io/pypi/v/cachecontrol.svg + :target: https://pypi.python.org/pypi/cachecontrol + :alt: Latest Version + +.. image:: https://travis-ci.org/ionrock/cachecontrol.png?branch=master + :target: https://travis-ci.org/ionrock/cachecontrol + +CacheControl is a port of the caching algorithms in httplib2_ for use with +requests_ session object. + +It was written because httplib2's better support for caching is often +mitigated by its lack of thread safety. The same is true of requests in +terms of caching. + + +Quickstart +========== + +.. code-block:: python + + import requests + + from cachecontrol import CacheControl + + + sess = requests.session() + cached_sess = CacheControl(sess) + + response = cached_sess.get('http://google.com') + +If the URL contains any caching based headers, it will cache the +result in a simple dictionary. + +For more info, check out the docs_ + +.. _docs: http://cachecontrol.readthedocs.org/en/latest/ +.. _httplib2: https://github.com/jcgregorio/httplib2 +.. _requests: http://docs.python-requests.org/ + + diff --git a/venv/Lib/site-packages/CacheControl-0.12.6.dist-info/RECORD b/venv/Lib/site-packages/CacheControl-0.12.6.dist-info/RECORD new file mode 100644 index 000000000..f310b5ce3 --- /dev/null +++ b/venv/Lib/site-packages/CacheControl-0.12.6.dist-info/RECORD @@ -0,0 +1,35 @@ +../../Scripts/doesitcache.exe,sha256=oUrPldHAhd6L96tleSYm9TnI_wQAlAXhZcgsF_m648I,97232 +CacheControl-0.12.6.dist-info/DESCRIPTION.rst,sha256=AVvOiHd6xGEt-8qj3nBO0wevsy94ATbiolgWP-hAdOw,1090 +CacheControl-0.12.6.dist-info/INSTALLER,sha256=zuuue4knoyJ-UwPPXg8fezS7VCrXJQrAP7zeNuwvFQg,4 +CacheControl-0.12.6.dist-info/METADATA,sha256=KdpEZki2tVLM6jOflJwcwdg_7YOT-HA08g1lF3BSU8A,2196 +CacheControl-0.12.6.dist-info/RECORD,, +CacheControl-0.12.6.dist-info/WHEEL,sha256=kdsN-5OJAZIiHN-iO4Rhl82KyS0bDWf4uBwMbkNafr8,110 +CacheControl-0.12.6.dist-info/entry_points.txt,sha256=HjCekaRCv8kfNqP5WehMR29IWxIA5VrhoOeKrCykCLc,56 +CacheControl-0.12.6.dist-info/metadata.json,sha256=fj7gcSEiRyF5g5Nt5ShwF7GP7QAPJFTqZ0YwhYlxMZE,1380 +CacheControl-0.12.6.dist-info/top_level.txt,sha256=vGYWzpbe3h6gkakV4f7iCK2x3KyK3oMkV5pe5v25-d4,13 +cachecontrol/__init__.py,sha256=pJtAaUxOsMPnytI1A3juAJkXYDr8krdSnsg4Yg3OBEg,302 +cachecontrol/__pycache__/__init__.cpython-36.pyc,, +cachecontrol/__pycache__/_cmd.cpython-36.pyc,, +cachecontrol/__pycache__/adapter.cpython-36.pyc,, +cachecontrol/__pycache__/cache.cpython-36.pyc,, +cachecontrol/__pycache__/compat.cpython-36.pyc,, +cachecontrol/__pycache__/controller.cpython-36.pyc,, +cachecontrol/__pycache__/filewrapper.cpython-36.pyc,, +cachecontrol/__pycache__/heuristics.cpython-36.pyc,, +cachecontrol/__pycache__/serialize.cpython-36.pyc,, +cachecontrol/__pycache__/wrapper.cpython-36.pyc,, +cachecontrol/_cmd.py,sha256=88j4P3JlJGqg6xAXR4btN9fYruXUH4CE-M93Sie5IB8,1242 +cachecontrol/adapter.py,sha256=ctnbSXDOj0V0NaxJP2jFauOYRDHaNYMP9QCE8kB4kfk,4870 +cachecontrol/cache.py,sha256=1fc4wJP8HYt1ycnJXeEw5pCpeBL2Cqxx6g9Fb0AYDWQ,805 +cachecontrol/caches/__init__.py,sha256=-gHNKYvaeD0kOk5M74eOrsSgIKUtC6i6GfbmugGweEo,86 +cachecontrol/caches/__pycache__/__init__.cpython-36.pyc,, +cachecontrol/caches/__pycache__/file_cache.cpython-36.pyc,, +cachecontrol/caches/__pycache__/redis_cache.cpython-36.pyc,, +cachecontrol/caches/file_cache.py,sha256=nYVKsJtXh6gJXvdn1iWyrhxvkwpQrK-eKoMRzuiwkKk,4153 +cachecontrol/caches/redis_cache.py,sha256=yZP1PoUgAvxEZZrCVwImZ-5pFKU41v5HYJf1rfbXYmM,844 +cachecontrol/compat.py,sha256=Fn_aYzqNbN0bK9gUn8SQUzMLxQ_ruGnsEMvryYDFh3o,647 +cachecontrol/controller.py,sha256=fpLmIvxce2mKVFmtDFiiyydqU_pPbCucYLC9qP-LqvY,14137 +cachecontrol/filewrapper.py,sha256=vACKO8Llzu_ZWyjV1Fxn1MA4TGU60N5N3GSrAFdAY2Q,2533 +cachecontrol/heuristics.py,sha256=BFGHJ3yQcxvZizfo90LLZ04T_Z5XSCXvFotrp7Us0sc,4070 +cachecontrol/serialize.py,sha256=Jms7OS4GB2JFUzuMPlmQtuCDzcjjE-2ijrHpUXC2BV0,7062 +cachecontrol/wrapper.py,sha256=5LX0uJwkNQUtYSEw3aGmGu9WY8wGipd81mJ8lG0d0M4,690 diff --git a/venv/Lib/site-packages/requests-2.11.1.dist-info/WHEEL b/venv/Lib/site-packages/CacheControl-0.12.6.dist-info/WHEEL similarity index 70% rename from venv/Lib/site-packages/requests-2.11.1.dist-info/WHEEL rename to venv/Lib/site-packages/CacheControl-0.12.6.dist-info/WHEEL index 0de529b1e..7332a419c 100644 --- a/venv/Lib/site-packages/requests-2.11.1.dist-info/WHEEL +++ b/venv/Lib/site-packages/CacheControl-0.12.6.dist-info/WHEEL @@ -1,5 +1,5 @@ Wheel-Version: 1.0 -Generator: bdist_wheel (0.26.0) +Generator: bdist_wheel (0.30.0) Root-Is-Purelib: true Tag: py2-none-any Tag: py3-none-any diff --git a/venv/Lib/site-packages/CacheControl-0.12.6.dist-info/entry_points.txt b/venv/Lib/site-packages/CacheControl-0.12.6.dist-info/entry_points.txt new file mode 100644 index 000000000..7c31574e9 --- /dev/null +++ b/venv/Lib/site-packages/CacheControl-0.12.6.dist-info/entry_points.txt @@ -0,0 +1,3 @@ +[console_scripts] +doesitcache = cachecontrol._cmd:main + diff --git a/venv/Lib/site-packages/CacheControl-0.12.6.dist-info/metadata.json b/venv/Lib/site-packages/CacheControl-0.12.6.dist-info/metadata.json new file mode 100644 index 000000000..59890528a --- /dev/null +++ b/venv/Lib/site-packages/CacheControl-0.12.6.dist-info/metadata.json @@ -0,0 +1 @@ +{"classifiers": ["Development Status :: 4 - Beta", "Environment :: Web Environment", "License :: OSI Approved :: Apache Software License", "Operating System :: OS Independent", "Programming Language :: Python :: 2", "Programming Language :: Python :: 2.7", "Programming Language :: Python :: 3", "Programming Language :: Python :: 3.4", "Programming Language :: Python :: 3.5", "Programming Language :: Python :: 3.6", "Topic :: Internet :: WWW/HTTP"], "description_content_type": "UNKNOWN", "extensions": {"python.commands": {"wrap_console": {"doesitcache": "cachecontrol._cmd:main"}}, "python.details": {"contacts": [{"email": "eric@ionrock.org", "name": "Eric Larson", "role": "author"}], "document_names": {"description": "DESCRIPTION.rst"}, "project_urls": {"Home": "https://github.com/ionrock/cachecontrol"}}, "python.exports": {"console_scripts": {"doesitcache": "cachecontrol._cmd:main"}}}, "extras": ["filecache", "redis"], "generator": "bdist_wheel (0.30.0)", "keywords": ["requests", "http", "caching", "web"], "metadata_version": "2.0", "name": "CacheControl", "requires_python": ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*", "run_requires": [{"extra": "filecache", "requires": ["lockfile (>=0.9)"]}, {"requires": ["msgpack (>=0.5.2)", "requests"]}, {"extra": "redis", "requires": ["redis (>=2.10.5)"]}], "summary": "httplib2 caching for requests", "version": "0.12.6"} \ No newline at end of file diff --git a/venv/Lib/site-packages/CacheControl-0.12.6.dist-info/top_level.txt b/venv/Lib/site-packages/CacheControl-0.12.6.dist-info/top_level.txt new file mode 100644 index 000000000..af37ac627 --- /dev/null +++ b/venv/Lib/site-packages/CacheControl-0.12.6.dist-info/top_level.txt @@ -0,0 +1 @@ +cachecontrol diff --git a/venv/Lib/site-packages/__pycache__/google_auth_httplib2.cpython-36.pyc b/venv/Lib/site-packages/__pycache__/google_auth_httplib2.cpython-36.pyc new file mode 100644 index 0000000000000000000000000000000000000000..8354ae1c54654b86c7fff0cb1fe0446e128e863c GIT binary patch literal 8182 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 a636Retb!njxO80*+Ht49V*dO2KMso^j2yjX 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

-0NVNNR={EBnONV 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�^#aZCJT5J+$Z&T^yLE)k#M+?8yb<~R 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

6bnu^Z=kN(`J#4%=x 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 literal 0 HcmV?d00001 diff --git a/venv/Lib/site-packages/apiclient/__init__.py b/venv/Lib/site-packages/apiclient/__init__.py new file mode 100644 index 000000000..8d9c4ecb8 --- /dev/null +++ b/venv/Lib/site-packages/apiclient/__init__.py @@ -0,0 +1,36 @@ +"""Retain apiclient as an alias for googleapiclient.""" + +from six import iteritems + +import googleapiclient + +from googleapiclient import channel +from googleapiclient import discovery +from googleapiclient import errors +from googleapiclient import http +from googleapiclient import mimeparse +from googleapiclient import model + +try: + from googleapiclient import sample_tools +except ImportError: + # Silently ignore, because the vast majority of consumers won't use it and + # it has deep dependence on oauth2client, an optional dependency. + sample_tools = None +from googleapiclient import schema + +_SUBMODULES = { + "channel": channel, + "discovery": discovery, + "errors": errors, + "http": http, + "mimeparse": mimeparse, + "model": model, + "sample_tools": sample_tools, + "schema": schema, +} + +import sys + +for module_name, module in iteritems(_SUBMODULES): + sys.modules["apiclient.%s" % module_name] = module diff --git a/venv/Lib/site-packages/apiclient/__pycache__/__init__.cpython-36.pyc b/venv/Lib/site-packages/apiclient/__pycache__/__init__.cpython-36.pyc new file mode 100644 index 0000000000000000000000000000000000000000..300a76a88869371e18f8d46408151e0ad622cce1 GIT binary patch literal 857 zcma)3!EV$r5VezRlFeqf+a4;85fXka!45Rb)dyPrIV>r(*myJTfeX=WJ24%Y(V2G%?tE`Y$mD-3LD6!$TD3FRQdmgwRe2(WOGjmgFGe zg%D6nQxUunVh`x)aw5qAWzzs+Z)KOrf1PpMv-Igv)E6g|_!;4nwsZLNL%rv%r#^fm zLtAoZL8I9N*Wh=-HN3Uv;Bd!}Ad%g0599@jW^1mXxOum}<_)@UpaS1RX;cMF+F-6i z3ERMW+ZmFpg*AbcGJmAvnvU8%e>5BJO@J%1b|(w)eE0<~g)mekMAjU;`EBiVTfv83 Pzwgyg;`1CW<7NC8&T77$ literal 0 HcmV?d00001 diff --git a/venv/Lib/site-packages/cachecontrol/__pycache__/_cmd.cpython-36.pyc b/venv/Lib/site-packages/cachecontrol/__pycache__/_cmd.cpython-36.pyc new file mode 100644 index 0000000000000000000000000000000000000000..43baceee2af424f016bd38a408441ec4aefde016 GIT binary patch literal 1543 zcmZ8hOK;pZ5GM6r?IVU8v}sYaYLP?skQixmsZj(?ouVmVEQ;E>2m%B}WVBlARg!Yx z#rm|q=0Eh>zr<@#{R=&HhEm-m1V|2NNa~w!KI+@~Jp84&Nwq`BU*w%;gZ%?^sbFA) z(Tc>wOk)abtFmf4wki7T%BkJhHMUcEwIBP&cB`PC#1pVR=HHMwWC5GNJY^x9!aQSl z*o@6@Xguc&wz#lF$LD(j`{@~39{deoCaWdYADv|RnxC|d5^eR2Wu4*z+>_^Ju1p9P zUey+baW9^UqOWQRo)*6X^157!=u1Wo_&|r37YYPp;AD?g)Aq0St7t z^aM~tbRfAp<(ItDK7Ofe3hh4s>BpBp>-m`yJgZ-14Xe1&VaC{K11x_%xc?+#2G{)a zM}D02fJ!E>GS#n>w&6^ampoxyUZ}Q9`lfu-ii_lmXCiu%NM3UZ=|+!}oEJ~Nd;Cq( ziFU(tm0a?5nO8i@8dW}2YyMhAud|#-g6D0~l&Wl-NM6C=8n!l<$!Ym2k)`4fyDY!R z3NDizY0U>(kJ7wmkGd;8heZ1>9g{@R(u0A}84ajdfOX3#vWYRn=udR!AKJS7la}TVQsw=DjGT zD)X(sR;oKbI@$(kNU)Z^KsdsNK?j2W-UDw^`)6EAU_!ff+c!#wW4c(WgW*H}dzO~= zvq4_kk#Nw|Y#8Qv@3i15#Q@xR2o8yK5Ngo_D*%3GFp5vXbITBF4&`GQ`Wy^JP-Qz% z9E3iwJowYW0XPI$UwWDC>sUZaximo4{vbr z?1$_)byha_AuJDIAk?FtJ+nRg&|c8c5)bfTkfyjRP4Vw=NBH0qD2Dj1!8FS0(I_ON z%J}fTkXaa|#-F?&7~Ud?bNuN5+@XwE?je2D*FesHXqv3%Y5Gno_-KU@Z18>EvcBR^ Zv9J=E3#`BbrGi#xcHjlGzzgpN^j{^Zi=qGk literal 0 HcmV?d00001 diff --git a/venv/Lib/site-packages/cachecontrol/__pycache__/adapter.cpython-36.pyc b/venv/Lib/site-packages/cachecontrol/__pycache__/adapter.cpython-36.pyc new file mode 100644 index 0000000000000000000000000000000000000000..d1c40f35783479557e02a23f19dd008b3d9a9a4c GIT binary patch literal 3087 zcmai0OONBm5$eW5=7_^&%jQ*ok1T5xpBELegco00pWzxf=rt?ol^VFrVQS!a8~ZrrGz`&ExeUK_3hXzI;&tB z*s))9SK&0I}ZgsJYQS*q| zPK^KQ(=VP*o{lGJr_~^Yw+GKQJZb_&6HRM!&T>|F>fl>SNe$X90~u-OoRq8vZtT_` zP_Opa?{No4e(kIu>&{uX?$#uCYgW6Qy+TgF3FzdGjq};l$&i^|in_%@Cr8SJO2{lJ zvQspnL{)}eS{gPl-Y45m$MU*$moNa5-XtqP0_ovR2+Tq z;k)n6*0Rb)s%J07B1;PqC8f?D>4li<2o4pI6lrw?hRCWiQYWx^1xw49voEs4naZ?y zv<9#xM?%f4JzAZAo;0u>txx0te#`n82c)-0_o+`q7Ene{A0GTKUPhOePaWI<7dm7M z9<-qPBaoV{1MoIEb8DK@+Fkl`ak2w5EO%;pPS3orNcq4e+ReRXC_knIZw~Xn2ORy5 z)SjHcY9A2gamJlj&I`a=-pNra%eyG!9Pp<@-Lr`7*K|&6=UaN_*FK`^^siymUN1z+ zqXZ1~^#+VPioR4L0s~%7L|Hkn)^4}d5I>+CjbMsNdvmu@K#Fq@D%#KS=)C(y#ti z2l?H@ikfEj4c zaL!f=HkP<$=s*fzY|3R^KoT@gJYO3ha&DyrU=xMG!S`*Yh?|&*FPE1`dT|Y0vws`E zL~U#l#wg1E{761A0Y12NtCri4ON70Pthi9~;yj{SS6J0o1->65j9 z^7>m_5-0F+og8F@EB3SUB@|vrCgAzY(rH+=Y;!}rk%e)9*s5uK4yr-PdL8x-Lu-He zCdvseaba1F4c-EV{3#MtM*a-RV<2r(f!8CPvS}rP(TDJ;kARSF2&u%UeJAvM8aM%U z{XPwt@4&pvAknyV5BNUodoB%~J!hW|V71Rq-}wIy`~f5}|JWRa4g&}R2oZvsX=qxY z`LSOXkaRqB8zXoYe%F?~0^)z?$|oT693F+O2tj<^zfHXc&Hi{YhHD7tuxDfFf1u|n zla+{L6UOnX;v48~V$+Y~uQy52a3osGmUNq!txM$-m@`{#W0H!ZfUe2rZzQel8>3?- z$A(Ak0|{v0!k@SIU@*8l_}o^JVPF0V`0|%XFmk86Z6#5owy{tWL)&88wp~q&Wm~o0 n99rMwruA*Gi>F>IbR$B8$IV|tg8({Ve*!vz+xx6f;dcH5sQVyk literal 0 HcmV?d00001 diff --git a/venv/Lib/site-packages/cachecontrol/__pycache__/cache.cpython-36.pyc b/venv/Lib/site-packages/cachecontrol/__pycache__/cache.cpython-36.pyc new file mode 100644 index 0000000000000000000000000000000000000000..612faa1f8c0f6f5cced40eb9fec3e819ac024827 GIT binary patch literal 1816 zcma)7O^@3)5G5s9wv}~un;eCqB!zoEzeC0%>!U+Aeb)cPYvk(LIB6iIR3%)DoP(d$L$liT!TpRqsLP782; zirt)`QEbE%S6*-ywuBB zWzuG4A@p(({e|dQpVz_5QqCkjtec0EQ|#tbG{8n2gYYPbTQ>3=_@khKO@LJg*F)7s z;8ETEN*FjJ+>)-LMkB|5hTTMHEW2U9;idQjA0mQ>!_uCwqXPAf)}`)ybzmSL*ZvHa ze=yy~_x}D}K1&t`v`H?6T}+d*0Hw1lNEDcvEvsZvWUop+OO_yXe3BTYSGnqpyFptM}3S%3Og@jmxEGI=qS&GdPU!LR9;wpKWT_h&6a9jyF z6B96rD~>D+tIPZ|_b{lIwLbw%F&Y;=zwT}FF~A+^;}$g<-!)U7L# zFTmxYF&$d<4cHz|{>2^c{O=Mp?!2wLeLtas94s8|xH{TK)@(`&h#HNX;3$y0QoBq0 zyzxQ>-3g>6^U}aWTwI58xV_))4g2l7lct53Lz>o6n$AnL$Z39%roS#k-t6cuU3`zs z0U659PBhLfrA|``Xky58ypB&lw<>XA)9BbKb~8Y;5ksUr<==9Y0}27@AE;2ZacrrM z>N+`aWcR(g`!y=g$zk|LF^C;!bn9a@q=ywt`HENfGn#p8ZTOlF)j=r={G zyBU%+B|Yy1=O}?Wa(n4}bU&q^@eaR!ut73dA9w>1#pw{;$H|IavP;CH*p1hy)YDWO zm)tuDj+T4Q-Tnu7a9zaS*6Tj~NhQwVCwC5CKj!3^UwSLP@-lwIIr|y8^F8~4{j%l| zYT^L_AvATks4yq6s}oJv?xP|$#Mrml*uk~06XK76g1q5g1<@W0Xd zRaw0)S47W`2o>p@Y83J7qiwz#QPDqSTT@N+AsJGjene)E=UY8(DgF+gdl&m1#iIZz z9%xz}_QSfJrmB>vpKkN9!0$;zx3Kx*I4!u-JNevPUU!~10(?Ofb1?+`z&|?t2Y9q> A8UO$Q literal 0 HcmV?d00001 diff --git a/venv/Lib/site-packages/cachecontrol/__pycache__/compat.cpython-36.pyc b/venv/Lib/site-packages/cachecontrol/__pycache__/compat.cpython-36.pyc new file mode 100644 index 0000000000000000000000000000000000000000..a03ef683bbdb10cf058a866b8056d3325e0bf7ad GIT binary patch literal 759 zcmZ`#L5mYH6i#N^ZMWOjvL_EBg9o9=R(HD>Wf3oe3$iS_poT!1W?tKDGs&1_s&f~- z_$$2mC;TCE5(L4&;K|p{Sa$_8!FjI=%kOnzg0}Q!Fm-V30{(6 z^C!+qhO}(uR$UsY&oJ*kySO-i0WLGz!TK)UWR^{YG7ggApzI=7$>}JItpkhCNXos_ zG&9yewbt0OjrayDTjE@brGj!N+nnrBeO;BUQ+_20XE(+dCq literal 0 HcmV?d00001 diff --git a/venv/Lib/site-packages/cachecontrol/__pycache__/controller.cpython-36.pyc b/venv/Lib/site-packages/cachecontrol/__pycache__/controller.cpython-36.pyc new file mode 100644 index 0000000000000000000000000000000000000000..0a7427b75c05e1c9763637a1ee15fa0f40530911 GIT binary patch literal 7829 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 literal 0 HcmV?d00001 diff --git a/venv/Lib/site-packages/cachecontrol/__pycache__/filewrapper.cpython-36.pyc b/venv/Lib/site-packages/cachecontrol/__pycache__/filewrapper.cpython-36.pyc new file mode 100644 index 0000000000000000000000000000000000000000..4fe73924aafc6b5bfb905f6b786309fe561b5a56 GIT binary patch literal 2204 zcmZ`)U2oeq6eT6uRvahG)~#!cqT~8h18s(Oec8|r{a8B`7_x^9SZ4?zXpxSU*pf%m zaUFP1&VL#9m-IU9p?_gdJ6E!kwD4r`lG44rJm-GUU+?U+Umu;zf3_I=n_YP#te;{y z0il`ZBR1we&e@Ml2Rb}wIyAvD?1efyWZlL)Sg|fIThHg-xYs|Y^uB&VES_Sx=MaYV zxMsaTbL_1=^&%bV#yRUXbW^u5H+8JHFt_wadRuqSc`w#GdKX`|bQ`DbmDgUV(WtM| zlULcu{A$%?VyrsljI{-x!!fjCR(}@C7Smh{B?c2w^p8#I#cY_RLov%><&6>M)Y!Qn zX8Dn@Mro1dz7VQ%)t?Rq#@-hS9%e(63qMp|3~;K*oJdE7Gq8t8@@3wdbm|R`N>}jk z-4C(HRL;^O_a^sF6ocAN?R~#pX`jJ^^4?~B_;7%2#KabFGaLXo@F76M*wLJDRtRb~ ztL?uGD?rLQF?HBKHsijru127QE~b5eu3WgZfb)A&cEt#M$=}49LH1TS@OBlNyzq3a zO4CdOGx*Gf8!BDQ5Q|Hk`!zAjFg-K}7%wo~4G7PcY{4X7aL8a0K!%zjhy0)$Su!ne z$_>es60s?7Y*q~><(_4MZ>)Hjq~_@HHxC~r$P86da%xaYh^xwd_5e8= zpg2@&P)BKTlxIFGa^dFKJcen0n*5aY6PJ1OV1nXRN5&tgXI;8}|tW;{opkySy0$Jf=B1yStg^ z)$Q+5z33AGcSOTpCyBw2gC$$yuGQ2#kafR=mMXwfV9OZcJ5{5p`5)ZP8t^07uIi@A z_gZJSHe#%}9lTdI7vS!%z#XH7sc--oYRxAP?)bkq`u`3qcI`!YEj=yt9er<$08YHeDXnt?1&ml;c8AN3`xp`TJCjR+^TS zx=5w89h_n5mbpY&#khiT1zH7?8s5^yLZw*Yi`!8UH{wqGalGA*D;@6lGRTVhj&Ig~ URh43sw=#ZGBSinMBH0Q518SBje*gdg literal 0 HcmV?d00001 diff --git a/venv/Lib/site-packages/cachecontrol/__pycache__/heuristics.cpython-36.pyc b/venv/Lib/site-packages/cachecontrol/__pycache__/heuristics.cpython-36.pyc new file mode 100644 index 0000000000000000000000000000000000000000..c895f624920835f9cc495ba8cd77330e2e86af74 GIT binary patch literal 4734 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 literal 0 HcmV?d00001 diff --git a/venv/Lib/site-packages/cachecontrol/_cmd.py b/venv/Lib/site-packages/cachecontrol/_cmd.py new file mode 100644 index 000000000..ee8d60d10 --- /dev/null +++ b/venv/Lib/site-packages/cachecontrol/_cmd.py @@ -0,0 +1,57 @@ +import logging + +import requests + +from cachecontrol.adapter import CacheControlAdapter +from cachecontrol.cache import DictCache +from cachecontrol.controller import logger + +from argparse import ArgumentParser + + +def setup_logging(): + logger.setLevel(logging.DEBUG) + handler = logging.StreamHandler() + logger.addHandler(handler) + + +def get_session(): + adapter = CacheControlAdapter( + DictCache(), cache_etags=True, serializer=None, heuristic=None + ) + sess = requests.Session() + sess.mount("http://", adapter) + sess.mount("https://", adapter) + + sess.cache_controller = adapter.controller + return sess + + +def get_args(): + parser = ArgumentParser() + parser.add_argument("url", help="The URL to try and cache") + return parser.parse_args() + + +def main(args=None): + args = get_args() + sess = get_session() + + # Make a request to get a response + resp = sess.get(args.url) + + # Turn on logging + setup_logging() + + # try setting the cache + sess.cache_controller.cache_response(resp.request, resp.raw) + + # Now try to get it + if sess.cache_controller.cached_request(resp.request): + print("Cached!") + else: + print("Not cached :(") + + +if __name__ == "__main__": + main() diff --git a/venv/Lib/site-packages/cachecontrol/adapter.py b/venv/Lib/site-packages/cachecontrol/adapter.py new file mode 100644 index 000000000..de50006af --- /dev/null +++ b/venv/Lib/site-packages/cachecontrol/adapter.py @@ -0,0 +1,133 @@ +import types +import functools +import zlib + +from requests.adapters import HTTPAdapter + +from .controller import CacheController +from .cache import DictCache +from .filewrapper import CallbackFileWrapper + + +class CacheControlAdapter(HTTPAdapter): + invalidating_methods = {"PUT", "DELETE"} + + def __init__( + self, + cache=None, + cache_etags=True, + controller_class=None, + serializer=None, + heuristic=None, + cacheable_methods=None, + *args, + **kw + ): + super(CacheControlAdapter, self).__init__(*args, **kw) + self.cache = DictCache() if cache is None else cache + self.heuristic = heuristic + self.cacheable_methods = cacheable_methods or ("GET",) + + controller_factory = controller_class or CacheController + self.controller = controller_factory( + self.cache, cache_etags=cache_etags, serializer=serializer + ) + + def send(self, request, cacheable_methods=None, **kw): + """ + Send a request. Use the request information to see if it + exists in the cache and cache the response if we need to and can. + """ + cacheable = cacheable_methods or self.cacheable_methods + if request.method in cacheable: + try: + cached_response = self.controller.cached_request(request) + except zlib.error: + cached_response = None + if cached_response: + return self.build_response(request, cached_response, from_cache=True) + + # check for etags and add headers if appropriate + request.headers.update(self.controller.conditional_headers(request)) + + resp = super(CacheControlAdapter, self).send(request, **kw) + + return resp + + def build_response( + self, request, response, from_cache=False, cacheable_methods=None + ): + """ + Build a response by making a request or using the cache. + + This will end up calling send and returning a potentially + cached response + """ + cacheable = cacheable_methods or self.cacheable_methods + if not from_cache and request.method in cacheable: + # Check for any heuristics that might update headers + # before trying to cache. + if self.heuristic: + response = self.heuristic.apply(response) + + # apply any expiration heuristics + if response.status == 304: + # We must have sent an ETag request. This could mean + # that we've been expired already or that we simply + # have an etag. In either case, we want to try and + # update the cache if that is the case. + cached_response = self.controller.update_cached_response( + request, response + ) + + if cached_response is not response: + from_cache = True + + # We are done with the server response, read a + # possible response body (compliant servers will + # not return one, but we cannot be 100% sure) and + # release the connection back to the pool. + response.read(decode_content=False) + response.release_conn() + + response = cached_response + + # We always cache the 301 responses + elif response.status == 301: + self.controller.cache_response(request, response) + else: + # Wrap the response file with a wrapper that will cache the + # response when the stream has been consumed. + response._fp = CallbackFileWrapper( + response._fp, + functools.partial( + self.controller.cache_response, request, response + ), + ) + if response.chunked: + super_update_chunk_length = response._update_chunk_length + + def _update_chunk_length(self): + super_update_chunk_length() + if self.chunk_left == 0: + self._fp._close() + + response._update_chunk_length = types.MethodType( + _update_chunk_length, response + ) + + resp = super(CacheControlAdapter, self).build_response(request, response) + + # See if we should invalidate the cache. + if request.method in self.invalidating_methods and resp.ok: + cache_url = self.controller.cache_url(request.url) + self.cache.delete(cache_url) + + # Give the request a from_cache attr to let people use it + resp.from_cache = from_cache + + return resp + + def close(self): + self.cache.close() + super(CacheControlAdapter, self).close() diff --git a/venv/Lib/site-packages/cachecontrol/cache.py b/venv/Lib/site-packages/cachecontrol/cache.py new file mode 100644 index 000000000..94e07732d --- /dev/null +++ b/venv/Lib/site-packages/cachecontrol/cache.py @@ -0,0 +1,39 @@ +""" +The cache object API for implementing caches. The default is a thread +safe in-memory dictionary. +""" +from threading import Lock + + +class BaseCache(object): + + def get(self, key): + raise NotImplementedError() + + def set(self, key, value): + raise NotImplementedError() + + def delete(self, key): + raise NotImplementedError() + + def close(self): + pass + + +class DictCache(BaseCache): + + def __init__(self, init_dict=None): + self.lock = Lock() + self.data = init_dict or {} + + def get(self, key): + return self.data.get(key, None) + + def set(self, key, value): + with self.lock: + self.data.update({key: value}) + + def delete(self, key): + with self.lock: + if key in self.data: + self.data.pop(key) diff --git a/venv/Lib/site-packages/cachecontrol/caches/__init__.py b/venv/Lib/site-packages/cachecontrol/caches/__init__.py new file mode 100644 index 000000000..0e1658fa5 --- /dev/null +++ b/venv/Lib/site-packages/cachecontrol/caches/__init__.py @@ -0,0 +1,2 @@ +from .file_cache import FileCache # noqa +from .redis_cache import RedisCache # noqa diff --git a/venv/Lib/site-packages/cachecontrol/caches/__pycache__/__init__.cpython-36.pyc b/venv/Lib/site-packages/cachecontrol/caches/__pycache__/__init__.cpython-36.pyc new file mode 100644 index 0000000000000000000000000000000000000000..705c01dcde6570992ad533761ec5810a35f197d1 GIT binary patch literal 344 zcmX|7!Ait15KY=ew7P%bq1QdE%j#Yf5kU|H*@J?IWuRo!X&c)nB}ps2`!nJn_3FuA z@Z_|Jfth)4-kTxG#e5z;34HQ#YQ;-CuZa2FB|pV?ye z&B?Oh!_mE}@J`4Ai9}DBDmSt1Vm3q>X^9*~JFXs%?Wq5CLh5`ldq8DMKcDgnT8Gxb zUih{EqcOFrLrBq;-Zao^^=51dJqjCdz+sKfqm9=fG2dLS&!MsA6{Uv`3neRzh4yOc z3(S0+35l^qX>zT+GCFoW4cBDV9XzT%IOTEK2w9389Za{DMtf_j)kNGXNfgZ{$yw76 Shu5`9+X`>Se{kdLPWUgxNN868 literal 0 HcmV?d00001 diff --git a/venv/Lib/site-packages/cachecontrol/caches/__pycache__/file_cache.cpython-36.pyc b/venv/Lib/site-packages/cachecontrol/caches/__pycache__/file_cache.cpython-36.pyc new file mode 100644 index 0000000000000000000000000000000000000000..1dc58879229e34dc80b777cf6964e86743a76c28 GIT binary patch literal 3254 zcmZWr-EP~+6`mRXh@xf1F&1eyO}8wt-Bybx!KOjc1Zlb(BQ64XCDh3_i6DTWIU`Fl zMXE!}i43YJR_R^Q1^NJc-vWJyJ_m1ml~?FhzcY+vJEbsZ{>~iDcYf!W+uQ!rcMITU~>Ylt;8aQP)G zMafsz(pt1I-zqI>t;92<2u}BCl@`hQmc3U816;dX`Mt2)+wUD5^j=h6FMRy8`_fuY2&SYV^Xr!zW)ouiRevJ5^QV zY43^FnZ}`K^}x<%Dy`h1G`$liS*|*EmMW>or)nToeo|z!!8{$m&h*J(p&}jJ8{}%L@$FBfJ9)K|6x;wVdeGAPN zyv=v9(&mDDIk*UH&a!+>}CE37?83Vi03Hv8ML2j>J#ls?K>N7Or$weAz6Vvbn-pxZw4d zkgR3tE#0(bWP5s6HkNM5OBOcZ%q;Xu3$$6C)U99u7({nHOFeBIvjCl7+BX^?3N zUn(;5R}d9!^cO6$c`%*lMKFp^)uq#P19FRCoaRM@93gK9ufQEg>3S&`7s2T`3TETk zgG*-vTH0`}C0%0av?~7(Q8HI`Y##KO*ubtC_#~&+YR9kaTqQ&ODbDMk68VhC&q!SBqB-=>X`OCW z|GNvDjbmj3yCxsg87~aS2){6VfLTsbnZLt5fwn5+dgip!JnMJzDKR{7g;V@NT&MAj8q@`>8Z2KGub}zx8OlDwEIy#53_{0D~N&C)U zTBSu=e#U;!4%thp%O4>dSjYws>!L+5jCx#ys)Rnmh3`Y2rqWs2T1B$DN_XgH#eOzV zrE%6ZD(gfo^sk6h3`hS52hpBjFQ-QZ<343pdhu&aHVQ-r zpYZ%19x-s|HE`n#Hhkgk#Rtq9yi>q)2yGUqAL8RL-to$%U!keR}hgB;K|2U75dPn~P%vB2s9XV`@ zvXV&?i}j^{OX8jo*(Y+YTQedB>mP!Uit>*@Jm>w}jQc^$_8MN(Ya5PBs@}+rdyXiEb;xwe96H|2$C@Ta};^`>~Oqgh>=oLVyRSN{7~7v9_EM#e3wW*0`Qi`jWV qm{=fXn?Ja4r;RBp?_q7@M^q>BYakx?@Cs|835?pPH(qDw`TqbpA^dj$ literal 0 HcmV?d00001 diff --git a/venv/Lib/site-packages/cachecontrol/caches/__pycache__/redis_cache.cpython-36.pyc b/venv/Lib/site-packages/cachecontrol/caches/__pycache__/redis_cache.cpython-36.pyc new file mode 100644 index 0000000000000000000000000000000000000000..f3a4b93864fa41d977e28ed6b16e0744807de76d GIT binary patch literal 1588 zcmaJ>Pp=y_5VzO6$-Xpc162IEfRTEML{k-d08|x3k)TqQ0|+5Si&lQ?NwRsH-PHEx z{ZV?#`!ZbkKzrrHSK!2qH{pe+CoI_>uV;4V_nR4iF&Ok-&9Bqfg0Vl@(Fjrg7N`9Z z7tJ&;*osd%CpjpBRWJ>_EDEs-ry*xQFdgdXn&}9_otQ?t^D`TD|3Ygv;!UjcO>Xn5 z^s;i`@)e+b@}08qQe_LsNb@i-n%4UZ6o5^+X461(9bB`i&_ai}hx)$m=}_i*p(z8>Hn>j-0b(DZ%+o!iz+uy;W_&6hZB50@?9vJ}yw1)pGKVOEvpC}=_p z#msb2<9B9a-2VO}`#PyD7@M3bS1*#P1a0ySBpU3QtJX`rp} zL=IcBCExNLZ|Mm8z;sa;l9 z=S_rP;Gz+E>6(G7oGMa_WS82GLJ!1Hz)iGKMGZ|CF4nmLdmGpQbspffR1l1Zd>Hik z)iFGDb2ptsG&msJ`F{Ejr5z0gM!09y2Xou`L;S=0I1jA8bHr+EopHRTK?x=Jp4Uex zTzuU6-m&l5Z^O4(^O)Fx63f|}{;$~Q7)@~X>PINnSh2IpNUTp~@^UU!QAn&&iHWu{ zFQt-NIdzH+JeI#$kmtEu^yGeIs;27wbTSfcDnc?d6#M^RYa;LMBh<3KHpGx$4Uh2o z>wn=9Oqw1Z>F>k;##=~iQY)#AvDK)P)>Ty?kk4dU$r3R@seJU6Y9HCtsqUCUYf2dT^A(x)AUWPiuT6P%j4U`P)T`u z4CU5*K+BD1FZrH|@PZo7Qk}*@EMn2?;@UBEGZ}Tr+pKoAL2rf%z&F73UH={+NO~#8 b{$PkQZ+4fbCVt)q{emdA^aA#=%KPFUr)Xzg literal 0 HcmV?d00001 diff --git a/venv/Lib/site-packages/cachecontrol/caches/file_cache.py b/venv/Lib/site-packages/cachecontrol/caches/file_cache.py new file mode 100644 index 000000000..607b94524 --- /dev/null +++ b/venv/Lib/site-packages/cachecontrol/caches/file_cache.py @@ -0,0 +1,146 @@ +import hashlib +import os +from textwrap import dedent + +from ..cache import BaseCache +from ..controller import CacheController + +try: + FileNotFoundError +except NameError: + # py2.X + FileNotFoundError = (IOError, OSError) + + +def _secure_open_write(filename, fmode): + # We only want to write to this file, so open it in write only mode + flags = os.O_WRONLY + + # os.O_CREAT | os.O_EXCL will fail if the file already exists, so we only + # will open *new* files. + # We specify this because we want to ensure that the mode we pass is the + # mode of the file. + flags |= os.O_CREAT | os.O_EXCL + + # Do not follow symlinks to prevent someone from making a symlink that + # we follow and insecurely open a cache file. + if hasattr(os, "O_NOFOLLOW"): + flags |= os.O_NOFOLLOW + + # On Windows we'll mark this file as binary + if hasattr(os, "O_BINARY"): + flags |= os.O_BINARY + + # Before we open our file, we want to delete any existing file that is + # there + try: + os.remove(filename) + except (IOError, OSError): + # The file must not exist already, so we can just skip ahead to opening + pass + + # Open our file, the use of os.O_CREAT | os.O_EXCL will ensure that if a + # race condition happens between the os.remove and this line, that an + # error will be raised. Because we utilize a lockfile this should only + # happen if someone is attempting to attack us. + fd = os.open(filename, flags, fmode) + try: + return os.fdopen(fd, "wb") + + except: + # An error occurred wrapping our FD in a file object + os.close(fd) + raise + + +class FileCache(BaseCache): + + def __init__( + self, + directory, + forever=False, + filemode=0o0600, + dirmode=0o0700, + use_dir_lock=None, + lock_class=None, + ): + + if use_dir_lock is not None and lock_class is not None: + raise ValueError("Cannot use use_dir_lock and lock_class together") + + try: + from lockfile import LockFile + from lockfile.mkdirlockfile import MkdirLockFile + except ImportError: + notice = dedent( + """ + NOTE: In order to use the FileCache you must have + lockfile installed. You can install it via pip: + pip install lockfile + """ + ) + raise ImportError(notice) + + else: + if use_dir_lock: + lock_class = MkdirLockFile + + elif lock_class is None: + lock_class = LockFile + + self.directory = directory + self.forever = forever + self.filemode = filemode + self.dirmode = dirmode + self.lock_class = lock_class + + @staticmethod + def encode(x): + return hashlib.sha224(x.encode()).hexdigest() + + def _fn(self, name): + # NOTE: This method should not change as some may depend on it. + # See: https://github.com/ionrock/cachecontrol/issues/63 + hashed = self.encode(name) + parts = list(hashed[:5]) + [hashed] + return os.path.join(self.directory, *parts) + + def get(self, key): + name = self._fn(key) + try: + with open(name, "rb") as fh: + return fh.read() + + except FileNotFoundError: + return None + + def set(self, key, value): + name = self._fn(key) + + # Make sure the directory exists + try: + os.makedirs(os.path.dirname(name), self.dirmode) + except (IOError, OSError): + pass + + with self.lock_class(name) as lock: + # Write our actual file + with _secure_open_write(lock.path, self.filemode) as fh: + fh.write(value) + + def delete(self, key): + name = self._fn(key) + if not self.forever: + try: + os.remove(name) + except FileNotFoundError: + pass + + +def url_to_file_path(url, filecache): + """Return the file cache path based on the URL. + + This does not ensure the file exists! + """ + key = CacheController.cache_url(url) + return filecache._fn(key) diff --git a/venv/Lib/site-packages/cachecontrol/caches/redis_cache.py b/venv/Lib/site-packages/cachecontrol/caches/redis_cache.py new file mode 100644 index 000000000..16da0aed9 --- /dev/null +++ b/venv/Lib/site-packages/cachecontrol/caches/redis_cache.py @@ -0,0 +1,33 @@ +from __future__ import division + +from datetime import datetime +from cachecontrol.cache import BaseCache + + +class RedisCache(BaseCache): + + def __init__(self, conn): + self.conn = conn + + def get(self, key): + return self.conn.get(key) + + def set(self, key, value, expires=None): + if not expires: + self.conn.set(key, value) + else: + expires = expires - datetime.utcnow() + self.conn.setex(key, int(expires.total_seconds()), value) + + def delete(self, key): + self.conn.delete(key) + + def clear(self): + """Helper for clearing all the keys in a database. Use with + caution!""" + for key in self.conn.keys(): + self.conn.delete(key) + + def close(self): + """Redis uses connection pooling, no need to close the connection.""" + pass diff --git a/venv/Lib/site-packages/cachecontrol/compat.py b/venv/Lib/site-packages/cachecontrol/compat.py new file mode 100644 index 000000000..143c8ab08 --- /dev/null +++ b/venv/Lib/site-packages/cachecontrol/compat.py @@ -0,0 +1,29 @@ +try: + from urllib.parse import urljoin +except ImportError: + from urlparse import urljoin + + +try: + import cPickle as pickle +except ImportError: + import pickle + + +# Handle the case where the requests module has been patched to not have +# urllib3 bundled as part of its source. +try: + from requests.packages.urllib3.response import HTTPResponse +except ImportError: + from urllib3.response import HTTPResponse + +try: + from requests.packages.urllib3.util import is_fp_closed +except ImportError: + from urllib3.util import is_fp_closed + +# Replicate some six behaviour +try: + text_type = unicode +except NameError: + text_type = str diff --git a/venv/Lib/site-packages/cachecontrol/controller.py b/venv/Lib/site-packages/cachecontrol/controller.py new file mode 100644 index 000000000..c5c4a5080 --- /dev/null +++ b/venv/Lib/site-packages/cachecontrol/controller.py @@ -0,0 +1,376 @@ +""" +The httplib2 algorithms ported for use with requests. +""" +import logging +import re +import calendar +import time +from email.utils import parsedate_tz + +from requests.structures import CaseInsensitiveDict + +from .cache import DictCache +from .serialize import Serializer + + +logger = logging.getLogger(__name__) + +URI = re.compile(r"^(([^:/?#]+):)?(//([^/?#]*))?([^?#]*)(\?([^#]*))?(#(.*))?") + + +def parse_uri(uri): + """Parses a URI using the regex given in Appendix B of RFC 3986. + + (scheme, authority, path, query, fragment) = parse_uri(uri) + """ + groups = URI.match(uri).groups() + return (groups[1], groups[3], groups[4], groups[6], groups[8]) + + +class CacheController(object): + """An interface to see if request should cached or not. + """ + + def __init__( + self, cache=None, cache_etags=True, serializer=None, status_codes=None + ): + self.cache = DictCache() if cache is None else cache + self.cache_etags = cache_etags + self.serializer = serializer or Serializer() + self.cacheable_status_codes = status_codes or (200, 203, 300, 301) + + @classmethod + def _urlnorm(cls, uri): + """Normalize the URL to create a safe key for the cache""" + (scheme, authority, path, query, fragment) = parse_uri(uri) + if not scheme or not authority: + raise Exception("Only absolute URIs are allowed. uri = %s" % uri) + + scheme = scheme.lower() + authority = authority.lower() + + if not path: + path = "/" + + # Could do syntax based normalization of the URI before + # computing the digest. See Section 6.2.2 of Std 66. + request_uri = query and "?".join([path, query]) or path + defrag_uri = scheme + "://" + authority + request_uri + + return defrag_uri + + @classmethod + def cache_url(cls, uri): + return cls._urlnorm(uri) + + def parse_cache_control(self, headers): + known_directives = { + # https://tools.ietf.org/html/rfc7234#section-5.2 + "max-age": (int, True), + "max-stale": (int, False), + "min-fresh": (int, True), + "no-cache": (None, False), + "no-store": (None, False), + "no-transform": (None, False), + "only-if-cached": (None, False), + "must-revalidate": (None, False), + "public": (None, False), + "private": (None, False), + "proxy-revalidate": (None, False), + "s-maxage": (int, True), + } + + cc_headers = headers.get("cache-control", headers.get("Cache-Control", "")) + + retval = {} + + for cc_directive in cc_headers.split(","): + if not cc_directive.strip(): + continue + + parts = cc_directive.split("=", 1) + directive = parts[0].strip() + + try: + typ, required = known_directives[directive] + except KeyError: + logger.debug("Ignoring unknown cache-control directive: %s", directive) + continue + + if not typ or not required: + retval[directive] = None + if typ: + try: + retval[directive] = typ(parts[1].strip()) + except IndexError: + if required: + logger.debug( + "Missing value for cache-control " "directive: %s", + directive, + ) + except ValueError: + logger.debug( + "Invalid value for cache-control directive " "%s, must be %s", + directive, + typ.__name__, + ) + + return retval + + def cached_request(self, request): + """ + Return a cached response if it exists in the cache, otherwise + return False. + """ + cache_url = self.cache_url(request.url) + logger.debug('Looking up "%s" in the cache', cache_url) + cc = self.parse_cache_control(request.headers) + + # Bail out if the request insists on fresh data + if "no-cache" in cc: + logger.debug('Request header has "no-cache", cache bypassed') + return False + + if "max-age" in cc and cc["max-age"] == 0: + logger.debug('Request header has "max_age" as 0, cache bypassed') + return False + + # Request allows serving from the cache, let's see if we find something + cache_data = self.cache.get(cache_url) + if cache_data is None: + logger.debug("No cache entry available") + return False + + # Check whether it can be deserialized + resp = self.serializer.loads(request, cache_data) + if not resp: + logger.warning("Cache entry deserialization failed, entry ignored") + return False + + # If we have a cached 301, return it immediately. We don't + # need to test our response for other headers b/c it is + # intrinsically "cacheable" as it is Permanent. + # See: + # https://tools.ietf.org/html/rfc7231#section-6.4.2 + # + # Client can try to refresh the value by repeating the request + # with cache busting headers as usual (ie no-cache). + if resp.status == 301: + msg = ( + 'Returning cached "301 Moved Permanently" response ' + "(ignoring date and etag information)" + ) + logger.debug(msg) + return resp + + headers = CaseInsensitiveDict(resp.headers) + if not headers or "date" not in headers: + if "etag" not in headers: + # Without date or etag, the cached response can never be used + # and should be deleted. + logger.debug("Purging cached response: no date or etag") + self.cache.delete(cache_url) + logger.debug("Ignoring cached response: no date") + return False + + now = time.time() + date = calendar.timegm(parsedate_tz(headers["date"])) + current_age = max(0, now - date) + logger.debug("Current age based on date: %i", current_age) + + # TODO: There is an assumption that the result will be a + # urllib3 response object. This may not be best since we + # could probably avoid instantiating or constructing the + # response until we know we need it. + resp_cc = self.parse_cache_control(headers) + + # determine freshness + freshness_lifetime = 0 + + # Check the max-age pragma in the cache control header + if "max-age" in resp_cc: + freshness_lifetime = resp_cc["max-age"] + logger.debug("Freshness lifetime from max-age: %i", freshness_lifetime) + + # If there isn't a max-age, check for an expires header + elif "expires" in headers: + expires = parsedate_tz(headers["expires"]) + if expires is not None: + expire_time = calendar.timegm(expires) - date + freshness_lifetime = max(0, expire_time) + logger.debug("Freshness lifetime from expires: %i", freshness_lifetime) + + # Determine if we are setting freshness limit in the + # request. Note, this overrides what was in the response. + if "max-age" in cc: + freshness_lifetime = cc["max-age"] + logger.debug( + "Freshness lifetime from request max-age: %i", freshness_lifetime + ) + + if "min-fresh" in cc: + min_fresh = cc["min-fresh"] + # adjust our current age by our min fresh + current_age += min_fresh + logger.debug("Adjusted current age from min-fresh: %i", current_age) + + # Return entry if it is fresh enough + if freshness_lifetime > current_age: + logger.debug('The response is "fresh", returning cached response') + logger.debug("%i > %i", freshness_lifetime, current_age) + return resp + + # we're not fresh. If we don't have an Etag, clear it out + if "etag" not in headers: + logger.debug('The cached response is "stale" with no etag, purging') + self.cache.delete(cache_url) + + # return the original handler + return False + + def conditional_headers(self, request): + cache_url = self.cache_url(request.url) + resp = self.serializer.loads(request, self.cache.get(cache_url)) + new_headers = {} + + if resp: + headers = CaseInsensitiveDict(resp.headers) + + if "etag" in headers: + new_headers["If-None-Match"] = headers["ETag"] + + if "last-modified" in headers: + new_headers["If-Modified-Since"] = headers["Last-Modified"] + + return new_headers + + def cache_response(self, request, response, body=None, status_codes=None): + """ + Algorithm for caching requests. + + This assumes a requests Response object. + """ + # From httplib2: Don't cache 206's since we aren't going to + # handle byte range requests + cacheable_status_codes = status_codes or self.cacheable_status_codes + if response.status not in cacheable_status_codes: + logger.debug( + "Status code %s not in %s", response.status, cacheable_status_codes + ) + return + + response_headers = CaseInsensitiveDict(response.headers) + + # If we've been given a body, our response has a Content-Length, that + # Content-Length is valid then we can check to see if the body we've + # been given matches the expected size, and if it doesn't we'll just + # skip trying to cache it. + if ( + body is not None + and "content-length" in response_headers + and response_headers["content-length"].isdigit() + and int(response_headers["content-length"]) != len(body) + ): + return + + cc_req = self.parse_cache_control(request.headers) + cc = self.parse_cache_control(response_headers) + + cache_url = self.cache_url(request.url) + logger.debug('Updating cache with response from "%s"', cache_url) + + # Delete it from the cache if we happen to have it stored there + no_store = False + if "no-store" in cc: + no_store = True + logger.debug('Response header has "no-store"') + if "no-store" in cc_req: + no_store = True + logger.debug('Request header has "no-store"') + if no_store and self.cache.get(cache_url): + logger.debug('Purging existing cache entry to honor "no-store"') + self.cache.delete(cache_url) + if no_store: + return + + # https://tools.ietf.org/html/rfc7234#section-4.1: + # A Vary header field-value of "*" always fails to match. + # Storing such a response leads to a deserialization warning + # during cache lookup and is not allowed to ever be served, + # so storing it can be avoided. + if "*" in response_headers.get("vary", ""): + logger.debug('Response header has "Vary: *"') + return + + # If we've been given an etag, then keep the response + if self.cache_etags and "etag" in response_headers: + logger.debug("Caching due to etag") + self.cache.set( + cache_url, self.serializer.dumps(request, response, body=body) + ) + + # Add to the cache any 301s. We do this before looking that + # the Date headers. + elif response.status == 301: + logger.debug("Caching permanant redirect") + self.cache.set(cache_url, self.serializer.dumps(request, response)) + + # Add to the cache if the response headers demand it. If there + # is no date header then we can't do anything about expiring + # the cache. + elif "date" in response_headers: + # cache when there is a max-age > 0 + if "max-age" in cc and cc["max-age"] > 0: + logger.debug("Caching b/c date exists and max-age > 0") + self.cache.set( + cache_url, self.serializer.dumps(request, response, body=body) + ) + + # If the request can expire, it means we should cache it + # in the meantime. + elif "expires" in response_headers: + if response_headers["expires"]: + logger.debug("Caching b/c of expires header") + self.cache.set( + cache_url, self.serializer.dumps(request, response, body=body) + ) + + def update_cached_response(self, request, response): + """On a 304 we will get a new set of headers that we want to + update our cached value with, assuming we have one. + + This should only ever be called when we've sent an ETag and + gotten a 304 as the response. + """ + cache_url = self.cache_url(request.url) + + cached_response = self.serializer.loads(request, self.cache.get(cache_url)) + + if not cached_response: + # we didn't have a cached response + return response + + # Lets update our headers with the headers from the new request: + # http://tools.ietf.org/html/draft-ietf-httpbis-p4-conditional-26#section-4.1 + # + # The server isn't supposed to send headers that would make + # the cached body invalid. But... just in case, we'll be sure + # to strip out ones we know that might be problmatic due to + # typical assumptions. + excluded_headers = ["content-length"] + + cached_response.headers.update( + dict( + (k, v) + for k, v in response.headers.items() + if k.lower() not in excluded_headers + ) + ) + + # we want a 200 b/c we have content via the cache + cached_response.status = 200 + + # update our cache + self.cache.set(cache_url, self.serializer.dumps(request, cached_response)) + + return cached_response diff --git a/venv/Lib/site-packages/cachecontrol/filewrapper.py b/venv/Lib/site-packages/cachecontrol/filewrapper.py new file mode 100644 index 000000000..30ed4c5a6 --- /dev/null +++ b/venv/Lib/site-packages/cachecontrol/filewrapper.py @@ -0,0 +1,80 @@ +from io import BytesIO + + +class CallbackFileWrapper(object): + """ + Small wrapper around a fp object which will tee everything read into a + buffer, and when that file is closed it will execute a callback with the + contents of that buffer. + + All attributes are proxied to the underlying file object. + + This class uses members with a double underscore (__) leading prefix so as + not to accidentally shadow an attribute. + """ + + def __init__(self, fp, callback): + self.__buf = BytesIO() + self.__fp = fp + self.__callback = callback + + def __getattr__(self, name): + # The vaguaries of garbage collection means that self.__fp is + # not always set. By using __getattribute__ and the private + # name[0] allows looking up the attribute value and raising an + # AttributeError when it doesn't exist. This stop thigns from + # infinitely recursing calls to getattr in the case where + # self.__fp hasn't been set. + # + # [0] https://docs.python.org/2/reference/expressions.html#atom-identifiers + fp = self.__getattribute__("_CallbackFileWrapper__fp") + return getattr(fp, name) + + def __is_fp_closed(self): + try: + return self.__fp.fp is None + + except AttributeError: + pass + + try: + return self.__fp.closed + + except AttributeError: + pass + + # We just don't cache it then. + # TODO: Add some logging here... + return False + + def _close(self): + if self.__callback: + self.__callback(self.__buf.getvalue()) + + # We assign this to None here, because otherwise we can get into + # really tricky problems where the CPython interpreter dead locks + # because the callback is holding a reference to something which + # has a __del__ method. Setting this to None breaks the cycle + # and allows the garbage collector to do it's thing normally. + self.__callback = None + + def read(self, amt=None): + data = self.__fp.read(amt) + self.__buf.write(data) + if self.__is_fp_closed(): + self._close() + + return data + + def _safe_read(self, amt): + data = self.__fp._safe_read(amt) + if amt == 2 and data == b"\r\n": + # urllib executes this read to toss the CRLF at the end + # of the chunk. + return data + + self.__buf.write(data) + if self.__is_fp_closed(): + self._close() + + return data diff --git a/venv/Lib/site-packages/cachecontrol/heuristics.py b/venv/Lib/site-packages/cachecontrol/heuristics.py new file mode 100644 index 000000000..6c0e9790d --- /dev/null +++ b/venv/Lib/site-packages/cachecontrol/heuristics.py @@ -0,0 +1,135 @@ +import calendar +import time + +from email.utils import formatdate, parsedate, parsedate_tz + +from datetime import datetime, timedelta + +TIME_FMT = "%a, %d %b %Y %H:%M:%S GMT" + + +def expire_after(delta, date=None): + date = date or datetime.utcnow() + return date + delta + + +def datetime_to_header(dt): + return formatdate(calendar.timegm(dt.timetuple())) + + +class BaseHeuristic(object): + + def warning(self, response): + """ + Return a valid 1xx warning header value describing the cache + adjustments. + + The response is provided too allow warnings like 113 + http://tools.ietf.org/html/rfc7234#section-5.5.4 where we need + to explicitly say response is over 24 hours old. + """ + return '110 - "Response is Stale"' + + def update_headers(self, response): + """Update the response headers with any new headers. + + NOTE: This SHOULD always include some Warning header to + signify that the response was cached by the client, not + by way of the provided headers. + """ + return {} + + def apply(self, response): + updated_headers = self.update_headers(response) + + if updated_headers: + response.headers.update(updated_headers) + warning_header_value = self.warning(response) + if warning_header_value is not None: + response.headers.update({"Warning": warning_header_value}) + + return response + + +class OneDayCache(BaseHeuristic): + """ + Cache the response by providing an expires 1 day in the + future. + """ + + def update_headers(self, response): + headers = {} + + if "expires" not in response.headers: + date = parsedate(response.headers["date"]) + expires = expire_after(timedelta(days=1), date=datetime(*date[:6])) + headers["expires"] = datetime_to_header(expires) + headers["cache-control"] = "public" + return headers + + +class ExpiresAfter(BaseHeuristic): + """ + Cache **all** requests for a defined time period. + """ + + def __init__(self, **kw): + self.delta = timedelta(**kw) + + def update_headers(self, response): + expires = expire_after(self.delta) + return {"expires": datetime_to_header(expires), "cache-control": "public"} + + def warning(self, response): + tmpl = "110 - Automatically cached for %s. Response might be stale" + return tmpl % self.delta + + +class LastModified(BaseHeuristic): + """ + If there is no Expires header already, fall back on Last-Modified + using the heuristic from + http://tools.ietf.org/html/rfc7234#section-4.2.2 + to calculate a reasonable value. + + Firefox also does something like this per + https://developer.mozilla.org/en-US/docs/Web/HTTP/Caching_FAQ + http://lxr.mozilla.org/mozilla-release/source/netwerk/protocol/http/nsHttpResponseHead.cpp#397 + Unlike mozilla we limit this to 24-hr. + """ + cacheable_by_default_statuses = { + 200, 203, 204, 206, 300, 301, 404, 405, 410, 414, 501 + } + + def update_headers(self, resp): + headers = resp.headers + + if "expires" in headers: + return {} + + if "cache-control" in headers and headers["cache-control"] != "public": + return {} + + if resp.status not in self.cacheable_by_default_statuses: + return {} + + if "date" not in headers or "last-modified" not in headers: + return {} + + date = calendar.timegm(parsedate_tz(headers["date"])) + last_modified = parsedate(headers["last-modified"]) + if date is None or last_modified is None: + return {} + + now = time.time() + current_age = max(0, now - date) + delta = date - calendar.timegm(last_modified) + freshness_lifetime = max(0, min(delta / 10, 24 * 3600)) + if freshness_lifetime <= current_age: + return {} + + expires = date + freshness_lifetime + return {"expires": time.strftime(TIME_FMT, time.gmtime(expires))} + + def warning(self, resp): + return None diff --git a/venv/Lib/site-packages/cachecontrol/serialize.py b/venv/Lib/site-packages/cachecontrol/serialize.py new file mode 100644 index 000000000..572cf0e6c --- /dev/null +++ b/venv/Lib/site-packages/cachecontrol/serialize.py @@ -0,0 +1,188 @@ +import base64 +import io +import json +import zlib + +import msgpack +from requests.structures import CaseInsensitiveDict + +from .compat import HTTPResponse, pickle, text_type + + +def _b64_decode_bytes(b): + return base64.b64decode(b.encode("ascii")) + + +def _b64_decode_str(s): + return _b64_decode_bytes(s).decode("utf8") + + +class Serializer(object): + + def dumps(self, request, response, body=None): + response_headers = CaseInsensitiveDict(response.headers) + + if body is None: + body = response.read(decode_content=False) + + # NOTE: 99% sure this is dead code. I'm only leaving it + # here b/c I don't have a test yet to prove + # it. Basically, before using + # `cachecontrol.filewrapper.CallbackFileWrapper`, + # this made an effort to reset the file handle. The + # `CallbackFileWrapper` short circuits this code by + # setting the body as the content is consumed, the + # result being a `body` argument is *always* passed + # into cache_response, and in turn, + # `Serializer.dump`. + response._fp = io.BytesIO(body) + + # NOTE: This is all a bit weird, but it's really important that on + # Python 2.x these objects are unicode and not str, even when + # they contain only ascii. The problem here is that msgpack + # understands the difference between unicode and bytes and we + # have it set to differentiate between them, however Python 2 + # doesn't know the difference. Forcing these to unicode will be + # enough to have msgpack know the difference. + data = { + u"response": { + u"body": body, + u"headers": dict( + (text_type(k), text_type(v)) for k, v in response.headers.items() + ), + u"status": response.status, + u"version": response.version, + u"reason": text_type(response.reason), + u"strict": response.strict, + u"decode_content": response.decode_content, + } + } + + # Construct our vary headers + data[u"vary"] = {} + if u"vary" in response_headers: + varied_headers = response_headers[u"vary"].split(",") + for header in varied_headers: + header = text_type(header).strip() + header_value = request.headers.get(header, None) + if header_value is not None: + header_value = text_type(header_value) + data[u"vary"][header] = header_value + + return b",".join([b"cc=4", msgpack.dumps(data, use_bin_type=True)]) + + def loads(self, request, data): + # Short circuit if we've been given an empty set of data + if not data: + return + + # Determine what version of the serializer the data was serialized + # with + try: + ver, data = data.split(b",", 1) + except ValueError: + ver = b"cc=0" + + # Make sure that our "ver" is actually a version and isn't a false + # positive from a , being in the data stream. + if ver[:3] != b"cc=": + data = ver + data + ver = b"cc=0" + + # Get the version number out of the cc=N + ver = ver.split(b"=", 1)[-1].decode("ascii") + + # Dispatch to the actual load method for the given version + try: + return getattr(self, "_loads_v{}".format(ver))(request, data) + + except AttributeError: + # This is a version we don't have a loads function for, so we'll + # just treat it as a miss and return None + return + + def prepare_response(self, request, cached): + """Verify our vary headers match and construct a real urllib3 + HTTPResponse object. + """ + # Special case the '*' Vary value as it means we cannot actually + # determine if the cached response is suitable for this request. + # This case is also handled in the controller code when creating + # a cache entry, but is left here for backwards compatibility. + if "*" in cached.get("vary", {}): + return + + # Ensure that the Vary headers for the cached response match our + # request + for header, value in cached.get("vary", {}).items(): + if request.headers.get(header, None) != value: + return + + body_raw = cached["response"].pop("body") + + headers = CaseInsensitiveDict(data=cached["response"]["headers"]) + if headers.get("transfer-encoding", "") == "chunked": + headers.pop("transfer-encoding") + + cached["response"]["headers"] = headers + + try: + body = io.BytesIO(body_raw) + except TypeError: + # This can happen if cachecontrol serialized to v1 format (pickle) + # using Python 2. A Python 2 str(byte string) will be unpickled as + # a Python 3 str (unicode string), which will cause the above to + # fail with: + # + # TypeError: 'str' does not support the buffer interface + body = io.BytesIO(body_raw.encode("utf8")) + + return HTTPResponse(body=body, preload_content=False, **cached["response"]) + + def _loads_v0(self, request, data): + # The original legacy cache data. This doesn't contain enough + # information to construct everything we need, so we'll treat this as + # a miss. + return + + def _loads_v1(self, request, data): + try: + cached = pickle.loads(data) + except ValueError: + return + + return self.prepare_response(request, cached) + + def _loads_v2(self, request, data): + try: + cached = json.loads(zlib.decompress(data).decode("utf8")) + except (ValueError, zlib.error): + return + + # We need to decode the items that we've base64 encoded + cached["response"]["body"] = _b64_decode_bytes(cached["response"]["body"]) + cached["response"]["headers"] = dict( + (_b64_decode_str(k), _b64_decode_str(v)) + for k, v in cached["response"]["headers"].items() + ) + cached["response"]["reason"] = _b64_decode_str(cached["response"]["reason"]) + cached["vary"] = dict( + (_b64_decode_str(k), _b64_decode_str(v) if v is not None else v) + for k, v in cached["vary"].items() + ) + + return self.prepare_response(request, cached) + + def _loads_v3(self, request, data): + # Due to Python 2 encoding issues, it's impossible to know for sure + # exactly how to load v3 entries, thus we'll treat these as a miss so + # that they get rewritten out as v4 entries. + return + + def _loads_v4(self, request, data): + try: + cached = msgpack.loads(data, raw=False) + except ValueError: + return + + return self.prepare_response(request, cached) diff --git a/venv/Lib/site-packages/cachecontrol/wrapper.py b/venv/Lib/site-packages/cachecontrol/wrapper.py new file mode 100644 index 000000000..d8e6fc6a9 --- /dev/null +++ b/venv/Lib/site-packages/cachecontrol/wrapper.py @@ -0,0 +1,29 @@ +from .adapter import CacheControlAdapter +from .cache import DictCache + + +def CacheControl( + sess, + cache=None, + cache_etags=True, + serializer=None, + heuristic=None, + controller_class=None, + adapter_class=None, + cacheable_methods=None, +): + + cache = DictCache() if cache is None else cache + adapter_class = adapter_class or CacheControlAdapter + adapter = adapter_class( + cache, + cache_etags=cache_etags, + serializer=serializer, + heuristic=heuristic, + controller_class=controller_class, + cacheable_methods=cacheable_methods, + ) + sess.mount("http://", adapter) + sess.mount("https://", adapter) + + return sess diff --git a/venv/Lib/site-packages/cachetools-4.1.1.dist-info/INSTALLER b/venv/Lib/site-packages/cachetools-4.1.1.dist-info/INSTALLER new file mode 100644 index 000000000..a1b589e38 --- /dev/null +++ b/venv/Lib/site-packages/cachetools-4.1.1.dist-info/INSTALLER @@ -0,0 +1 @@ +pip diff --git a/venv/Lib/site-packages/cachetools-4.1.1.dist-info/LICENSE b/venv/Lib/site-packages/cachetools-4.1.1.dist-info/LICENSE new file mode 100644 index 000000000..0dc186434 --- /dev/null +++ b/venv/Lib/site-packages/cachetools-4.1.1.dist-info/LICENSE @@ -0,0 +1,20 @@ +The MIT License (MIT) + +Copyright (c) 2014-2020 Thomas Kemmer + +Permission is hereby granted, free of charge, to any person obtaining a copy of +this software and associated documentation files (the "Software"), to deal in +the Software without restriction, including without limitation the rights to +use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of +the Software, and to permit persons to whom the Software is furnished to do so, +subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS +FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR +COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER +IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. diff --git a/venv/Lib/site-packages/cachetools-4.1.1.dist-info/METADATA b/venv/Lib/site-packages/cachetools-4.1.1.dist-info/METADATA new file mode 100644 index 000000000..44223974d --- /dev/null +++ b/venv/Lib/site-packages/cachetools-4.1.1.dist-info/METADATA @@ -0,0 +1,124 @@ +Metadata-Version: 2.1 +Name: cachetools +Version: 4.1.1 +Summary: Extensible memoizing collections and decorators +Home-page: https://github.com/tkem/cachetools/ +Author: Thomas Kemmer +Author-email: tkemmer@computer.org +License: MIT +Platform: UNKNOWN +Classifier: Development Status :: 5 - Production/Stable +Classifier: Environment :: Other Environment +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.5 +Classifier: Programming Language :: Python :: 3.6 +Classifier: Programming Language :: Python :: 3.7 +Classifier: Programming Language :: Python :: 3.8 +Classifier: Topic :: Software Development :: Libraries :: Python Modules +Requires-Python: ~=3.5 + +cachetools +======================================================================== + +.. image:: http://img.shields.io/pypi/v/cachetools + :target: https://pypi.org/project/cachetools/ + :alt: Latest PyPI version + +.. image:: https://img.shields.io/readthedocs/cachetools + :target: http://cachetools.readthedocs.io/ + :alt: Documentation build status + +.. image:: http://img.shields.io/travis/tkem/cachetools + :target: https://travis-ci.org/tkem/cachetools/ + :alt: Travis CI build status + +.. image:: http://img.shields.io/coveralls/tkem/cachetools + :target: https://coveralls.io/r/tkem/cachetools + :alt: Test coverage + +.. image:: https://img.shields.io/github/license/tkem/cachetools + :target: http://raw.github.com/tkem/cachetools/master/LICENSE + :alt: License + +This module provides various memoizing collections and decorators, +including variants of the Python Standard Library's `@lru_cache`_ +function decorator. + +.. code-block:: python + + from cachetools import cached, LRUCache, TTLCache + + # speed up calculating Fibonacci numbers with dynamic programming + @cached(cache={}) + def fib(n): + return n if n < 2 else fib(n - 1) + fib(n - 2) + + # cache least recently used Python Enhancement Proposals + @cached(cache=LRUCache(maxsize=32)) + def get_pep(num): + url = 'http://www.python.org/dev/peps/pep-%04d/' % num + with urllib.request.urlopen(url) as s: + return s.read() + + # cache weather data for no longer than ten minutes + @cached(cache=TTLCache(maxsize=1024, ttl=600)) + def get_weather(place): + return owm.weather_at_place(place).get_weather() + +For the purpose of this module, a *cache* is a mutable_ mapping_ of a +fixed maximum size. When the cache is full, i.e. by adding another +item the cache would exceed its maximum size, the cache must choose +which item(s) to discard based on a suitable `cache algorithm`_. In +general, a cache's size is the total size of its items, and an item's +size is a property or function of its value, e.g. the result of +``sys.getsizeof(value)``. For the trivial but common case that each +item counts as ``1``, a cache's size is equal to the number of its +items, or ``len(cache)``. + +Multiple cache classes based on different caching algorithms are +implemented, and decorators for easily memoizing function and method +calls are provided, too. + + +Installation +------------------------------------------------------------------------ + +cachetools is available from PyPI_ and can be installed by running:: + + pip install cachetools + + +Project Resources +------------------------------------------------------------------------ + +- `Documentation`_ +- `Issue tracker`_ +- `Source code`_ +- `Change log`_ + + +License +------------------------------------------------------------------------ + +Copyright (c) 2014-2020 Thomas Kemmer. + +Licensed under the `MIT License`_. + + +.. _@lru_cache: http://docs.python.org/3/library/functools.html#functools.lru_cache +.. _mutable: http://docs.python.org/dev/glossary.html#term-mutable +.. _mapping: http://docs.python.org/dev/glossary.html#term-mapping +.. _cache algorithm: http://en.wikipedia.org/wiki/Cache_algorithms + +.. _PyPI: https://pypi.org/project/cachetools/ +.. _Documentation: https://cachetools.readthedocs.io/ +.. _Issue tracker: https://github.com/tkem/cachetools/issues/ +.. _Source code: https://github.com/tkem/cachetools/ +.. _Change log: https://github.com/tkem/cachetools/blob/master/CHANGELOG.rst +.. _MIT License: http://raw.github.com/tkem/cachetools/master/LICENSE + + diff --git a/venv/Lib/site-packages/cachetools-4.1.1.dist-info/RECORD b/venv/Lib/site-packages/cachetools-4.1.1.dist-info/RECORD new file mode 100644 index 000000000..6597cfdf0 --- /dev/null +++ b/venv/Lib/site-packages/cachetools-4.1.1.dist-info/RECORD @@ -0,0 +1,26 @@ +cachetools-4.1.1.dist-info/INSTALLER,sha256=zuuue4knoyJ-UwPPXg8fezS7VCrXJQrAP7zeNuwvFQg,4 +cachetools-4.1.1.dist-info/LICENSE,sha256=WjqbFSk9D0xU0ftRzw9RpxHwz1gvgKDnMwR4ZwwX9ns,1085 +cachetools-4.1.1.dist-info/METADATA,sha256=UCFBVawzngdeCUWD5P33LTAx5AShjKmQ29q3kcc696A,4383 +cachetools-4.1.1.dist-info/RECORD,, +cachetools-4.1.1.dist-info/WHEEL,sha256=g4nMs7d-Xl9-xC9XovUrsDHGXt-FT0E17Yqo92DEfvY,92 +cachetools-4.1.1.dist-info/top_level.txt,sha256=ai2FH78TGwoBcCgVfoqbzk5IQCtnDukdSs4zKuVPvDs,11 +cachetools/__init__.py,sha256=65iD423Ll5taTrDqqSQH2oxmUBHfLP48oWTcOQGGS6M,375 +cachetools/__pycache__/__init__.cpython-36.pyc,, +cachetools/__pycache__/abc.cpython-36.pyc,, +cachetools/__pycache__/cache.cpython-36.pyc,, +cachetools/__pycache__/decorators.cpython-36.pyc,, +cachetools/__pycache__/func.cpython-36.pyc,, +cachetools/__pycache__/keys.cpython-36.pyc,, +cachetools/__pycache__/lfu.cpython-36.pyc,, +cachetools/__pycache__/lru.cpython-36.pyc,, +cachetools/__pycache__/rr.cpython-36.pyc,, +cachetools/__pycache__/ttl.cpython-36.pyc,, +cachetools/abc.py,sha256=KdAOSBVp5jb_MUYdaoiWqbfXsiO9epC-KWVEXXD2TXc,1076 +cachetools/cache.py,sha256=JQPstpjP-TgdpLdQbrGN3gU8F9yk1IQdkFtaK0_CJEo,2272 +cachetools/decorators.py,sha256=Z8XaWDAnlq50Qf3FVrKSPbwr15dDkGRITMcHsVdy2AQ,2829 +cachetools/func.py,sha256=XXIllKSnfzt_Z8NcALeT5gz-tc1uU2V91502Z2QFTYQ,4009 +cachetools/keys.py,sha256=bKwFwU15s-vKWM1lnNdcJWfyQxu7uqIcRRJNg9hUfFg,1466 +cachetools/lfu.py,sha256=xAkYTpx8-7Gg1IOw08UVxncQys8tn7sPg09lr9IvTyQ,1065 +cachetools/lru.py,sha256=0XNTY7VzYEdV9yCdOMwnhkBeQox_N6VscVzNFm-VwRo,1188 +cachetools/rr.py,sha256=uoIxqj9xFYcA2sfKwoOQYd8JE6wzMXPrHLlUsuscILA,974 +cachetools/ttl.py,sha256=VI1Dci_sozLA8m15-l5OfNFfJ1GUhuWm39ISjvxrMg4,5830 diff --git a/venv/Lib/site-packages/cachetools-4.1.1.dist-info/WHEEL b/venv/Lib/site-packages/cachetools-4.1.1.dist-info/WHEEL new file mode 100644 index 000000000..b552003ff --- /dev/null +++ b/venv/Lib/site-packages/cachetools-4.1.1.dist-info/WHEEL @@ -0,0 +1,5 @@ +Wheel-Version: 1.0 +Generator: bdist_wheel (0.34.2) +Root-Is-Purelib: true +Tag: py3-none-any + diff --git a/venv/Lib/site-packages/cachetools-4.1.1.dist-info/top_level.txt b/venv/Lib/site-packages/cachetools-4.1.1.dist-info/top_level.txt new file mode 100644 index 000000000..50d14084a --- /dev/null +++ b/venv/Lib/site-packages/cachetools-4.1.1.dist-info/top_level.txt @@ -0,0 +1 @@ +cachetools diff --git a/venv/Lib/site-packages/cachetools/__init__.py b/venv/Lib/site-packages/cachetools/__init__.py new file mode 100644 index 000000000..51d8f7c82 --- /dev/null +++ b/venv/Lib/site-packages/cachetools/__init__.py @@ -0,0 +1,20 @@ +"""Extensible memoizing collections and decorators.""" + +from .cache import Cache +from .decorators import cached, cachedmethod +from .lfu import LFUCache +from .lru import LRUCache +from .rr import RRCache +from .ttl import TTLCache + +__all__ = ( + 'Cache', + 'LFUCache', + 'LRUCache', + 'RRCache', + 'TTLCache', + 'cached', + 'cachedmethod' +) + +__version__ = '4.1.1' diff --git a/venv/Lib/site-packages/cachetools/__pycache__/__init__.cpython-36.pyc b/venv/Lib/site-packages/cachetools/__pycache__/__init__.cpython-36.pyc new file mode 100644 index 0000000000000000000000000000000000000000..057baf494eb13624d479231959fb69294646226b GIT binary patch literal 676 zcma)(J&zMH5Qg_No6E;tpr+V%iwgwOfDl4LToqA-qp>Vm8+($N*z3sl=16LO2_1iF zTPpqn6}BT?C|PUYebzfO`+DZpcs#hiv(n@vfT5I`+gjVbGfl?=BP6?gfEnr@*=x*qkwy3zS5!EP0E z0sY0@mvfBgU7K{UWeVTv45S>3Q)T(0wndm(0m2pHFAg*{7=bkKk(36@)NF z3F-3SD85A{M?algM%*7I=DcowIW#Y6>A|}#UUXF(8hI#ke`vh_7=VT z`9a^{*0@i2RoixpRRc`(17HSbXVo6J4S!I2hmTO}a*hp1Fcx$R`POaB5p0kPHq literal 0 HcmV?d00001 diff --git a/venv/Lib/site-packages/cachetools/__pycache__/abc.cpython-36.pyc b/venv/Lib/site-packages/cachetools/__pycache__/abc.cpython-36.pyc new file mode 100644 index 0000000000000000000000000000000000000000..187fc2b6a4570998f18de92f4adab6bf1d54e3c2 GIT binary patch literal 1477 zcmZWpPmkj?6t|r;O*5J9?104V!lB}TRB3n6!Uzeppp}5-0NcynqDYY&zqV=9q-(o_ zItmv$UxN?8SMrq;Ux5?vr8DjPaqH(7`^E3~`}sLvA0J0=r`Oqq&)7fgPQz#R2D|wN zjbe(IY{?VO$rq(qdWpx`FHCvLzh=q@Z|fyK`11|~TZ-zuXT#uMe3uQm>&vmRTIO~M zc2+BzdAGK5T*5oKS{2nar@-6hq4Ng28KD7|aK#caVTlL6;!0ezEl)b=x2e$&RICEk zz2-?5!YxaB(3@}-svgcn>R3hU2)&~gQs4D|f{9$0_BOM?B-Ci+*nh-sh`r)SL5$x1 zjn?@F%8Bz9u+be{Yt4Uu<=>@i1KOlxY1gx~u0ZMH5>f?bVe3`8u8QAly+}78_242k zumod44_>7?OfSBD^;Npk^&E1WUc#)%OBl$?7BB4#CU!89ISe%9^|UH%QC9=A!Izg9 zT3x2U730(t7GADozK~NeX)f~_*t#ywmvWq+uQo2uvb?UWEGm;_J)+fe6<43$m*D(v zTz*#%I*C?~FVL~9VRNqdR_N#C%|*i+e0tBUha>+J_+9c9_FFb2;x%Z9$|&ZLpn zYS+U=r8I~}N4TL2e}&D@TGx6gbbu4OOJ=XH4k-vXn}S8E%Pc#_2}6-g#Jn%Aobbl!$Tg5 ztJ4Q?Fl3K{Dr%47;(+38hvE;9#_w5m)}X9&wg~kL%XhL?ej{+*Lvi^CYw?rpejZd? z>IG;`@(le0c>M$?T<21jYj}izRj)q7Wz$E)2tWQJ9tod6;(?*}co3IX&Ck)fQSvH=0w`87cz87vYg#J-g5R{18jh;6HX@mQ`{I zS>_@XrdI2ce7p-E*0Q`=!9p};ZK)9HOf+2%O+x4sG%l#ebSd>yn)!$fo%9``ZHW>v zO;XTPD`O~p5&LmB3IY*F?b>MAbspZwHjjIf*JX)2<83zQG)uMF#<@_#w4jfJ^HqVl Y54T{S%!RLae14$sR9kp4kG+%O|J#gG{{R30 literal 0 HcmV?d00001 diff --git a/venv/Lib/site-packages/cachetools/__pycache__/cache.cpython-36.pyc b/venv/Lib/site-packages/cachetools/__pycache__/cache.cpython-36.pyc new file mode 100644 index 0000000000000000000000000000000000000000..363f0dd7bffbc2cde3db13a0ebe2e3412b15c75e GIT binary patch literal 3324 zcma)9TW=dh6yDj3y>XnxO>b!_?Fw3oDGd}VD5Zs>LJ^{kL|YXUSsHD2#>x7&?#wzg zmh)2QNASioe`%kPc})!iyTZfVlMHiLl%81i@+*d))mgUuy=;bq zPWmY9_v7Angs;=b26qpyz6>I*O(v{OTQFfCSeuS;go_bJixNgplyR(|Rr%z=C-G25 zbOJpzlEC|THEAvwcH0|@KK=zRbG7U=GsYFI8uIU-(e1`SOQjoIVLI4pBt0oqyek_* z>UNs+8-rf_d!pKnJsGOtW<$%a)Tva#jYcH5Z+>;-vqoPfEg7YaUAYrS9T|kZG`^nh z$YvTe!$<~7M#*+BPUEB(=so054q2p9u?}t%4+?Ki#h0%^olcb|RG3Mjd_xiXPQwYL z;txtCs_rO~rAi=~w;Of_a^^EtrmxUT7kU9Uuhnb1>FwfV#MJGX_@i>2e$ro@lUFjEXu+Mn0>JzDi{~UqNrl5h$XR%aZ#*@ z8pf(PAyzRiiId_K#$~x8PKz@K)|hS9z@HUshCd-!#W``_@F#_huwKZ#`-G(7w~q#C zxCKad^TZ3%BtV#Vfl(cVfsVU<7(nKvR@njr2KevHzPEdbRT>6CP7 z1*BBIEu!*44~>)+_wnlYK*+k5)nY09&~jP`_n5wTcuP(9OrBxGOIP%VSJcOdfzk0U z@r4DL)X5i|8;5hQmT+$7c4D2X)5Lm|`C6R?ug-wfS)Lj*xE4k!*;kyui#@smVlmqo z<<1$DZ#k5RlmNz{kHG9z$eJM~!fLh)TAB0m|LZb&ck6i{$; zJ4_)ZP~=dZG?9Qlyieo^Xn_|YJ9%sS8tbOaS|$-^XqfIe1lws}BL|ttS#7#<0G7-+ zwrC;2F>=udqNJCGaZhu84;zY}x>`VRwtT!)GBkx;!dl@2rY_>^8|11>ST_(R?X9_3 zOta=ttvO^Pq#+iRfMg@CGH{#9Eq!f8pe>v~fULs6S!pv%Z!ga2$ljZzl{v=_&VQN{ zwp4i2tQ?Xxy{1uS6U@l0;l-yr)T&;@-9Z=4X()rF8Q>z7H>Pz&mdfDq70@Kf!>M#< zIFUZ7x^F9;3bX8`$4h@x{Vgi`FLNqPyj?6EuLI>oeo-A>do0s|>KT&@^TSD3mK|I? zd+AjjnDVl2F1041;15$J4kwpseb45US;?a@?Yab`Q>NW0>VawnBtsZQ5}^%I9msR~ z9C6fD<}OT^X-XB`Kw4cTt`3s R`AzT}LZA5uq3YBY{{!@Tu3i8D literal 0 HcmV?d00001 diff --git a/venv/Lib/site-packages/cachetools/__pycache__/decorators.cpython-36.pyc b/venv/Lib/site-packages/cachetools/__pycache__/decorators.cpython-36.pyc new file mode 100644 index 0000000000000000000000000000000000000000..663d110be7cfb212bbe201ac0de62333d1d017df GIT binary patch literal 2505 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 Xru$@>at9=4D5a1e{*C>%-|hVa)Drmc literal 0 HcmV?d00001 diff --git a/venv/Lib/site-packages/cachetools/__pycache__/lfu.cpython-36.pyc b/venv/Lib/site-packages/cachetools/__pycache__/lfu.cpython-36.pyc new file mode 100644 index 0000000000000000000000000000000000000000..9456892ecacb2af0f0142c29ea1dee05a75ecd9d GIT binary patch literal 1644 zcmZux%WfMt6eT$`dP{YTz(5}hqCf$wNL;whA_>yMfKhi*LyNZQLl}UW3@Le}c_<`D zi3E95`8WCj{iWGk~m%$B@fnsZK=t=q`>DS&vG#R|7VEeQR&ZGEB#n`ti9yHFN znoBT>45=hTCMnGCN>BPXbm*&KQX5ej$QpPx@ao{zWdpoAcn$EHvISm4wq@sr44aa{ z-o2`EdGXTixIDd7k+J+jt2d>}ZMxtujgtHr0{T2gP&~koUKD-5Vy9(TlI|szv z!TKq5tN`Oq1pi0t#BeWK-Gj;c128+tW&`;itlJSG4k3I?Y3DA|eaN0wR3BC+*du7{ zSfwCSWc6!E;EhzbGKBELb33`}#6aR=@dp1~kYbw3p*>5C2_!YS)lNzXn zjv(D7s>5HN{h+d9j*^xjV_WK+gRuFlV^GK=?j+HF#b;5XdFq~o(Z5duWR*N|@>;e( zGdwX|Wiz`N^y^M+RXZz;g;dS5BClFMqrAS=y3kboL4DTpdqL0d`ECRb hgo9P!vTn07&bYOTThwJ;TNrz$^hCvq_5D%-1Zn^1@6$QEv3=6U$U9r{>z^Wqc$kB&K z(phadH%tD;?sl`k#M@obJfdDcIxoNMc3a;~uJ~U*A^(tT7sTWV zG`$ajF_PC{2k#5|B8-$8B7~vDgx1fr~y$EqNWHTYC;r3v?E#&g`zDw zS7fv!x}pd7mSCWvZ^NUL=kCqR2S+l|COVO+EKRLBxk`>{;An;ClJO~s%VnfceGBcdpc3S1R zOmSUp+dnBGl@#A(sj+>&5y*Lk{|`LtYnhL2vq;|PY$@%|L>e4a|Dk|>N8W#;(3|?q%_%mb1KIs8YiiYluWA$hzG@yUckczq?YILQT964nUVKrNqUw{q>ddt zQ&qWskgNG{won0R+<~SM8lgS9+}&()xIwaoi#bTk!F?YFD~4z<*@d?vQyfuBR^A#c zwY%4N&1WJpa^Nd`nf1=(V$^kNI1mGkg$>S=d@dcdb=SqrHs2(0j(_L|bcD9xw|wuK z(s~unQ@0Vw!8iK8Fo z;#;LEWxZK7yH3`6g`V8x*@PtIj5Vau(}Xd)2Uh9OK3n#;MOde$3{&93`Y*@5zVX7XCd`j%kKp}zvqW7HwV_kX&bm>Vf_Mp=C;Lbc(_*i7>m~x Ic*r{5fB6Kb*#H0l literal 0 HcmV?d00001 diff --git a/venv/Lib/site-packages/cachetools/__pycache__/rr.cpython-36.pyc b/venv/Lib/site-packages/cachetools/__pycache__/rr.cpython-36.pyc new file mode 100644 index 0000000000000000000000000000000000000000..078112adf63e11d1f12962c6e91c23038d16b5be GIT binary patch literal 1349 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 Nm|!*R)wR{{{tvhUZM^^h literal 0 HcmV?d00001 diff --git a/venv/Lib/site-packages/cachetools/abc.py b/venv/Lib/site-packages/cachetools/abc.py new file mode 100644 index 000000000..b61e49bba --- /dev/null +++ b/venv/Lib/site-packages/cachetools/abc.py @@ -0,0 +1,46 @@ +from abc import abstractmethod +from collections.abc import MutableMapping + + +class DefaultMapping(MutableMapping): + + __slots__ = () + + @abstractmethod + def __contains__(self, key): # pragma: nocover + return False + + @abstractmethod + def __getitem__(self, key): # pragma: nocover + if hasattr(self.__class__, '__missing__'): + return self.__class__.__missing__(self, key) + else: + raise KeyError(key) + + def get(self, key, default=None): + if key in self: + return self[key] + else: + return default + + __marker = object() + + def pop(self, key, default=__marker): + if key in self: + value = self[key] + del self[key] + elif default is self.__marker: + raise KeyError(key) + else: + value = default + return value + + def setdefault(self, key, default=None): + if key in self: + value = self[key] + else: + self[key] = value = default + return value + + +DefaultMapping.register(dict) diff --git a/venv/Lib/site-packages/cachetools/cache.py b/venv/Lib/site-packages/cachetools/cache.py new file mode 100644 index 000000000..4354ca69b --- /dev/null +++ b/venv/Lib/site-packages/cachetools/cache.py @@ -0,0 +1,89 @@ +from .abc import DefaultMapping + + +class _DefaultSize(object): + def __getitem__(self, _): + return 1 + + def __setitem__(self, _, value): + assert value == 1 + + def pop(self, _): + return 1 + + +class Cache(DefaultMapping): + """Mutable mapping to serve as a simple cache or cache base class.""" + + __size = _DefaultSize() + + def __init__(self, maxsize, getsizeof=None): + if getsizeof: + self.getsizeof = getsizeof + if self.getsizeof is not Cache.getsizeof: + self.__size = dict() + self.__data = dict() + self.__currsize = 0 + self.__maxsize = maxsize + + def __repr__(self): + return '%s(%r, maxsize=%r, currsize=%r)' % ( + self.__class__.__name__, + list(self.__data.items()), + self.__maxsize, + self.__currsize, + ) + + def __getitem__(self, key): + try: + return self.__data[key] + except KeyError: + return self.__missing__(key) + + def __setitem__(self, key, value): + maxsize = self.__maxsize + size = self.getsizeof(value) + if size > maxsize: + raise ValueError('value too large') + if key not in self.__data or self.__size[key] < size: + while self.__currsize + size > maxsize: + self.popitem() + if key in self.__data: + diffsize = size - self.__size[key] + else: + diffsize = size + self.__data[key] = value + self.__size[key] = size + self.__currsize += diffsize + + def __delitem__(self, key): + size = self.__size.pop(key) + del self.__data[key] + self.__currsize -= size + + def __contains__(self, key): + return key in self.__data + + def __missing__(self, key): + raise KeyError(key) + + def __iter__(self): + return iter(self.__data) + + def __len__(self): + return len(self.__data) + + @property + def maxsize(self): + """The maximum size of the cache.""" + return self.__maxsize + + @property + def currsize(self): + """The current size of the cache.""" + return self.__currsize + + @staticmethod + def getsizeof(value): + """Return the size of a cache element's value.""" + return 1 diff --git a/venv/Lib/site-packages/cachetools/decorators.py b/venv/Lib/site-packages/cachetools/decorators.py new file mode 100644 index 000000000..cbea9fcb3 --- /dev/null +++ b/venv/Lib/site-packages/cachetools/decorators.py @@ -0,0 +1,88 @@ +import functools + +from .keys import hashkey + + +def cached(cache, key=hashkey, lock=None): + """Decorator to wrap a function with a memoizing callable that saves + results in a cache. + + """ + def decorator(func): + if cache is None: + def wrapper(*args, **kwargs): + return func(*args, **kwargs) + elif lock is None: + def wrapper(*args, **kwargs): + k = key(*args, **kwargs) + try: + return cache[k] + except KeyError: + pass # key not found + v = func(*args, **kwargs) + try: + cache[k] = v + except ValueError: + pass # value too large + return v + else: + def wrapper(*args, **kwargs): + k = key(*args, **kwargs) + try: + with lock: + return cache[k] + except KeyError: + pass # key not found + v = func(*args, **kwargs) + try: + with lock: + cache[k] = v + except ValueError: + pass # value too large + return v + return functools.update_wrapper(wrapper, func) + return decorator + + +def cachedmethod(cache, key=hashkey, lock=None): + """Decorator to wrap a class or instance method with a memoizing + callable that saves results in a cache. + + """ + def decorator(method): + if lock is None: + def wrapper(self, *args, **kwargs): + c = cache(self) + if c is None: + return method(self, *args, **kwargs) + k = key(*args, **kwargs) + try: + return c[k] + except KeyError: + pass # key not found + v = method(self, *args, **kwargs) + try: + c[k] = v + except ValueError: + pass # value too large + return v + else: + def wrapper(self, *args, **kwargs): + c = cache(self) + if c is None: + return method(self, *args, **kwargs) + k = key(*args, **kwargs) + try: + with lock(self): + return c[k] + except KeyError: + pass # key not found + v = method(self, *args, **kwargs) + try: + with lock(self): + c[k] = v + except ValueError: + pass # value too large + return v + return functools.update_wrapper(wrapper, method) + return decorator diff --git a/venv/Lib/site-packages/cachetools/func.py b/venv/Lib/site-packages/cachetools/func.py new file mode 100644 index 000000000..5baf6de7e --- /dev/null +++ b/venv/Lib/site-packages/cachetools/func.py @@ -0,0 +1,147 @@ +"""`functools.lru_cache` compatible memoizing function decorators.""" + +import collections +import functools +import math +import random +import time + +try: + from threading import RLock +except ImportError: # pragma: no cover + from dummy_threading import RLock + +from . import keys +from .lfu import LFUCache +from .lru import LRUCache +from .rr import RRCache +from .ttl import TTLCache + +__all__ = ('lfu_cache', 'lru_cache', 'rr_cache', 'ttl_cache') + + +_CacheInfo = collections.namedtuple('CacheInfo', [ + 'hits', 'misses', 'maxsize', 'currsize' +]) + + +class _UnboundCache(dict): + + @property + def maxsize(self): + return None + + @property + def currsize(self): + return len(self) + + +class _UnboundTTLCache(TTLCache): + def __init__(self, ttl, timer): + TTLCache.__init__(self, math.inf, ttl, timer) + + @property + def maxsize(self): + return None + + +def _cache(cache, typed): + maxsize = cache.maxsize + + def decorator(func): + key = keys.typedkey if typed else keys.hashkey + lock = RLock() + stats = [0, 0] + + def wrapper(*args, **kwargs): + k = key(*args, **kwargs) + with lock: + try: + v = cache[k] + stats[0] += 1 + return v + except KeyError: + stats[1] += 1 + v = func(*args, **kwargs) + try: + with lock: + cache[k] = v + except ValueError: + pass # value too large + return v + + def cache_info(): + with lock: + hits, misses = stats + maxsize = cache.maxsize + currsize = cache.currsize + return _CacheInfo(hits, misses, maxsize, currsize) + + def cache_clear(): + with lock: + try: + cache.clear() + finally: + stats[:] = [0, 0] + + wrapper.cache_info = cache_info + wrapper.cache_clear = cache_clear + wrapper.cache_parameters = lambda: {'maxsize': maxsize, 'typed': typed} + functools.update_wrapper(wrapper, func) + return wrapper + return decorator + + +def lfu_cache(maxsize=128, typed=False): + """Decorator to wrap a function with a memoizing callable that saves + up to `maxsize` results based on a Least Frequently Used (LFU) + algorithm. + + """ + if maxsize is None: + return _cache(_UnboundCache(), typed) + elif callable(maxsize): + return _cache(LFUCache(128), typed)(maxsize) + else: + return _cache(LFUCache(maxsize), typed) + + +def lru_cache(maxsize=128, typed=False): + """Decorator to wrap a function with a memoizing callable that saves + up to `maxsize` results based on a Least Recently Used (LRU) + algorithm. + + """ + if maxsize is None: + return _cache(_UnboundCache(), typed) + elif callable(maxsize): + return _cache(LRUCache(128), typed)(maxsize) + else: + return _cache(LRUCache(maxsize), typed) + + +def rr_cache(maxsize=128, choice=random.choice, typed=False): + """Decorator to wrap a function with a memoizing callable that saves + up to `maxsize` results based on a Random Replacement (RR) + algorithm. + + """ + if maxsize is None: + return _cache(_UnboundCache(), typed) + elif callable(maxsize): + return _cache(RRCache(128, choice), typed)(maxsize) + else: + return _cache(RRCache(maxsize, choice), typed) + + +def ttl_cache(maxsize=128, ttl=600, timer=time.monotonic, typed=False): + """Decorator to wrap a function with a memoizing callable that saves + up to `maxsize` results based on a Least Recently Used (LRU) + algorithm with a per-item time-to-live (TTL) value. + """ + if maxsize is None: + return _cache(_UnboundTTLCache(ttl, timer), typed) + elif callable(maxsize): + return _cache(TTLCache(128, ttl, timer), typed)(maxsize) + else: + return _cache(TTLCache(maxsize, ttl, timer), typed) diff --git a/venv/Lib/site-packages/cachetools/keys.py b/venv/Lib/site-packages/cachetools/keys.py new file mode 100644 index 000000000..355d742df --- /dev/null +++ b/venv/Lib/site-packages/cachetools/keys.py @@ -0,0 +1,52 @@ +"""Key functions for memoizing decorators.""" + +__all__ = ('hashkey', 'typedkey') + + +class _HashedTuple(tuple): + """A tuple that ensures that hash() will be called no more than once + per element, since cache decorators will hash the key multiple + times on a cache miss. See also _HashedSeq in the standard + library functools implementation. + + """ + + __hashvalue = None + + def __hash__(self, hash=tuple.__hash__): + hashvalue = self.__hashvalue + if hashvalue is None: + self.__hashvalue = hashvalue = hash(self) + return hashvalue + + def __add__(self, other, add=tuple.__add__): + return _HashedTuple(add(self, other)) + + def __radd__(self, other, add=tuple.__add__): + return _HashedTuple(add(other, self)) + + def __getstate__(self): + return {} + + +# used for separating keyword arguments; we do not use an object +# instance here so identity is preserved when pickling/unpickling +_kwmark = (_HashedTuple,) + + +def hashkey(*args, **kwargs): + """Return a cache key for the specified hashable arguments.""" + + if kwargs: + return _HashedTuple(args + sum(sorted(kwargs.items()), _kwmark)) + else: + return _HashedTuple(args) + + +def typedkey(*args, **kwargs): + """Return a typed cache key for the specified hashable arguments.""" + + key = hashkey(*args, **kwargs) + key += tuple(type(v) for v in args) + key += tuple(type(v) for _, v in sorted(kwargs.items())) + return key diff --git a/venv/Lib/site-packages/cachetools/lfu.py b/venv/Lib/site-packages/cachetools/lfu.py new file mode 100644 index 000000000..adb45ee27 --- /dev/null +++ b/venv/Lib/site-packages/cachetools/lfu.py @@ -0,0 +1,34 @@ +import collections + +from .cache import Cache + + +class LFUCache(Cache): + """Least Frequently Used (LFU) cache implementation.""" + + def __init__(self, maxsize, getsizeof=None): + Cache.__init__(self, maxsize, getsizeof) + self.__counter = collections.Counter() + + def __getitem__(self, key, cache_getitem=Cache.__getitem__): + value = cache_getitem(self, key) + self.__counter[key] -= 1 + return value + + def __setitem__(self, key, value, cache_setitem=Cache.__setitem__): + cache_setitem(self, key, value) + self.__counter[key] -= 1 + + def __delitem__(self, key, cache_delitem=Cache.__delitem__): + cache_delitem(self, key) + del self.__counter[key] + + def popitem(self): + """Remove and return the `(key, value)` pair least frequently used.""" + try: + (key, _), = self.__counter.most_common(1) + except ValueError: + msg = '%s is empty' % self.__class__.__name__ + raise KeyError(msg) from None + else: + return (key, self.pop(key)) diff --git a/venv/Lib/site-packages/cachetools/lru.py b/venv/Lib/site-packages/cachetools/lru.py new file mode 100644 index 000000000..7634f9cf4 --- /dev/null +++ b/venv/Lib/site-packages/cachetools/lru.py @@ -0,0 +1,40 @@ +import collections + +from .cache import Cache + + +class LRUCache(Cache): + """Least Recently Used (LRU) cache implementation.""" + + def __init__(self, maxsize, getsizeof=None): + Cache.__init__(self, maxsize, getsizeof) + self.__order = collections.OrderedDict() + + def __getitem__(self, key, cache_getitem=Cache.__getitem__): + value = cache_getitem(self, key) + self.__update(key) + return value + + def __setitem__(self, key, value, cache_setitem=Cache.__setitem__): + cache_setitem(self, key, value) + self.__update(key) + + def __delitem__(self, key, cache_delitem=Cache.__delitem__): + cache_delitem(self, key) + del self.__order[key] + + def popitem(self): + """Remove and return the `(key, value)` pair least recently used.""" + try: + key = next(iter(self.__order)) + except StopIteration: + msg = '%s is empty' % self.__class__.__name__ + raise KeyError(msg) from None + else: + return (key, self.pop(key)) + + def __update(self, key): + try: + self.__order.move_to_end(key) + except KeyError: + self.__order[key] = None diff --git a/venv/Lib/site-packages/cachetools/rr.py b/venv/Lib/site-packages/cachetools/rr.py new file mode 100644 index 000000000..30f38226d --- /dev/null +++ b/venv/Lib/site-packages/cachetools/rr.py @@ -0,0 +1,35 @@ +import random + +from .cache import Cache + + +# random.choice cannot be pickled in Python 2.7 +def _choice(seq): + return random.choice(seq) + + +class RRCache(Cache): + """Random Replacement (RR) cache implementation.""" + + def __init__(self, maxsize, choice=random.choice, getsizeof=None): + Cache.__init__(self, maxsize, getsizeof) + # TODO: use None as default, assing to self.choice directly? + if choice is random.choice: + self.__choice = _choice + else: + self.__choice = choice + + @property + def choice(self): + """The `choice` function used by the cache.""" + return self.__choice + + def popitem(self): + """Remove and return a random `(key, value)` pair.""" + try: + key = self.__choice(list(self)) + except IndexError: + msg = '%s is empty' % self.__class__.__name__ + raise KeyError(msg) from None + else: + return (key, self.pop(key)) diff --git a/venv/Lib/site-packages/cachetools/ttl.py b/venv/Lib/site-packages/cachetools/ttl.py new file mode 100644 index 000000000..7822e8bea --- /dev/null +++ b/venv/Lib/site-packages/cachetools/ttl.py @@ -0,0 +1,209 @@ +import collections +import time + +from .cache import Cache + + +class _Link(object): + + __slots__ = ('key', 'expire', 'next', 'prev') + + def __init__(self, key=None, expire=None): + self.key = key + self.expire = expire + + def __reduce__(self): + return _Link, (self.key, self.expire) + + def unlink(self): + next = self.next + prev = self.prev + prev.next = next + next.prev = prev + + +class _Timer(object): + + def __init__(self, timer): + self.__timer = timer + self.__nesting = 0 + + def __call__(self): + if self.__nesting == 0: + return self.__timer() + else: + return self.__time + + def __enter__(self): + if self.__nesting == 0: + self.__time = time = self.__timer() + else: + time = self.__time + self.__nesting += 1 + return time + + def __exit__(self, *exc): + self.__nesting -= 1 + + def __reduce__(self): + return _Timer, (self.__timer,) + + def __getattr__(self, name): + return getattr(self.__timer, name) + + +class TTLCache(Cache): + """LRU Cache implementation with per-item time-to-live (TTL) value.""" + + def __init__(self, maxsize, ttl, timer=time.monotonic, getsizeof=None): + Cache.__init__(self, maxsize, getsizeof) + self.__root = root = _Link() + root.prev = root.next = root + self.__links = collections.OrderedDict() + self.__timer = _Timer(timer) + self.__ttl = ttl + + def __contains__(self, key): + try: + link = self.__links[key] # no reordering + except KeyError: + return False + else: + return not (link.expire < self.__timer()) + + def __getitem__(self, key, cache_getitem=Cache.__getitem__): + try: + link = self.__getlink(key) + except KeyError: + expired = False + else: + expired = link.expire < self.__timer() + if expired: + return self.__missing__(key) + else: + return cache_getitem(self, key) + + def __setitem__(self, key, value, cache_setitem=Cache.__setitem__): + with self.__timer as time: + self.expire(time) + cache_setitem(self, key, value) + try: + link = self.__getlink(key) + except KeyError: + self.__links[key] = link = _Link(key) + else: + link.unlink() + link.expire = time + self.__ttl + link.next = root = self.__root + link.prev = prev = root.prev + prev.next = root.prev = link + + def __delitem__(self, key, cache_delitem=Cache.__delitem__): + cache_delitem(self, key) + link = self.__links.pop(key) + link.unlink() + if link.expire < self.__timer(): + raise KeyError(key) + + def __iter__(self): + root = self.__root + curr = root.next + while curr is not root: + # "freeze" time for iterator access + with self.__timer as time: + if not (curr.expire < time): + yield curr.key + curr = curr.next + + def __len__(self): + root = self.__root + curr = root.next + time = self.__timer() + count = len(self.__links) + while curr is not root and curr.expire < time: + count -= 1 + curr = curr.next + return count + + def __setstate__(self, state): + self.__dict__.update(state) + root = self.__root + root.prev = root.next = root + for link in sorted(self.__links.values(), key=lambda obj: obj.expire): + link.next = root + link.prev = prev = root.prev + prev.next = root.prev = link + self.expire(self.__timer()) + + def __repr__(self, cache_repr=Cache.__repr__): + with self.__timer as time: + self.expire(time) + return cache_repr(self) + + @property + def currsize(self): + with self.__timer as time: + self.expire(time) + return super(TTLCache, self).currsize + + @property + def timer(self): + """The timer function used by the cache.""" + return self.__timer + + @property + def ttl(self): + """The time-to-live value of the cache's items.""" + return self.__ttl + + def expire(self, time=None): + """Remove expired items from the cache.""" + if time is None: + time = self.__timer() + root = self.__root + curr = root.next + links = self.__links + cache_delitem = Cache.__delitem__ + while curr is not root and curr.expire < time: + cache_delitem(self, curr.key) + del links[curr.key] + next = curr.next + curr.unlink() + curr = next + + def clear(self): + with self.__timer as time: + self.expire(time) + Cache.clear(self) + + def get(self, *args, **kwargs): + with self.__timer: + return Cache.get(self, *args, **kwargs) + + def pop(self, *args, **kwargs): + with self.__timer: + return Cache.pop(self, *args, **kwargs) + + def setdefault(self, *args, **kwargs): + with self.__timer: + return Cache.setdefault(self, *args, **kwargs) + + def popitem(self): + """Remove and return the `(key, value)` pair least recently used that + has not already expired. + + """ + with self.__timer as time: + self.expire(time) + try: + key = next(iter(self.__links)) + except StopIteration: + msg = '%s is empty' % self.__class__.__name__ + raise KeyError(msg) from None + else: + return (key, self.pop(key)) + + def __getlink(self, key): + value = self.__links[key] + self.__links.move_to_end(key) + return value diff --git a/venv/Lib/site-packages/certifi-2020.6.20.dist-info/INSTALLER b/venv/Lib/site-packages/certifi-2020.6.20.dist-info/INSTALLER new file mode 100644 index 000000000..a1b589e38 --- /dev/null +++ b/venv/Lib/site-packages/certifi-2020.6.20.dist-info/INSTALLER @@ -0,0 +1 @@ +pip diff --git a/venv/Lib/site-packages/certifi-2020.6.20.dist-info/LICENSE b/venv/Lib/site-packages/certifi-2020.6.20.dist-info/LICENSE new file mode 100644 index 000000000..802b53ff1 --- /dev/null +++ b/venv/Lib/site-packages/certifi-2020.6.20.dist-info/LICENSE @@ -0,0 +1,21 @@ +This packge contains a modified version of ca-bundle.crt: + +ca-bundle.crt -- Bundle of CA Root Certificates + +Certificate data from Mozilla as of: Thu Nov 3 19:04:19 2011# +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: +http://mxr.mozilla.org/mozilla/source/security/nss/lib/ckfw/builtins/certdata.txt?raw=1# +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/venv/Lib/site-packages/certifi-2020.6.20.dist-info/METADATA b/venv/Lib/site-packages/certifi-2020.6.20.dist-info/METADATA new file mode 100644 index 000000000..0bcbcce26 --- /dev/null +++ b/venv/Lib/site-packages/certifi-2020.6.20.dist-info/METADATA @@ -0,0 +1,82 @@ +Metadata-Version: 2.1 +Name: certifi +Version: 2020.6.20 +Summary: Python package for providing Mozilla's CA Bundle. +Home-page: https://certifiio.readthedocs.io/en/latest/ +Author: Kenneth Reitz +Author-email: me@kennethreitz.com +License: MPL-2.0 +Project-URL: Documentation, https://certifiio.readthedocs.io/en/latest/ +Project-URL: Source, https://github.com/certifi/python-certifi +Platform: UNKNOWN +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.3 +Classifier: Programming Language :: Python :: 3.4 +Classifier: Programming Language :: Python :: 3.5 +Classifier: Programming Language :: Python :: 3.6 +Classifier: Programming Language :: Python :: 3.7 +Classifier: Programming Language :: Python :: 3.8 + +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! + +1024-bit Root Certificates +~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Browsers and certificate authorities have concluded that 1024-bit keys are +unacceptably weak for certificates, particularly root certificates. For this +reason, Mozilla has removed any weak (i.e. 1024-bit key) certificate from its +bundle, replacing it with an equivalent strong (i.e. 2048-bit or greater key) +certificate from the same CA. Because Mozilla removed these certificates from +its bundle, ``certifi`` removed them as well. + +In previous versions, ``certifi`` provided the ``certifi.old_where()`` function +to intentionally re-add the 1024-bit roots back into your bundle. This was not +recommended in production and therefore was removed at the end of 2018. + +.. _`Certifi`: https://certifiio.readthedocs.io/en/latest/ +.. _`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/venv/Lib/site-packages/certifi-2020.6.20.dist-info/RECORD b/venv/Lib/site-packages/certifi-2020.6.20.dist-info/RECORD new file mode 100644 index 000000000..b3b52478f --- /dev/null +++ b/venv/Lib/site-packages/certifi-2020.6.20.dist-info/RECORD @@ -0,0 +1,13 @@ +certifi-2020.6.20.dist-info/INSTALLER,sha256=zuuue4knoyJ-UwPPXg8fezS7VCrXJQrAP7zeNuwvFQg,4 +certifi-2020.6.20.dist-info/LICENSE,sha256=anCkv2sBABbVmmS4rkrY3H9e8W8ftFPMLs13HFo0ETE,1048 +certifi-2020.6.20.dist-info/METADATA,sha256=_0lH4pmUKzXqjJAq6fIlE4JB2g1CFLPpjpwwOsqNqwk,2944 +certifi-2020.6.20.dist-info/RECORD,, +certifi-2020.6.20.dist-info/WHEEL,sha256=kGT74LWyRUZrL4VgLh6_g12IeVl_9u9ZVhadrgXZUEY,110 +certifi-2020.6.20.dist-info/top_level.txt,sha256=KMu4vUCfsjLrkPbSNdgdekS-pVJzBAJFO__nI8NF6-U,8 +certifi/__init__.py,sha256=u1E_DrSGj_nnEkK5VglvEqP8D80KpghLVWL0A_pq41A,62 +certifi/__main__.py,sha256=xBBoj905TUWBLRGANOcf7oi6e-3dMP4cEoG9OyMs11g,243 +certifi/__pycache__/__init__.cpython-36.pyc,, +certifi/__pycache__/__main__.cpython-36.pyc,, +certifi/__pycache__/core.cpython-36.pyc,, +certifi/cacert.pem,sha256=GhT24f0R7_9y4YY_hkXwkO7BthZhRGDCEMO348E9S14,282394 +certifi/core.py,sha256=V0uyxKOYdz6ulDSusclrLmjbPgOXsD0BnEf0SQ7OnoE,2303 diff --git a/venv/Lib/site-packages/certifi-2020.6.20.dist-info/WHEEL b/venv/Lib/site-packages/certifi-2020.6.20.dist-info/WHEEL new file mode 100644 index 000000000..ef99c6cf3 --- /dev/null +++ b/venv/Lib/site-packages/certifi-2020.6.20.dist-info/WHEEL @@ -0,0 +1,6 @@ +Wheel-Version: 1.0 +Generator: bdist_wheel (0.34.2) +Root-Is-Purelib: true +Tag: py2-none-any +Tag: py3-none-any + diff --git a/venv/Lib/site-packages/certifi-2020.6.20.dist-info/top_level.txt b/venv/Lib/site-packages/certifi-2020.6.20.dist-info/top_level.txt new file mode 100644 index 000000000..963eac530 --- /dev/null +++ b/venv/Lib/site-packages/certifi-2020.6.20.dist-info/top_level.txt @@ -0,0 +1 @@ +certifi diff --git a/venv/Lib/site-packages/certifi/__init__.py b/venv/Lib/site-packages/certifi/__init__.py new file mode 100644 index 000000000..5d52a62e7 --- /dev/null +++ b/venv/Lib/site-packages/certifi/__init__.py @@ -0,0 +1,3 @@ +from .core import contents, where + +__version__ = "2020.06.20" diff --git a/venv/Lib/site-packages/certifi/__main__.py b/venv/Lib/site-packages/certifi/__main__.py new file mode 100644 index 000000000..8945b5da8 --- /dev/null +++ b/venv/Lib/site-packages/certifi/__main__.py @@ -0,0 +1,12 @@ +import argparse + +from certifi import contents, where + +parser = argparse.ArgumentParser() +parser.add_argument("-c", "--contents", action="store_true") +args = parser.parse_args() + +if args.contents: + print(contents()) +else: + print(where()) diff --git a/venv/Lib/site-packages/certifi/__pycache__/__init__.cpython-36.pyc b/venv/Lib/site-packages/certifi/__pycache__/__init__.cpython-36.pyc new file mode 100644 index 0000000000000000000000000000000000000000..1814529c57e490f9024167f8c5c8548957bb0d8d GIT binary patch literal 326 zcmX|6Jxjzu6x@6$$H{@EW!e-MbMX)qIc)62#x5)@x!sp!O|l!_ZgRxh|6%Q4N^9j` zuyWJ*V1@@XZys~A*{q+c4|X7gd^`M)@3uz=bLB`7;kBgmafus3?u@TTntr+_vc)kb={eJR$ zIv6L>V_}DyY6Sx22vmS+tnTTc}K4Y;Kv)RMOl z70Sx3t)aA0S#XFDxUQ76?s;S;cicIv8tJnA_<-l3pHQ$gq zzr;0D=Wd-!DL@F^Tr6a=Tz5 zm)3YN-i7pG4G52{l8;4Iy~~C37NPbyz=DQMNUyC~6d@Pb^a34(xdiljrIE!U6@Un_Na}2A$T%IjqvYTUhpAiIDRkuu;$i) zLcIg7z-_$k`C#;e#SPzs!1A0s=)ifv@{CJp&cB|0<~`aLq~|+WYq^C|7_Te8hLtZ@ zLPCikZDaJfSn2k$xr7hR;8W;vzpfK9hNK#<|f+i`6`XPlO z<<(JllC83FzADBAC5nk1)Sk*!aY4rA6JkHliS92dcuYxp)KK+Q zc|pg8>UU>;Czd@Ws!{{IQ7QHt8SOsTmDCW-#O$xnsz2XIRUOZauUAfOmbwNVHeh`n zX1X@k2eDj=V4SU&PIiWy)Ka8K`)j?b9n>cHS~?rF4Sv6RjRldT5sUd+gjwu^7K#V` zN04dbN-{JKQ2lLO0y3~D;j=&!3tJ{w$O4<^Te77BcM*Md6nmHGpI2|wkBT_t2M-Sp zA06{w9v=S~%c%~$O+2{r9~?i8nGX>AoFhaHoc~Rr!o2PB?<@IDv+){yb0WfK);Oyb zm{Z*-?H9qVn~gQk94wkMEuenTc)ijd!_@a1sizOVzW+tD1~=C-G^cuIB$6m>Fn5u` zNvJ1C6_P65)S8w@e}K_ierw>VknOtF{QU)783Je#vE^7$)yL~uSX znWZqIvD8*NW$bj6#oVp6?Q-O)f1^D1csC%iXz7I;7(eDp1o4(iNK*|7&OKD0@DTbD zZ9Ou5B%!G3NQ?3o8iCB|96P?HFFHFvN6gzav+U@dW;5r3;hor12CP`=SaLowOU-%A z=gwFxgihW?l*sxD^%BvLy#a$xQlPeA_Rzpl#1T}P%3o#(pg4k5#dQ?0i;fX(3BXq> ztpD;9Qe zyGztdRs!5LXYf;d`_. + +Contact +------- + +`Mailing list `_ + + diff --git a/venv/Lib/site-packages/cffi-1.14.3.dist-info/RECORD b/venv/Lib/site-packages/cffi-1.14.3.dist-info/RECORD new file mode 100644 index 000000000..9607bddfa --- /dev/null +++ b/venv/Lib/site-packages/cffi-1.14.3.dist-info/RECORD @@ -0,0 +1,44 @@ +_cffi_backend.cp36-win32.pyd,sha256=G6qu3i9zJLMfZ_PT7JiYLHWlQ4oeg6Xdtt0U2fz452g,146432 +cffi-1.14.3.dist-info/INSTALLER,sha256=zuuue4knoyJ-UwPPXg8fezS7VCrXJQrAP7zeNuwvFQg,4 +cffi-1.14.3.dist-info/LICENSE,sha256=esEZUOct9bRcUXFqeyLnuzSzJNZ_Bl4pOBUt1HLEgV8,1320 +cffi-1.14.3.dist-info/METADATA,sha256=SOxoTo-W2jbz8qj7XHL2Ry3Shfpbeg6IHx7crTt4NRs,1191 +cffi-1.14.3.dist-info/RECORD,, +cffi-1.14.3.dist-info/WHEEL,sha256=AV2Nvbg-pC-zIZdxGMBky9Ya05hYOPClxAaFNPEQVgE,102 +cffi-1.14.3.dist-info/entry_points.txt,sha256=Q9f5C9IpjYxo0d2PK9eUcnkgxHc9pHWwjEMaANPKNCI,76 +cffi-1.14.3.dist-info/top_level.txt,sha256=rE7WR3rZfNKxWI9-jn6hsHCAl7MDkB-FmuQbxWjFehQ,19 +cffi/__init__.py,sha256=r5h8errFupyJOsTuicf5dYchgmL9Hwsy-GzAH5AAMOw,527 +cffi/__pycache__/__init__.cpython-36.pyc,, +cffi/__pycache__/api.cpython-36.pyc,, +cffi/__pycache__/backend_ctypes.cpython-36.pyc,, +cffi/__pycache__/cffi_opcode.cpython-36.pyc,, +cffi/__pycache__/commontypes.cpython-36.pyc,, +cffi/__pycache__/cparser.cpython-36.pyc,, +cffi/__pycache__/error.cpython-36.pyc,, +cffi/__pycache__/ffiplatform.cpython-36.pyc,, +cffi/__pycache__/lock.cpython-36.pyc,, +cffi/__pycache__/model.cpython-36.pyc,, +cffi/__pycache__/pkgconfig.cpython-36.pyc,, +cffi/__pycache__/recompiler.cpython-36.pyc,, +cffi/__pycache__/setuptools_ext.cpython-36.pyc,, +cffi/__pycache__/vengine_cpy.cpython-36.pyc,, +cffi/__pycache__/vengine_gen.cpython-36.pyc,, +cffi/__pycache__/verifier.cpython-36.pyc,, +cffi/_cffi_errors.h,sha256=INd0GxZQna8TTRYNOOr9_iFy0FZa84I_KH1qlmPgulQ,4003 +cffi/_cffi_include.h,sha256=H7cgdZR-POwmUFrIup4jOGzmje8YoQHhN99gVFg7w08,15185 +cffi/_embedding.h,sha256=4vlPtC1Zof0KjwnohsyLcWSDv-Kxa_bLmkobilrHbx0,18108 +cffi/api.py,sha256=Xs_dAN5x1ehfnn_F9ZTdA3Ce0bmPrqeIOkO4Ya1tfbQ,43029 +cffi/backend_ctypes.py,sha256=BHN3q2giL2_Y8wMDST2CIcc_qoMrs65qV9Ob5JvxBZ4,43575 +cffi/cffi_opcode.py,sha256=57P2NHLZkuTWueZybu5iosWljb6ocQmUXzGrCplrnyE,5911 +cffi/commontypes.py,sha256=mEZD4g0qtadnv6O6CEXvMQaJ1K6SRbG5S1h4YvVZHOU,2769 +cffi/cparser.py,sha256=CwVk2V3ATYlCoywG6zN35w6UQ7zj2EWX68KjoJp2Mzk,45237 +cffi/error.py,sha256=Bka7fSV22aIglTQDPIDfpnxTc1aWZLMQdQOJY-h_PUA,908 +cffi/ffiplatform.py,sha256=qioydJeC63dEvrQ3ht5_BPmSs7wzzzuWnZAJtfhic7I,4173 +cffi/lock.py,sha256=vnbsel7392Ib8gGBifIfAfc7MHteSwd3nP725pvc25Q,777 +cffi/model.py,sha256=HRD0WEYHF2Vr6RjS-4wyncElrZxU2256zY0fbMkSKec,22385 +cffi/parse_c_type.h,sha256=fKYNqWNX5f9kZNNhbXcRLTOlpRGRhh8eCLyHmTXIZnQ,6157 +cffi/pkgconfig.py,sha256=9zDcDf0XKIJaxFHLg7e-W8-Xb8Yq5hdhqH7kLg-ugRo,4495 +cffi/recompiler.py,sha256=_Hti-7dC_XumeGfj8tnodXwg1KplG_Iv-7P_5Xl41pA,65632 +cffi/setuptools_ext.py,sha256=8y14TOlRAkgdczmwtPOahyFXJHNyIqhLjUHMYQmjOHs,9150 +cffi/vengine_cpy.py,sha256=ukugKCIsURxJzHxlxS265tGjQfPTFDbThwsqBrwKh-A,44396 +cffi/vengine_gen.py,sha256=mykUhLFJIcV6AyQ5cMJ3n_7dbqw0a9WEjXW0E-WfgiI,27359 +cffi/verifier.py,sha256=La8rdbEkvdvbqAHDzTk5lsNUvdkqB_GcFnO7wXI6Mgk,11513 diff --git a/venv/Lib/site-packages/cffi-1.14.3.dist-info/WHEEL b/venv/Lib/site-packages/cffi-1.14.3.dist-info/WHEEL new file mode 100644 index 000000000..9ed4ab625 --- /dev/null +++ b/venv/Lib/site-packages/cffi-1.14.3.dist-info/WHEEL @@ -0,0 +1,5 @@ +Wheel-Version: 1.0 +Generator: bdist_wheel (0.35.1) +Root-Is-Purelib: false +Tag: cp36-cp36m-win32 + diff --git a/venv/Lib/site-packages/cffi-1.14.3.dist-info/entry_points.txt b/venv/Lib/site-packages/cffi-1.14.3.dist-info/entry_points.txt new file mode 100644 index 000000000..eee7e0fb1 --- /dev/null +++ b/venv/Lib/site-packages/cffi-1.14.3.dist-info/entry_points.txt @@ -0,0 +1,3 @@ +[distutils.setup_keywords] +cffi_modules = cffi.setuptools_ext:cffi_modules + diff --git a/venv/Lib/site-packages/cffi-1.14.3.dist-info/top_level.txt b/venv/Lib/site-packages/cffi-1.14.3.dist-info/top_level.txt new file mode 100644 index 000000000..f64577957 --- /dev/null +++ b/venv/Lib/site-packages/cffi-1.14.3.dist-info/top_level.txt @@ -0,0 +1,2 @@ +_cffi_backend +cffi diff --git a/venv/Lib/site-packages/cffi/__init__.py b/venv/Lib/site-packages/cffi/__init__.py new file mode 100644 index 000000000..264afa162 --- /dev/null +++ b/venv/Lib/site-packages/cffi/__init__.py @@ -0,0 +1,14 @@ +__all__ = ['FFI', 'VerificationError', 'VerificationMissing', 'CDefError', + 'FFIError'] + +from .api import FFI +from .error import CDefError, FFIError, VerificationError, VerificationMissing +from .error import PkgConfigError + +__version__ = "1.14.3" +__version_info__ = (1, 14, 3) + +# The verifier module file names are based on the CRC32 of a string that +# contains the following version number. It may be older than __version__ +# if nothing is clearly incompatible. +__version_verifier_modules__ = "0.8.6" diff --git a/venv/Lib/site-packages/cffi/__pycache__/__init__.cpython-36.pyc b/venv/Lib/site-packages/cffi/__pycache__/__init__.cpython-36.pyc new file mode 100644 index 0000000000000000000000000000000000000000..6defb7f4cc367d69db8b77c4c4373d53e199b396 GIT binary patch literal 596 zcmZut%Wl*#6wN!Cb{-%$ELdbaiw+DORe&mlRH#6L3JHmYWywn8n~a$xj;=FPP1k$| zKfo_#%W8gs71!yaU0}(__i>Kz<8(4P`dI!HGtY7UI1f%p_B*=fiaDK}4w~C&xmd0ir-vz}50-NqzF53koL$X*jI1uPFd~?b`&fvqs)XqMtW`suJ_Ot3 z|B7KuqW)Nj9iX9UNcQO7QB9$RV9)L&M5D<8MXlww0wct42WPgrg}=Y@H+*a8D}J4I z+cnn>NK`xE63nL4E#EfkM&pL>A;WaV4b)&dz;wxTC|9qSFL{gl2jm^!!CK`Nq*>Fc zlWq+~mljzLDMGHxM%mS;W>4apsLhUlR@dC94o=!E-()2io)?9BE`%bo5Q}!-C+Bxv WzqQLZcA1GAd1LpfJN5!M2>$`ew5H7f literal 0 HcmV?d00001 diff --git a/venv/Lib/site-packages/cffi/__pycache__/api.cpython-36.pyc b/venv/Lib/site-packages/cffi/__pycache__/api.cpython-36.pyc new file mode 100644 index 0000000000000000000000000000000000000000..29bc1b3f7f69f242a713362262b9649c1bb32ef3 GIT binary patch literal 34009 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 VlszhE3c2Y&l}i3Q2$y{C{{VUu-^Ks{ literal 0 HcmV?d00001 diff --git a/venv/Lib/site-packages/cffi/__pycache__/backend_ctypes.cpython-36.pyc b/venv/Lib/site-packages/cffi/__pycache__/backend_ctypes.cpython-36.pyc new file mode 100644 index 0000000000000000000000000000000000000000..92f4e6b8dbb0762e3a40d2f9c7b4cffbcd15fc83 GIT binary patch literal 40053 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 C)H!be literal 0 HcmV?d00001 diff --git a/venv/Lib/site-packages/cffi/__pycache__/cffi_opcode.cpython-36.pyc b/venv/Lib/site-packages/cffi/__pycache__/cffi_opcode.cpython-36.pyc new file mode 100644 index 0000000000000000000000000000000000000000..f496e18c1327b1f78071e2b74406c9335a422177 GIT binary patch literal 4847 zcmcInNmm<560Rz(h~386c$F7ygbijhwlR$@w1C>8ibewCwA^W-OhJKA;i|$mdhSch zbMLv&dvl)q{F=JXss2L0H`5c5B^5I6dEJ*0Pm!@@#FvqgsbsddH@3R_g#1t0zBC!BhngJ4EK^FQVksy;uh=oa*MM#82NtAVw zE*2v()=j!u59wjOq?h%PKGskA*#H?}gJh7MBj?z8a-I#5A$EaWV8djXT_hLTC31<4 zkP&v7T!y$;*cEaWVqard$#sZ-gIyzW$Z?ZhC$}KaZFYm)fn1|3PVPd!d+a6|gPaL= zi;P3w`|LJ(0J$gF9Wn{|AF@$01sJB;T`~hWX4yS52Us4lF)|N$9ZSgIf;a;^-0 zl#rdlEpF;ny;8PyqnoY8|3II49rpkjE)f~fDokd|7YVuy`V2cDuGrs95G%BzSaPc&+=!9N}m;=5EtgiYC>@oDc0?RoW@r$9pBC&Y7uy;3dYb1KT(%9oO}bhIvpr;bk*E zSF-paw`^|4r%M&SJNI;YrgUT)`@CY8KJY!gQseP*-PR}UJzllr)pCW$OpB)C zZk@p7LvXEsDCPB?lBL^x;;39XDDQHsRDnf4L_&?Dioy8g(TNkKRENowB6JIhB!}fj zzgLjSwzYzLfFG<1R!3B337F5)KAi7^sCn0h8tp4~ps84w?cmQc6LM7^hI-i{^c#_W zg8jf+?kiOV^@)Jm7#gD;ps1Y~8?_RR5t_G!Krhe>`_mVlG@m8N7a*#YF6@=x+-nS~ER=DZzbLWebK z%0J6cC9p%a!suy7nuar~LkYT!#=g)C{T!=NI-ufi8qS06x&_LPc#v zpzB0;1)GOKS9E%CL(y&u<0muVw4^l z?6`(}52f#q%Qeqpc3}csx_Jo+#_Y(4cZz6D6E_II7H(Hmjs~NVXt&V%MZhDA{Vt9w zUW#}inerTddS5{Eu%OR{d=4ztpg5RewQ;HRX>@94`&;TFHupCqcsZK5O9Ca_(t-N% zVFzM_XAT3wU1%LB1-29agx1b@7ICu_^+ziw)}bAQ3woM-Erx4k1C@CIWYHAKa@* zgcwKe7Lq$i?jjjOGLGav5-hkofn*ZNLnKp3rjg7bnMHyRrNpcgtn8IdCuHpzrfp(! zCs;G;yNxcSalv+5`Y!x@#L=_SdtC1n`+QMEX!Q6p9MleH5$K$6^n*JgILBq%2{Yq( zr^XxI!qO7@ge^`}#^F(oe`@r5dS5|8blEU!B=QlVQJX|@oStuUvopYj0mu^=Bgbt9 zM$ZQ|f{OqnoTI1`9IEE$FcPXf4wxf2a5m{eU5kZ*>D4M`vh)VWOje8O0WVtPWlI3) z#Yr8aF9`^Jr&b~N`ep&A!z|=evw+rN7IHVvuC@~Qh|s>&HhF1$n-B$J^z@SWMj`q} zk-}RJ`ufE=EPrYjN3i~lfR`|yG;t$fBk#gJ@OBukLwMj^giEps{gdsiumsJc4d*0nBOP zrfS-{a9hq5#j=G^d=1gzT|x$7PHO#iaaB|4a=xh2t#4K8w<=9UNoi`Km{f}*b6cRW z7_oqrytbUo)2-wN>4PlkyjT$e6#gw)OcRPzf0`u&FvHss>Y*cDSTwq&<#V#1-&!Ebi(g;i~%NVrhey+pd3ov87 zxIub6&|gWQPv^4PRs{+<0xc=r3WE3G!wj0wBnyCZz>o2@#&-eCgJ*m|a6Wra=W9p zD0#R=JEXL=^?YWVoD)UynxL)ox)ECeK%EMZzKg=?7S{yng){$B)n2Kdc-|L9cuzUx zE3qSKyZ2~LgR3r|XpIXLW#CFQ r5`@S0pZZh&!0V6fe=dt0Y{yZ80Y(1*|3w4-x|FC4{{lk(OYrw!N+8XB literal 0 HcmV?d00001 diff --git a/venv/Lib/site-packages/cffi/__pycache__/commontypes.cpython-36.pyc b/venv/Lib/site-packages/cffi/__pycache__/commontypes.cpython-36.pyc new file mode 100644 index 0000000000000000000000000000000000000000..c7197a99d3252e84b138e95d3595192601efe6b3 GIT binary patch literal 1983 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 Ds)_co literal 0 HcmV?d00001 diff --git a/venv/Lib/site-packages/cffi/__pycache__/error.cpython-36.pyc b/venv/Lib/site-packages/cffi/__pycache__/error.cpython-36.pyc new file mode 100644 index 0000000000000000000000000000000000000000..6968c467785a3466287bc8a68cf0d5aa7e86f9c9 GIT binary patch literal 1593 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 Xyha(J!#i%U>DU}W*wJx<^MU_=c!qgZ literal 0 HcmV?d00001 diff --git a/venv/Lib/site-packages/cffi/__pycache__/lock.cpython-36.pyc b/venv/Lib/site-packages/cffi/__pycache__/lock.cpython-36.pyc new file mode 100644 index 0000000000000000000000000000000000000000..8febefa2f19846d2a73d880a94e96882f0c4a5f6 GIT binary patch literal 487 zcmYjN!A|2a5FIC_bPGjjwI7gc58V|k7Z5_Ll|Z}FiVFuyWhpYwq;-?nVeAAV?QuVX zU*MN=-4nmS38$q}ZTZb;-aPw_zmG=4U-N(Qrx4&jY^^meU@sfePX^syu{&$_&a+d{#~+&hMx&z-O}(Yr-Dq?$^{?K* zc<0qSfa_Q95XP(>i99z_IE;PB#*BilK4?SR*ml20vdZXK>D07+w;&V=b;@?{cTpO0 zmqdoz{iG_2CSLRH?j{+<+w~Wq?iW_@_AJkMW&Q2^Ubt$(jmCsjjXXh{IaBgVt4Bi_ zZ%|Nl!YvkP9a40}CC*PykB)gsW{J}A8W&3D7zypv#4Rv&Q7R-xgwo8la^8RBhjCc= zR$cQy>YiKWa8e4Hi8)#>(^P%y#{XJ2?clsHNtNRT^JeX54})OH0(Qs_*q2}(-vOn2 Bh+qH! literal 0 HcmV?d00001 diff --git a/venv/Lib/site-packages/cffi/__pycache__/model.cpython-36.pyc b/venv/Lib/site-packages/cffi/__pycache__/model.cpython-36.pyc new file mode 100644 index 0000000000000000000000000000000000000000..4ea8028f25295f8fd4a0ab83240388bee8c38051 GIT binary patch literal 19788 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 h=P@;4juJEDNWuUB literal 0 HcmV?d00001 diff --git a/venv/Lib/site-packages/cffi/__pycache__/recompiler.cpython-36.pyc b/venv/Lib/site-packages/cffi/__pycache__/recompiler.cpython-36.pyc new file mode 100644 index 0000000000000000000000000000000000000000..f504366076e70bc0da06ece354e0628beed087c2 GIT binary patch literal 46983 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 D`*u=b literal 0 HcmV?d00001 diff --git a/venv/Lib/site-packages/cffi/__pycache__/setuptools_ext.cpython-36.pyc b/venv/Lib/site-packages/cffi/__pycache__/setuptools_ext.cpython-36.pyc new file mode 100644 index 0000000000000000000000000000000000000000..a9d39745e509d22045f6f65fe9a172600abe53e2 GIT binary patch literal 7403 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 U8;7Khj?LPlebs);ZrHc}3-x9~&;S4c literal 0 HcmV?d00001 diff --git a/venv/Lib/site-packages/cffi/__pycache__/vengine_cpy.cpython-36.pyc b/venv/Lib/site-packages/cffi/__pycache__/vengine_cpy.cpython-36.pyc new file mode 100644 index 0000000000000000000000000000000000000000..d36acb0081905ddf7cecb4cc17024e608899b38c GIT binary patch literal 35691 zcmchAd5~PkdEeaE9#|}H5Ck7i&MX%<1X5U%5{QF@1ukF$JTwILG?<@uACGi2f+AdpV}kD)T{1WonuAWI3y{<(!J&jFocVMk%rR zZ^v;h#e3<+wyHJpu=S0a)2KJ96|d25U3Q$dQ)NQ`lflEM@pUtaSgaO9#j$ci#mh;R zD5q3Xr9Oz2)4IxXMrBnF?^%^s1>AG0rN-672k~-VO{y&jDX1y6756bUt+wGluG(sc z+KChsYM0uLkV&;i?ZthIdP42PeM&v4_T#=)J*6z%r_}*<5ch5BkUEU}c6CG@#eIi* zS`~5MS=(CPh3{^B_td7#d+~ijmDCL4_NiyoEbdRLW9m5W`w{n)I-ySD*+TjQ>XbT- z=Y#5uI*a=u^$B$j_rvO0^&IX;kmjiRq&ko1r`4Q#9`~YpLA{83NqtIv8uuA>LA`|g zGwPzcg!`y_fzUsHIMsgbzR-S{ft^tH`Oil z%31ZgdIKS!P;aWYa6gCK&jRY_@cpEEpgyb0NOfMlt!^WBPC4px%0|fZNcRH1FRIV0 z3SvH`?x-s6pH@oMaKC`Km+-xaaxUR}S=H5DgkMqjR0H>y5%&thuc`%gAMf9znradE zJ{CAT;E#>E?}-aQ~p>u#e}>%~`YRe>M!;ho=$_`3UX>BhS;8`lNiR%RcHO?S+-Q1@ zmR(j&-)%JrgXOLw^CFVA9^SszxO3ZWc(r3omFoS<-I{y5iUyuQ z96QdgF0CG4TJ7a*yMfHMJ;6@P;S!5y;yHXfy9T@ZxSw*Mzd5O;zezJpuS(NP31==LoOKBtH}J5! z(~DuuLt;bXhWxL)waWfd4jEFpT&Ts1^Med z747Xvo&ZgWE=G_g&_`yPK@XgL?NwV)vT&C(M1HzMDRI za^TH}V*ewccq$ae-4-7!!haMbR^C5=HqH%b>Gf^x)Y&TS?*|;-%veZkdTD93Z z3S{*fRqMv;t2M0p>Qb$4*<8o$MR|AMe#d&jdasw!ubnfN_1;09z^!@9O9y97a(SDz zUcG$l75j|~uU&ZU<(sqC{Oi}Qt<82y$izn-Fl(JOF%~{2W~`evthlXO)0#QaNvzFX z>Fhbws9QHaYrlHod#=A`zj67sn^&*TTQ9y~o#`Am@MWFJSZ=JNdUDE`z9>o&FO6ZJj%ywhdzI6HG zYnQLENR*$nthLTWP#gj5#n(FNL$#(`>x{DmzcpdNZMIW)eo^{yu+vcRSRcr_&Vi4F zuaoy-nCoN?kvXiF^3FcctlloWdanWuQFgQ8dLW2GVm;S6z}QKmD;NR$Uag{Pjc^`ZMVJbRBN`^w(IAR!1Zv6#dBK=iA(~#USd3+NflCfO6NedbMlu-l7N#F zO-$r{G7`reI=#O7@!$lk$YL-A-h8kUk{5jnUoHvmLo5g6=}59VKjS4ltb*$aXP=kE z$_E17dANE`La|PQmxHWGo({2TEE4fJ^JYFwE@Vm0<(^+pd?^l|@H}|J0(iojFq z_I{Pr@gQR$jWFC^cJwGwZ|-o#r_=g&!9vgnwY*uprWeT(%? zd>F@qlK>o(T4F`mmW8SH*d;6#>+vrozL==TA;V@q$a!16=?_uPdYo}Xgi9jSLL z?Chr35x$mwIrhca7vo<{){`oy@*m*q?OIQMDfS^2%eBmh@rB*pG@ynM{?)kinkuMR zbI)3~n_bwe#-wfN1HDuj$i~6*PJ9`yXFVUr?I&>Ghx?P=40xW&`Q9YZP&L~SiR#VD zT?k=7($ITn3QRFrV2DfB5$C*h#4Tr=?Fz-GU~%Uta)H0e(cF#8T`ceKOx?zEE__S8 zp7`O!gVarfyhP(tvX?l1vX{JHTkWMER+`IEM(aC;=Q-i3?Zu@Rzrk|JwgJgbM39WI zU~1lRD$eTh=bPElm~hCU_2La^GYU@a z;bLWJ361X0Kj#I+e-mE~TC9r4;KMHA$32RRui*F^6dYemETqcmyRmZSi!q=DG%g?H zpxQ`cFjAXr+?6X=ujvK{jiVI6Dy4B#c=!X`C24egSs1WY1_l%s6g0ov<)8t={}UNl-c7x4_1L6)(QFhhzdasLnxA`9mrVrB4^ zP!Rz;C!Jat+pWdM-Fu$ZhMGWVnbmHB$Xi(7xiV2NP|gtlY6|_9HAq<6?`$Oq(&4~5MBm=H zQ)|{Lt|>Q-;wuUa6-H6>_G!pWi*7INR9bgy&eP0yf%%d^VClWyR>~%JwNkx@RqYOi zoL;6aJVJR)ce$)nz1+JMrv;REdnrDZr*&l8X+X(PY1-_5$^+$nI)Wt)sZZQePA_X| zAur`gERGKw?Pb^2%7Qtru5*v!hlclLREkxtDo*U)9F8q zVE1`kV#yrjXfAE3_%!b0kX5Gew?9#cPbCVeaV&&W@xAfs?CwkkPh0{gGrZ^GohKfF z(7{wA9SKCp!+4Q7Y^2$R1QiWJ+#$(u`Jx6e@j3g9U6dlO%mJcbaW?WC6YCMbq< z6C)^QN(hoOha3(i-g1g_MbA-omUN2{rElTQ5T(x9NSkEr$$nQL?-PYb5zSIsV@lRu zsyNVal_$W|_Om$D!$2X1Wx>eGPMH7*6agp(&%zmhn}Bf!Qx7%GE|2mIL*Nat41181 z^V|JtTvmQe%aE61?|jvCT!KmuNQVi$LoozZ5u`hn>_Tkjg1?>+Rgnd@APKhMEv+i@ zQYxiop7-OQmBoK`vYY89xg^KI2s|hteH!WiD%glD*of_3W&uks6;Scm`$%D!hwK-! zZy`0mWFIi<>G|)(Er;0B+1BR*p`8Phj{nY6t+r=@;xwTdY=Z2G-mD zbj(AUxFj^#;Swbn1$`cLU%edISE0eqEMwl{WpHSPvHe|yyL)koVJN3C>vEWDleqJl zvu-@z**%PXTG3SX7f2Ei(#y}_>%Nc6N;eqRB|VJL-t~tyvz9f3n&@WCpypP$cXQn| zh9q83c9UNLPiTgX!@PoF%geB(z%k~*@eK}J{tNlYu%+f58<6OMD{!pzkd-nr9M0z% zS>dJ13!CC7TuKE^pM+f17`la*pnsh@U+?m=Vb9JZ_K)#(xr*zaoko9d*Zn!9-6Hi5 z`jUW<6S#=4DCh(Un2SI#Yv+elCWEi^1(d=d z)8My3jJ3YaxkYW;ddxXZGOZH#lg??CT!ZR}?~o1Bt$hme#X_1|RE9yV1WVL9C^KR+ zDz}zxea)1IP{#w-=193gI8y5=t@<$WdDK~`Q+oL&q#9Fsq=5uM=>?QNX;eFmDRfb{ zuQ)NeCy?)t)tC>9)IRR#C!}fuu;jc+miIn+zA-h48Zv+-T{q=P=oWB-z1PSpvsaZ$?ovp9|| zJJw9;=n>af+>m1^9#JJ0s5J#tjaYb_>+Fn_ztl$EHK#Kb&D={-DMGyjG!QS~f{Z9` zuJd#t_rLIh#nKRe^eB`NAe#2|YIWIhYN}W&m9{vC(Of-`kFeoe8ZKK}0|O;0Z^6`F zLD(j(@XtE6r6w#iy|Eh_E>W>UJJoK1fO}#&syKHkl~?U0&#~K%U2&YsYH#AE*r2XE zueU&|d%4Tdy)v^X6r4j+{S{+(y5Tue?zZ{12TO#%ObF38gj^HuY~5)uKCC#swAbb> z3zn)1Q*1d0GmKLKBt7a82pU%N9AZbwT)iD5;s0NN$vulp3{2HHh&`@gr=~@>K*lMR zm`-Fsq9*Y~h6_fFWG=B2Yy9?j=Wuih7}Z4q@gTh*8Ix&y91o!>JJSVsrHvZ$Bm#Li zi7?Up3YkgGceX*xcu-!-{LW(21dIY8aWj;71V%{1Ifj zDr&Dt+ySEkGukGm*JH~3%Ur?TVx+v%9JD%ptYxg>U26sqWwKGUqB~GFZq=Y{{kLBDL^Yl zrOPKUP_(v@Qgxw~2xt}9svu1YF}{MDd1$j3okuI;nI`K~I;k(`)4WoCzH`b7#tq}4 zM+{N}Skanor~sswW;5vaVy8%|;pQhmt}$z~ENRWRiTFp@${z{-ovBn$3ChQ7oOct){#cX1D}Yg8DgpqX?@d_pT+8%lhyYFm5Zh_X`nH5{VF_+92&@+^ZVWeR`U45um_i3x)T5yC=R>cJl&RP&m7}Q>>JXo$p3e|KtD02ieP%3Q=kxZ_~&LS_u zMz{IIMbaTHb*Ss^nG6KBjFsJBE9Xw0$E#Ga<2S% zlE#y_6%(c5&cROf*D2}N$qOz-f69}(?{c+fv$5nhTxSN=_flLmdl{$ZE;qe!59)zB zh&0jOJ2)r<``$HZci@@uz3fYNdJKJ)iI2k(VieW!{S`zo8&yuwZ5&p(by`comm~q({1r$E>DDyfQh2+i(s)a$%o=(Z(m@>R z9%$}SPFhn0c^9KHDFb=;mE#_%2Fk?9SdehDYdPc@>*f{;YP_4>2``m(p(gRzgTM4< z%o~H|KQGt9%0A{qzG>v41d)S0TOh;_{^gsomHpmC7j;Sen3Or@ugeeqJ4zxIodk6g zTI8OC+%OJFL77J%-Lw+*0piJFVON7XxYzsQ+^2gXJTbGTLV+OZw&4j4y8_e zao<(D^RdfV?lB$3f8ctM_~f&G?t!HypuU9m1*sWHupF$B431TiAwcLq)RL~6YIPf z<$*?1BPu>eDOX2W(9;4)C&|7X3)$AS3xWO8<(IF{+ZV1~yZ)wq>y_8wM{tudda*`V zdTnsVkm*|OA~@VF@OVJKXl`K6T6^q%AsCzLl&^<61p}<%aVrl)z<}L`ICgpdQUv_H zmZiNEh;VcC#8_?#3jsfjC;T|U?&)Za_ijhcGJaH9L_xfl zMbVrIa#+vV#TFVEmoHr<1jR@Hh*r**fS^Cis)w!;l}V|2dF0e>F_ z%Ichgyf4y$_9Mt7QqTp!lmf4V?eTrk2w?pderP%|g_JqCHx?2pJd;C$_5fiA5t>PC zm$z}`quC}EKa4xWwZ8(>Q4WDQN3;%%gXLgm^RqBu1}J_6A_$o%5bKx&Bl=AmOX-Lg z2dku=@D3{25U|igyMTrMq)Oo}h2=g4BA--Lt|huDUmzADoYjt`*^L>}VR1w+wC?yy+AkYa${ADESrRXFT9m^*-7)$L? z^$m`uc0FYu`~Dyt$Ik5LdRG?|C=)V(gp@bX-VF3_k`@yvVbO17kjS=(qa!RW#;K7` z+q%sawkeAlLwko<8KHcS%!F5vMhu3%6j{J%w7NND=i% z9+fXZp(L^fO|}I92`@T7xLnGBk&g8C_s2%ZQbh=l zaX3tK{R0^z*ZUrVM8N4YrXm(owTheB?-mvW;#c@dFr-k%~0R`4Pmx?rrtq zh_*vx$49m#LUBwfI`eO`EnIhDf_U_dAIMgf<|7yH!Hg#_&~FRaMWd#t3%F^`ZW(;o zKKu^#2W42o5%i15huebe{W1BiP!kSD2ZQz-*49rRfKIU4^3UMwP6nWp^Ao(nWQoH) zjU~WH66yP4Dk0#Gva?M4Mf73#RtV$+qd-Q5{nVoo$0Ed=m>X%q`S8?meiT_h5^Hw% z@s6PMXU^{op#RfR@CR16ey-7t*cki&24RdlKfW1I_l^Qp;{_a-^VL?d8)1w|jJpVM$Dpf((mGrbnqG9W6D*uyXx2njQ$GYiqu0 zD6BLacU#hVkWIx7yfVjnRsqgjXFpS$tpI`P4ib*p06>WrDPYEH*J;KTr+y0>hC28| z1Z_~$thI`ykV`{JHG_>{h>;fe0tD^tKq3t)DaweIPL`xsXFD0j!Kj^rab=DvKc4Ig zgS3%JH8#`{?uuJGJgo<^% zlqUMzcP|5L95%TLGh3dJVI_Y}IkY#aTN1pdCD;+EHC>k^={lu!DCqArJdSEFT^CQb zQI1Ar1$rdyjHFG97U*$k&$aU&CBdEYKAB7)j@tLB_)(D%>6uO+b$%gvB32y#V3*bs zq`op$=h%iTuNfYn3l!EoSUt$0aV3`3<0Kw7UOlivz%dQ0gV?hI9xgdQl8gY`jATfJ z4T+P1Xqb>89u^3{0VuSP@e6z!WKV@#nZPP%Bp}_JXn)kHy3emf+i&;}wwxcXpFt0N z3oje?KpFyeiY|3nEi+g%>BWVuUT~3w;4K}z z(HjP(z~?>-{dXK!Y|%==bKriW{Z-LQL#KQ{(Mlzd#{Cg52g$6^g^sy*pk{V4P645l6ElM@ML{$o1bQd;aYtE{5=z#`UmN5EPnb4qkg%*sr}t zrCFY+V>5h>?ynwp$ZF}H5@8uTPgiP6&mZUKSOg6h;hE?3hgVo5jxpwu@fN{^m9?mx z_u3xFIi^;5QXYl;(m?@g9}@j`-7V)eH9#Wgo2)B>D&!Q&5XoL^Gx4B)f!iiLY_+Ff zE<@z}mp6TzOqmy>8iU4cxT-I(5kXv4{}0Q8W>nGQ|K`x!6*+qI{y-mynL zjZULAGTa)uP6t|S2c~v`D1;PgZt%eN4C)#fnwHRvgklo~M5*jrcIAE44~7eB`iBE- zN)pW1PdxaLIlEcOnFA8%))O%CeeJlEqnVnicO7nP6}**2 zU%O%M2nPrF?EHPy+S#MyG(%uvdRabe)7hn?I2Q&YN@IGa5^RS(Ds!!uTxu^tTZ7c? zI&`b#TH1Bz=Mi7d`TRzI#tux)f6PKyTsiyFO;Pta|A;{{xkNGhclr8@y!<_0ehHUy z=A|o~kkQ%qQ-~|ETW9g$&ps$f({#p|!g96~%NZ9knwha2B6K_MP-Y$7T-Og^RY1Xy zqq4qz)Y-?WN1sOc0|C)nlX%B8izcK`2rk1yT`JQ9x zY+jYHb3iE;H2uxUC=NNU`K!o4ql4D^%$KOgB8Y4GhzlVd?znUaZxwWl1J(=bvmunE+A;>JK>gYPYk<6hV&CbCJES7V=89iY&oPUAwbw0r5JMp93z}$fNPH}gR z?tN`z?Bqhyneg2|Eirc<(9s&IzRMWhiCj;Y0CAV*bd=(6ipBjR`zp0&;~2GOb8hsnNK^SJi~3oM8ccae)P0Kq`X&=Z8}LI4`cidY7>p?AiE zD(JhAmR;!D)|(MgN({AP=I!mlzHjP!FjBfBaWoIyZn;tQ2RTqDZ~?ndlTfnTpERMyhtk$r(hW!IC$#!o{SD?!j`B*r4ipXWzfO~}m>Y%2o0Ub3<#~LKa14L}YDv=^M+>cu>K!1%hm_%Pl zA{Uv>&Tk;>XNk;*@t}_eU|4je z&O84A#r4M6RrIccal|1_b$*8zB4IDtX)I}tx8S)eNTye8y%{}Z`{X$4w7M|oTP#MF zV*y7m&x2#^{3_D?ItP|=BawC-RG538_>_aUHx*=NRUHz@2i6`Le-iXy)Jc=hP!O)ke%j}YjF?fLtw26pUQz@ zsvsG*j-1EM`2#-3omcoQjiHI#P%Tq>0YJ*{GHy_rNPfo~F>B%MlF|k19Lny%gQ-uBjf%Dya%o$}Pt-)bY zHgI3cqJ&^coW;w^QL;5MK|m`w<+Os)( z14B3`jkwB0>}Kab@DjnWe}=F>Vq^3gzdJsB)LKYr6tY32;fFbbR*(==V*_~&7VWhp zWHq|DaR(M1*nl`B8wPPY$>Yb5-$JMUHge%MnpI(B1l(T48Dp_hb=sn;`4hGwhaA)m zif7r7vUp%V^m7K(o9zjx_i4QJSxx9Z!D?cJFb&YQf_@VxK1y)?ZGjk@Oh`dR^OoK~ z^8I`o$$R!P-V%3iMw=R8KYdXw%zpl_extE{0b28qU_eKeG0=P>rmO<5;UU!g)8Xc0 zP|X$w+2#u>tP)?w*}biOgWW={76)FXzU=!yrRT3;;{PW5;To9mw=lhw)E3@zMTY0|f+Anv{WS zC=tkoEr`7b9#{MjK{-91*O733QBWx6bYY}QdoWVDvt9-YkhHNUU_IpK?geV~vv8uI z!$%f|BJj3y)&yKQpemp;-top|Vj-<|#y~0Yg$XE6;yl|BTLXA_)i)$RN<=92QrU$q zFi+7qmiDFypZ1RAwCtw86!W%fnBzDc3TFoKc;wvLm^|}T<{Y+WOnKOn!cCgqHki4_ zahMdQwGLa@zOVx=j+<$2yi_|U?o^cM*LlzcPLYI+O#8Bnow0OGxKqPnw3h5!)V}<| zs>0O;0gw{t&ik?9()mj} zWgU%9n*Yqo{*V`%`ovD4%?{s>*Iq_79^$|s=T{gA9YFtya zK7p>W2l<8*=Wu|R z3=^`e&iSuM==?Wc*tdSSNskRU*!ts?X8%zgORELd5#-q?jje*`f)tYaR34mgn-m9J zC@pqA+6mV$J3v8>IlJj1zOpkNb1267Wi~F8wFkcAol70;e*wp8&IA?Q$jo@kMJJ?>Mive-Lh>9gUQe@sd=76AHEm&(oS@$|+u^ zdD+Ly0bUOA!j;i^mY27A`5Z4#@Iv*IbB~t>FS1|Z3w(OO%MapGJ}_v)p{f!mXNA|v za>OyxPr@Ythe`##Km&jur|l(Wje9;9XCiT8Scr0%K<6(KqObAtb%Lc;^nOm?cJBN& z#)W*DS*I~yhZIZBkFlJe;N`FL^3%AKpBjWz`;>+={S1@-O4ywH#$ z{*UEDg9QbqfN-BV|AfhZjhA2N<)8ENWnTU*FaHjga>VUF(Epge8|(o;)^w@y?Da#n z=p>@mud?Wf9ZSTQP*ckhuXKsm)jH(Q9rCr#e`HCKUekUBVP9LDv>Kd#eowu@CTCUKjqFK{f^v0 z#Ai@iCYJ~Q5-%J_NhzJbup^f)OyfC$l=utE&F1nFdQf1j{8=#;D;#RHs?B9pv!2&y z>>t1PVkpe@aD;!IVFh>q;`ATay2FF(xc1{jT-S2%wU^;72)5up4w-@*TBYj2g|VS{ zfG$pBK#ccpt=58Z!>XE%=XY>8J=US)Rcy|~VR4b;=_7%d?KrcZ*()uj(`$-s;68p2 zPHup>uFv1Y$u0J)H!t#p-csQZ3@WB^i*iH*8iIn*5;_BzLmNtxpGrYLBa8y4&Ye7| zQ@(ohjf)64ee%>vCPbhiAQsQY_nxE8<~iG&8;Ut~j!~!1jfy*SnsH}NkBU2YmT~9K zM&bhfpQ(0vM7@J)000vWK`@vKpfJ@CEQ6^46jKdB)$apvB;Z0G(Gxns5HwPP?hl<} z2og!5dqt-hf?^QX=LFQz@C>FjJ+uL2gK14aZ2;q7TGLw_KpX0_`bTsb;~&{$Oz_AK zV}i}~*C<#9o8@=cNT>#r`n@$0zQLq^XN`n3H1>;?l}AnqQ;tb?NHpu90GLdM1b~(S zg@wLZa+Wjc!{DrcZg|$8(c}RsTRgzqhSy4S8RzaTyPWX>F$mfuUd(bp)*Ng1D>8Sg z`@>`@3=_=~a)v1E5JlU*`NnH!OFWn=6y`3sN+lkpZNiH7g{yB32H5wOmRCsn`VH5F zZlK{B93h)Shnhccok8|xY3_~Hi#Y4*HK@;)N+<(g;CyF#Rf4Q7eqti`G> ztwhuCMZM=-mmI_p^q~^^<@@Pip@2cOWZjlg2$goh<;Gc@kmaW=p~Ocu_eGrH9D`G(7JpQPU!Lwo!Szul);n1g#`_V-)cX80FXRME?0fxy@QP-}|zl>iX zz>GJw_lsh2gV<3t#>N#;jPs0s^e0*r2T+D5I;tB1-LIuzl!l?-F3dH7N{8s?T%8Y^ zGYnzBD8~K2X&_t5Zv%wy@;DQ%$8=;nlm&OG*^VnAfI(hVDE&k#-v^#of~ zY(FMO`$JyT=r`;pFbwR*A*LBo%sB-*S2Pv$=ZvmUue<{O@^i&@FcSxRWaBCkbKV*% zs==asl-~fV)0>3q)VV%be@>{RC6@2_OIS@jy5; z8ieKlk06{K4MGFb?&E(xUN3xNGziPzJrIJ0@FVf^+-O)Dki;MVGqO8^wd>InzjP4sOImY$9k0U-+oTp$;0RmZpQWUDK~@b9W!4 z;epv?2W>zp-(}-)Qv2h5d}vJWLCP@H5gSs-k5jo{^eLaYzkpKGR`9w4C?@r!Bp{OhmUm*2W^ z{k2;+t<#?<6ey%XGU%VGq64rJ4=u`bg+loFnHeoW`!a?dE&iQ3KY1Ucjm(WYu|vQV zFtpX6Uk@7ZAO5+q_skr6OB-Zyx(yF33BZijD^4#V4kUUeEf2md72XqrKtHefB`~qi z(y)p{bX*%dxUusc%E(ZQc;r8Sd=9(8f44^bBJlEZquA-+z=!t9b2YzhkcB=BaXkMsDF%QV+agL z5#@d{=yFuDRw#%kjKK`;6%%aSx0fwFfC0lT(-o(wW7g_c1~G6wa6D_#mU|?Q1HDN5 zd?Z{*O{$yzWChWlVvBXBmyWWu08m}fnpCxjU#F~j`uD)` zYfww_liVA$!a%9#%OJ7}E2~%OBFZob3bfRu=i|-|IkBxjKZkzbXQR=UdF~^gY8&Fl zPLdL51RL~YDcZUEoqa2%=uznReSj-h5M5j{^n1;E_a4rR!w5^J(4q#yJ2cVdx41=K z99lQ^4~=4(uiBNRhHV%hjWcFO=p+CTmLvHwU|Zi_l^_PjYec{H{a9x81Ji11X3*p1kKFW6?)Df@| zycf(6y#e!P&Evu0U{LUbi>4<;-)tJr!Ur43kO2ANSZWqt!;+B}`cQ=ZA3{)IV<{cz z4weQ;I+1goorIoZ0Wh{u(7y`rq zV0RBW0|DAvjn<+zks>?mOB`qIxKgP&abm}gol2$RO1V;%&21AWPAb(&l^>Fas498M z!&ahls`7pR>26$RsFji-`*ioY{^y+ke*VV8b92S#*WRuEX)BZYFPX7F8_!SR3Z6%z zGRkOYD*A3z40$&zrZSb)w$|;6ZDjClx3lZHO3uhUmr+@jdpDzUUVhuEI4WN$DC6Z! z+4&f~WmZ2nkd}=oyWUk^8xMP4_55a|S+9l7Zs%Fw@A`FCO#Uo9Jb^2C7Y)4(0l?r! z#ZqR)R+h5g%~Y~_$VyJ-m4o-ZDySmvj;g3xHTSLo5K3wuIYsq`+M^bcGo$vZCFIPi zeQH1MbLxOPhICkG)ECq;?uS)bt>Au-`l33C`w?|YoyPrMbw-`V{XTV0J%s!H>S1*r zcUOH$UBLYT^@w^D_oM2|>M`6OR9DsG>M|fdrhY;_ft=%j;)HrrJ*l2T?ibY4>KWuN zt7p{}+{@}Y^*rt?>ILLNDsn^Ec2=e!Pft^RCht=aJ+W9>@aj5myTUQct+ z?n5##2AL|-7VpMd2C3O(YN-r*GgixX^C$1EN-9tTK%!B8-eEsSFhE=jq6vt9Z&hq zTi#XW1vkQO@9IXUdAsZ1xVq)leE0m-z+3l%(DU7MSL@!|`7fV)=xWdJw!C_H^_F+N zS#Nu8trIp+h1b1C=r(F~&-J}}cdgST*1EwK8n2^j=hoF1o7b)e&Com5tJQDR*1X_q z9dkN^GOks1&Fh@*ZADJC+C<}Ob)M_wAjudx!@<=*FuA&?lbRDtOtO$AUc>_y7gRdP zw2W;N)W~HuSN#G?usFrQ3zgTXZM4HU%b!6>WZ$^00$DAc%rSGRR}1UctKMelbpp(+ z%1ZlC63G7A{RgLj+pT_`41|B2Ru-24`U)O4R|nQJnK!QtZD56cAT!JkOqIFe_-+W` zhvw$Wz(o1cVJI(O)sbv(wE4&Rtr2< zi}I@J%Y(z7q$Lq-Y{_OC&5o+-uJ1unuz)0E6tS7y&Z1E=W{v*gsdXD`R3}H|AMdjX(yeY&xyOU!!7`u9?pyA#h>bXg zy5)lZ0B%u<)Q#P*UiWIs^MwmVPS5vh>(|;|R3O27ehs{Zl!}seEo^lC^=KAMOh~NR zX>=>|YhD;5k>F?9j#roK80F9(kTl9;pxtnAkL*Y_=x+FRuNro%jW1%bfV&B{Vmjum zUCb7Ni#gLq+IOcmV@GqJc$lIHX_yz+D1f$*xnmMVh9>CJYS~D$$jP+@HL1QG3jfMH0}e#K*0Q(3>jzYft<|)Hgblt-IF2Bpy7cDK zRdZxQ=#nPIPDbN5HZGQUrXm)gxBtasOYmw$%c z6WCm)e|~CW;8$UljIjo$1q~n=k;SM3EHv>a%2#_eA8J-*ZlXz)g?w0t6b_)pC33=Q zLy4P`oqKkS_9j7N-&BVdAwhTWsvS*IHpOO#a6OGH_zfhRze+K(jYWU+qj>$ymav3v z6YusgyR|=rpitHT3W59BH?T=YCbX435aIET@r_K!d_A*Of@)$> zIWaO&MT)4OMg3nkGQ+%)=`V#~hJ*aTWcfR&@eRmwg|fHvucJ1vSb52=eqy*j_oBZy z6%~A_9uM%pe}AVNy3O@o8wzSC^pxA|xT5`TEtem2kNePVo{fPA7}!%AS9rTHwQ=^U|2!bkTUX?6=}jx=WJCNHSoo7nUSz_l_+LR%E^3}5 z+-H@!)EE7)GT{RI)8UBsF$>Gj;9X^~r|Ye_&T%${a@ zV#S1#X=&gD5CLfyg4LT-1!7)@P#&-!;%{bGQk|?^=Yag9HbE$4M|VJ>*|=T~fkGBb z)@cf!SrG-E0yN#;x6ok%$~3{JeUD2q5YZnp(8`?O?0Yx^s25u^gBh(+xAyvfhCcVIIoM&d(3#EQ ztSSv=2Q!00!$SQzHLqa;qr(`3IT?f6xTO}@2Un{#r=j`C@Sjn8hNaHoGY#vwrQq5o6AQN=E z4d~>l%;e?~okTNp@gOquAT|IBDgZ=>oCbl{aw5t#dA$aa@m4>(;=7N#{k-pm8-B;_&$wyji;*!b?~97f zpxFt+TBq)5wm*L*2J5BJr`iNz5kQC&P!Sf9X%If$J8%4bKfI*EXPC0yic!r_Tvq)1Td zBv)IBxf=PJwGCD1BcrnnK9(C8ke;xsVWW}0^W;9;M)0c8wS#^Nq-(!~y3Xb^VUcyV z4e-1RAh|-yp-{{JdDNa66u}{jgIsGCa<$knh0-0oAs@W2@ft^QhBN4YM)&T2GMH)2 ziC^f4VF|o)rZv9}zDREI4rd}f4E)S#Er4&%P*$UVJj2eP!3cOqtv%=yvkn&r;L+e} z)VVF_-kH|k))IKR0e%M+jht>^wf2GY&B1=nZXO-vFq^}AHmJQHS_2@5_eoai=K0q$ z;Q=U&CU_X+L3j|_g3&sJ8Ohv)e>tmHQU*ogND&wCqAmoLesO4wcI8!Yy_@iZX>-!@ zsRL_;!NU{uXW>j1IMb9O@JZnkt-8&gfBBEtxgM#1VH#<)H8#PK#+XskMStZB$Ad4p z&A^4{RJpYPE>7V!WQiwT=#nh!_G&jbJmFjZbqqSrt;&bTV5gDcSDAbhNmLRE46+hd z6oSS(TjJ@LUVP5fSFAYm5?pt1myq=R268~0ZABQsX_%>b)C{JRFmJ!f)^tq3DBOUq ztgRDmUDToBLP5C39-=uhBonfYma6Nu8(!jFj=4gVhsTskv@jDfjLW5I79<)8P0Gql z$Ge?$SeYH;JYs+baL4p2b4hlU9LrxPxIH$WPYYt!lzr+7IFa9BjVWDcDbZo5XeJ~6 zLsSf&Kq5@XSOVi9!Y7VL)VHW>~Wky%1IOZI|0pU8f69@Ow@&+cxcr96iGg*Yvm z6E#-Q2|PmYle*xk14l97*RhlV@7#Ijy>G(%W4>o6-k)K%vnc)`3wbcF=n;Z9*dAo7 zFsncb*;PS|I{KDB;x8aiKH^GRS&wqMJU6XnPH*yBz-=~ zS1SEJyOZAG4Hyk99gaqqf%~ZWr?_H!g=k0D_+oa^!g(Jp0=Z=*vj6t`Dh+LLeGgMb#!_HWT6~wR6PZqU=uTcitVX~kn|~P zW1w+VV?+lM&N2<|XE*y6lP*Ru{BI7)u`@>hf!#oc3>ek^|HG%O;K?{T`9F(+e=N=% zoWz+Cw*47_Pf_Lz)8GT{5z35OrOW=AF@`ECxWygb^Z~<;))WK#4m3B@@;BC-_GKTFig#P*ldqao~A z>dW*g4YP0?#?Lr-rREIgGlbg@8mm3B?(q&=7jh}Da`7GdvXR;R6^sIl7rN$$SM8xg z-5DCIJt**83)=ICu#w1Q!obls^UcoIF}xR1$5At|@R2{5QF9+y z11CA>f`6+6$7BKitxw?JnuULBKiZU_v(IjeHccN`?3$c?dlnw94liirc{MMvW?D1Q zYZLev23f6z%WRU|J%e0q$LG~zJj1O zT0kpDjo%e-2hNJ+Ij{EP9ae!JxwC+_2gcj7KbgnD7@|Y*{cwE0C%zvU*kg0jv&O2& z4C~(2{vIt7p+wei#7@~ooz<>wbvME|4_*ow-u-`{7unGk#=F=* z!rHPTX&jzSnJFrOGG!WoC364QSxVy305x-7QqzH&OL?a1w(e zdx6hovKgeYmi* zLbr_&4q8F<%6pq$9sYHtO`~`h6}QWw4`%sn`C@q?qVb}=6Io2B+0)*WB3&l33&F@_ zisoMOo9l=ux#dwgjpmyH9P**J=3yIi>M!E8&W0P;P{x!wPwhbM7|s`?dF`O zBt#roCg2$-)n+B;{fwHAxnLYN7EL-% z^gq_I@3!BS0 zOMs6RzKx=?ZopmtQU)FgTl+Nz1!X^iGliQ^z*~@o|3yy6{r`qB9i-?1{lbHxY}~=U z;k$qj_&dy=nuDC0hwpj5f%B0T`o07?2W!h&?eE6a_9aBSyi!h?Kv^6A z)U`fl;vYjoFD(gh-v5YMVpo*}Yr72yUL5%a*xlj}YBYqcBEyc=71(v*oH% zw1mVMI77B*BLQ)3)JOORpW*Dv0?pylB4VNjOmQGT9A*&p%*{$J2m!e{v90pM{N_7A zP6$h=Ft;Xzx&?LR`#0~fzJ;$MSz9aFL+kNE?+2 zEKpad`lKxp>;vM;-@HQ+k7F08A~$&0uoM>GF$AHDs}m|dwNElD9gzsi$ACDg(5E_s zj6R8oo0_YAIKtfJ+n#&9cFS{*#~l9YL{j^1P}>5wt1@(Ha+I=FDeyq_R;|6^Rp#K3 zgYVf>@)}v|!P*qkL|Ng$6`~C(B?FW&@vr}-Y0egV?xyfzZOGLKYr( zss!DJ|MM86;w0jHM9vd(>93=b@QX_Rsh8#S!2b%BsBzYGvUGVZK&b2oRZ^Uo5Il5+72zzScvTI? z>)nk&y4c|Ikcnit0A~M-(-Th=Q!$q(+ol#1XHJ?DM)VLK#%6zCGJBls8T3~`J5T37 z>A|=cEyq{D|4n2>+N?{=NY4FpSgiZS%u5=l;J-CK>qWDFe0tUi>!pt%ZI#ZKbLE`H zu`#vV?r6SLUm%JS2a=~v8jNr5!oWoFt zPwp{!&cRU5$0lNqp?;`OgaDVny7oYMw!=Z6Es{{sX8vWG$31I+5F9&(T+aFnLG zg^4#YwL9+u1p!y^N74&nbb=qo@D<^j{?9lbcW^j83zcqmh_DZi+5Hg|HcKmPke;TR z!x1{_G2#ctb_s_;d9DDXdt@%joN_oYCrl`d^R>aBOU=oJ)&7jOnk2f%{~fHdSX#6f z#CBStMJa|~Y&7CLH?~R6UeuP^5h!J>-zK}4L>h^-DfjPp-O($ItWmWxO{|Oky=jMh zcP~Bep1l}Zw`%YaoDi1O=dpJXx+^$K9>u=Wu!;deJN6Vuz>driQPrYDRS`QaQs?2)Ydm5~TAVplOzH+(MxZ zI1$b~19QqEt?vR~5u2DFwFbYSi;eRDY%r{ftNoIucv(w0i~7Zsa96bEwg|+hfi=o6 z_Y3KZsBs@tP3#v~i=L&j|0>=QQ!7Uq`T(GMqtm_JnIJn+tNdR>Rc(8H3r~?nGW#3M zOBIhXa*Sgw1gV~6B{}<$)6PHO>)&S=Sxt)HX2y`oUuCY*i=2+P24~ML(B)Gvf<5tq z?bf09U{~t&(eU?yK>>9Ls==Bv8BV-_e+iA!MQ|8&NmqgcYGl-exB~9oO}M3OCpG=~ zX;6x>&){VjQl!z3<43A(R8sH>3XdZZKu8r1I0yV}q$B2HCCQVtC~(uxNfuI(uG%cFS}>m!9Ytl5p3=QkHaE+ z5#MO^&yCfic$117_?~GEUxA6l9Bc7)X#&rmtDTqEHX3hSI1kU?BD2!**iTuzCz&7g ze2`IN8MRNkM~@$GtD`5!fPt8W572eJcHs3N;uHUNG}>UJoq(bBW8?Kxm4HJ9FiHcL z4oO;^u23Sx^ht3^9uJP5qzicThXxoV22&j^U;J2MyZa^9h{gG-a~BbT<_=-ZK7g`B z!U%o}LQ>>TVWt0j$cu=CE*|u!Yam&OOzp!Xnc70k62`RS5cF;;LW-fpZ3a(#U08X(Sm9jV9)cA)e4&l?xTPc6cgRt25wGlQ>J&N@^20+0R2>dkL zC6N|3lC8baXQ7F|vEC<0#l{w1taOZv$z^ZzCq z{U7er5j>Fi=}ECgZ{{;4w08CH^r}qg%d(janV1mN2?ho)qH}x`hR==CFUNp~?>flC zc7lYni1Nq6-ZAklv4zy`97I%*h;0%+o^yAw3EU2`!tK>Mpq4*6uBjF5#WnV&4T6c} z=$9cy2rjadh~Za2+~h)WFrNP}_-u`RLL@6H%OnvmPoaDPW5_`{VqA87Wi#$>;4+L{ zdZVvwUV*;w>*&b;XH0H0`R7O~3$eSricqF*`xZRwf&gR%chNAo%hFbFFX7w?y#W4O zC@K+fMsILy86SpkSxJn$9;hdt7NJDy6#V1LruxMtylh^e#>KBn8HNgqIi@|%A-}vK zf2NLwV{_%$Ux7^3qI?G;2L~h?TY*5|4SyEyG~@je+RDzIbZD&qiWf| ze>bHv_L#^tiJ|->vq`5(3y(fNxD^mJFtj=lNm@+lm;q&dfJw%9*tbrfK24;eQjJ@U zw;d4~qH#|GjA)+;5?Zg-{jS(`E@z=tLIhVq67S^wcWF66ecU=>pjRg6la=|1XcgrU zN-~Tn>jNAcgyIy6HxWV@o5*8@k)mv`PR=(gwDfuRP*!6%4S6CAL>8nx!eG4?WJ-6# z;CN@HVJZfR4!mS3ei08Ni^0DIEQay!SHSP>A)K7r^CZ%R*qdm@Sc+I~fIY=pEtVzq zSwU}RE`pSk4@tPZ1^HN6LW?^`bQxLQsDwXq@j(&>R#@%FF?-tiP6KnEkNV(V8;frM z{{B*`@adZ34HA#i760#|0E?0+pcsIx_5ZD+@T5 z(m9CHK?J=ChKKkbx-M|`^mfQ^fFNXAakPtkYa}u8hz!S9H7vol&!W!~%qt#=(I{p9 zyf|5Ykc@^}a=y@7fSZC5>~rBBFo=g(ooKHjv z3qpbfE}#tBtCiv?r9_lNtT{r`*NBPiCS&v;{uCjR;M+*3>-On6F8d(biS|JTPi;db zhw=FB4#KNJGWCbcQ;*R4}a5)k{ zlq~-HKhPy|`;z|<-u#D|oJUf@M`G<-5LEHacV$tI>UvxF5Vwi`ldmJG9G=uM=)J=)$OtpWuL+E+u5nRC2NB1TG|u$9>`Na~ zC0b$Az*^)6P%;`E$z#5pSM3OLR_ z=GeB0mIc(Bak9ld#iHXld9<5z7Hm_-tSJb!;)Bgjy}hA4_fin5X7}{<%ad8y&mDRA zHf1so9*53!)2-kP_cuUIxR4NJ_xkIvON2lWYaRSKq%I;ElOH-^NMW&viuhbOaIY~I zh)j0mB7&vgz<240sH@dOL`OCiLU8blU~QCyw>__e=tQ@EMsxZ2M;%Vr zPr4I7tW@u9;fIx`GNJJzlg)8Lr0eTm;^jGgozMXm7Yl;eKDAu^%F9nzUw!s#<>G_* z);?at^;#Qnr&DI6gyhtg%hH~H!la>#K+Fqg&+5hb%FC}ljf{uRo;%Bm$c%}@<*z!0 zk79`M(Q0^cN6EPhEIM~#x3Y&HV%ftF?N)Z-Jj*VepDIh8jPbA=yNo+o2LQ0r4hSY| z0TkBS0n2190L5B6pc<_Kumoumc+DL9d6du>%sRp;txM*a5{Ptd9z)yTdbC zGhU&)KsH%7UZ=ajI9WGdt-C-wwq}hVvt%s))D>fePhBup_-yO78!VI4N|tL^s3xl> ztFCK=r9^w|$YLCj-TI9w&^mC9?JeCZ1HpJj`9L zR$qSgYv;@Ei4zH5V_vY)DVKQ|lJdGIUwC~oqk6r!u}Ri9nz&|k6BF0qz*3~sS^tpF zMLtoL(I2k<6FyNhjB?#;{24tFP5udH?;rEw<${~kT4qKH&s`5AZkbfXK^&yv>oIfB{@gdIlx-EaJdr#c|y{c*dr7is|)NkTQ{u>3;m_E=t>a2Hk*)}?cJewU; zo~@3>3}y}r2gOcN*HE`mFLg??UKrR1HA z_fD}BY!&s>>?B*m`3!rSJ;hEv(K~0^X?6xZ=h#_x4(Ibs-_}~se2w*L?XPu|EnQr2 z-G>2B!Z@OH*bM{j9>i=k2ol%D^=h{p4hLS^jrjqZCq9ycd@scv8=S}dYZDXsH0S(B z9k*~KO%$ot(|aUG?U%+`4bRuxEmM@kgJI0mLAWc*2cEwlMgbp-)s2tuZM3(y?zG+Q zpKfk$eY~;#&l;~_7Fm4r5B}>rqXciev+Jd!{hc@p7!Mx?J1j{0X*}E+Md72E_jksD z$DQjtNpKJ(X~3PAcl==Q`j1|IWoO9aUf`!Y4}<;C9|VpUrQwU|e$Y*wuIC315Bzv9 z3TbstGRDmZ7#cm?xgGBABw-r7IQ0C!w-+QkJ_Pg9Tx9FRu{h}lkJBKMqD)4(`Z!3c zBnAV8rt=!gBXXjCDW_Fbn9htRQd%?ZZEZ$7Www3VB>IuE7I19iNE{StfJAYGo zV-O~(A0G^F&@LwQ0!7W%CzrotmFsT|V&5AiH&B`1)iQV;_jGD|LF&%MvGf$VtMn)- zmlb-3lG70pndqlqasfr4kzsa>Uuj)kip%bpzk+BwSTA(SZbK;_23vQ0IT3E4GtEFp zas@@IWqPX548E3;QtC5(s;6dZW!lW>6*9D8%A}-5TNJ#+55rbbRKg^TlGKa*K$M_i ze#`<<3?g|hBqIoquVHdgc*LP05W1BFgRamM*h|@U{ehRjmektiiqB#68G5H83Qe!z zZ_=2*{koc^AZ*u-yo11XMa9ic67`zvem3$3>I$csL_L3o9}EWb=a6_?I)54`xuNn6 zPopKJZ0oXpMASAe-lPE&6mwCtXIX(2fh8t$B#P<4z%r`r`_zs<9tPJkmRLcAj0poedz?GdQnEe7Y!Xg)sqd3vKfoW8L>jYV;#R zA(_38BY6npz&1kh`MDIEsp?(*6s+eLXl0sfW(G*GN}-gyy)mZWGle-f6W@bHCB*)Po<}Nr?Unt;=a-^&9fNE?3*-xC0ps8Vda_L zJIgB6PUmB*zcaR(H8Hlf7~5p^tSHxTE?dc(UF(!KwbJu5jTO&o(-WEb8+~{!y)Xl4 zxKF3g^q%cCF#74t%51zVtUVBlsa)V7$06s2omBE_k$~~*PZ8+Nz3=5%a~>u_+fYK z?8cbnvhqTt=$8T0%(4LJr??H zPTfMkHd%2AtKH`l{G-237zWMJdR~;=p~vA-IwxE>mc)&MM{d3_PIxO!+$roK54?lj zLBI(HMX3va2&5NlF5zApxIwfB52h>~b_E6B~Zr;tcE`Wren=63%NTS`*731 zz4Ty+wlLyESXkb^XsFldhJ%3iN;K5IE!tIhMMznCO;L6Cy(HiJyrG7-R{43nIR8B= zK-DzM)@MVhzjm1H3R;L+Izy?=;nm9EzJ?qdTfgBId84r_;#yFJLZ7 zyi?EjE8jm8;^-LtmvOwp$@wjLEdn9}<`5LYbse-4dM(YgbpwA5y@)?cB6>xyq24eo zY8$Jl6V6xk3wl!?s@2d>;g9Z`+|`KII=PxbBiAM8VXo1aPP}YKr5|ha3_O9 z?AzQ)O@&YB1riaO-3PPyiFQ}}7-w>mlm313QVuwebIVa8bI6sgJI+?>goy)+#6~`B zIgFgk^lyG4P_sLwaBE@gCeSNgzQPrxKdHH1Yfb$l;s%Ol?<@sQ`!%nJ6xAgMkzcP7fO z=5sEH72(H1vTvY~OZJ6avS%Ps$PxYo5=}0lEX*`{tw?7`*T|)7Na;TL9_cz)!mfl$ z2GTkgL`&itku0pt3Dfn3VDIf8ZbagE4jaR^Lf;vLQ6I%F_xSj5e~wz*<@L#F)iZw% z_E$cFwOb`+VIN?ne3J@7IVJiwY64iP#^#IzP$}(F(luE~6KEVA^%LBh5WgkC7j;`6 zlhX^)A07SO!l$>%g@0WMKe>*!nTy+yEi1Wtd<)Pn&A{1~l-%$xVqf10Qb_KWlgpyZ z;{#|tVJX&0I;x48^G=dO7ie2(K%;cp|^?mPQkYGpp(xMjo z7w=M(kszF)`N$~7(krq-JPe|_SCn(GU=ZxViQu7w!Qlj8l`_UkoHWjjRV{?<6si>X zL6SfVuI3lXgvoky+geOSo^!taPB#SdAFj6DvX7~QXv|%jdf1_6aN1)~%|YxjH`l=L zQI6X3m_NpCG7!{CbJZXPK_qc#nakrB$}uPJ67znHSyUt`RRXjfJj<{65Ag)Y2Pf(_Dk!n4FpG==!n23-Oq^izb%h`3Myf&%#!&k(hecmutBtEr1Jv zm0JqN6J;!cY7)5FGi_?1uMBc*bU_Jwm0y#{5Uy7x?dhz-cl&+UOF;;dbd-jJM5%}L z*%DC*LOLf8yz%Z5vmutiX#@GEC`6rBw1||YM{b!CWI7e)EF_I6K|)kHCO!TqnByT1 zrBf1WNUv5QHR#l-BXV0jWg#_!dpe}lDB{67Avd*7gTI6xtP{ingeTocPDJg~_bB>l z$w0_v^ZJTsOP6y~9U@#`25yP;HoFuDdc>e(QscZGK9Qp~Z@VTq=JRJs>X9 zDH5CH?@{qSjWdZ}lTAWhXmS;Jzl_=pM?%D01NkFGrNahAA*x8KJ30Hk>sSbvVh{4M zw{Rq1pvZNDe59VF&}56hJ3f^nWCJwHROX&Ov!?oeEn2g*wAiok8#>fqJcOwX?3Q}OwuT(fmTKo^g+8Qpr&y(!Wl+kV_k-WW*dQ&%VOVk@3k6- zA{NCkk)(}YS@CzIGF0jhsf_BDOaiJ{2c(*S0{IIvLZltTh~?HNafAO6x;u40Mo8kP zF6FEe$zWQRqKD?Nzn3HRJoY$_9h5!$8yv|qC^X5|4X|&pcEbiwZ^%utfF{Vt9Fmu# z9`Oh#UjXoPm=ERyFmaK}p>xm3`JsfE2RisSC6)lErh*y6?RHKqvsZ+GZg=iD?qI@W zua6Mz*zn(CP(moC;mr|!7)xq&eC*=Aix}R-A=T&~Q6VqcFC!&}w^lJj^aYY+N-3ZW zGACltdZuOyr-DQoTn7MY7nu~)z>keD*9bt!iDYKqsANssWKP;ugjpI> zW4wx<66Llaaio7?;AddqWf=Ioxq<6b^AjyHVB}`fO(~mYOSxBjwfTL=OnCE%=_&w| zUYl@7lyVL!{jabSc;?5I+o-O;m>Tokl!Lhe+P!`GSr` za~&5gk1EP_Ll^A%JM5DwxA32`K$V z^g*RjLd}73vPIFv+*k{80iy9%f-KSEn}^ISNHgX?#l+uD5BNP?`ga_;iBiB16FsCT zN4d1!ZnyalF?^E~nzY-575LZWgjW1nDjX_qQ}H1ccd4KkPzXuXh(Dl$d=4kHQ}#lN zD*3y7r6pMtekm_?5jA>_ghtySFHyNvDccphX;)F2IG?mjm9uu8)7Z@go{+y^=x&Ba zs&Si1hMs)Lj1+z!q~rqiMAyeP2A480r$(-`7IgMzuCvzE$aNM`c4lCEK2-DYE@hzy z#e>q+1fey1Ha4ihO6Vz1E%aEuO1@=w`(B4!$#^)1De)^U*PxOF_EjRt) zxK$NTxtn+H-r8{A*=TRv-NGl6_B&hc4N2$4+U_VEq~V+oO5UCz8j^{{UC?5L0lbH& z;oMJb;gd^| z2gzuV@`(DRS|9564fOpFjyz;gvZ0caZ=9|k!3~-@Hdn*SX%lz44MBqrkxYRqc12bln_^mRTy3#I+*;|^k%eU z^ef>YFqCh04Wlw`h@FE|*2WFmJ^GX(&5F353A4I7cLm!>{$)CU4Q|+s8mWcP0*DVN zku^0Rv&=yBup^x?df?6}h`tSzqE?CAax$5>NE`U=@fq5G9OWJyOJFHmor(+z_qV$L7e}(6NMJZ6wh~i{=YY-r_Ga7#HHX=>K z1Nf~l+M{#~5+?W#PKmZKl^GS85ogW=W%w_w|IELd#M1|khr|oMzR{U9 zoG+oFR5{aQGiw;V`pU$@H+MEMk(>sjrnpE!h`scm z73}Z$?ko|MVu|NyDKckCOEAFOjG`e0zCZ)AJvyY#T}5S1%Vf?(=T~GKQTI%*X|k0k z-4EHrP28n6XqRe#i$d5GszTNY$iBoYdFiO&C6#)KUXl2^1~6aMWgqUL9`yk$|Bhv} zH(M9v@}&;(AJG7E#li?<$tmP#BlY#FfX~%2S9#w*q%kKK{}*F@@n11G!Htq?oyOSP z_;3{MZQW7ayY%BRk{(-kL{TL=B_-g$pnJ&ONUT#jO&BJ3UP@N3U`fRm7%l8KRHo$y od8gzB6j!ij{L#kf6?|W@3$#V6rRLAIH!Z_Hg`= 3 + bi = PyImport_ImportModule("builtins"); +#else + bi = PyImport_ImportModule("__builtin__"); +#endif + if (bi == NULL) + goto error; + PyDict_SetItemString(result, "__builtins__", bi); + Py_DECREF(bi); + + x = PyRun_String( + "import sys\n" + "class FileLike:\n" + " def write(self, x):\n" + " try:\n" + " of.write(x)\n" + " except: pass\n" + " self.buf += x\n" + "fl = FileLike()\n" + "fl.buf = ''\n" + "of = sys.stderr\n" + "sys.stderr = fl\n" + "def done():\n" + " sys.stderr = of\n" + " return fl.buf\n", /* make sure the returned value stays alive */ + Py_file_input, + result, result); + Py_XDECREF(x); + + error: + if (PyErr_Occurred()) + { + PyErr_WriteUnraisable(Py_None); + PyErr_Clear(); + } + return result; +} + +#pragma comment(lib, "user32.lib") + +static DWORD WINAPI _cffi_bootstrap_dialog(LPVOID ignored) +{ + Sleep(666); /* may be interrupted if the whole process is closing */ +#if PY_MAJOR_VERSION >= 3 + MessageBoxW(NULL, (wchar_t *)_cffi_bootstrap_text, + L"Python-CFFI error", + MB_OK | MB_ICONERROR); +#else + MessageBoxA(NULL, (char *)_cffi_bootstrap_text, + "Python-CFFI error", + MB_OK | MB_ICONERROR); +#endif + _cffi_bootstrap_text = NULL; + return 0; +} + +static void _cffi_stop_error_capture(PyObject *ecap) +{ + PyObject *s; + void *text; + + if (ecap == (PyObject *)1) + return; + + if (ecap == NULL) + goto error; + + s = PyRun_String("done()", Py_eval_input, ecap, ecap); + if (s == NULL) + goto error; + + /* Show a dialog box, but in a background thread, and + never show multiple dialog boxes at once. */ +#if PY_MAJOR_VERSION >= 3 + text = PyUnicode_AsWideCharString(s, NULL); +#else + text = PyString_AsString(s); +#endif + + _cffi_bootstrap_text = text; + + if (text != NULL) + { + HANDLE h; + h = CreateThread(NULL, 0, _cffi_bootstrap_dialog, + NULL, 0, NULL); + if (h != NULL) + CloseHandle(h); + } + /* decref the string, but it should stay alive as 'fl.buf' + in the small module above. It will really be freed only if + we later get another similar error. So it's a leak of at + most one copy of the small module. That's fine for this + situation which is usually a "fatal error" anyway. */ + Py_DECREF(s); + PyErr_Clear(); + return; + + error: + _cffi_bootstrap_text = NULL; + PyErr_Clear(); +} + +#else + +static PyObject *_cffi_start_error_capture(void) { return NULL; } +static void _cffi_stop_error_capture(PyObject *ecap) { } + +#endif diff --git a/venv/Lib/site-packages/cffi/_cffi_include.h b/venv/Lib/site-packages/cffi/_cffi_include.h new file mode 100644 index 000000000..e4c0a6724 --- /dev/null +++ b/venv/Lib/site-packages/cffi/_cffi_include.h @@ -0,0 +1,385 @@ +#define _CFFI_ + +/* We try to define Py_LIMITED_API before including Python.h. + + Mess: we can only define it if Py_DEBUG, Py_TRACE_REFS and + Py_REF_DEBUG are not defined. This is a best-effort approximation: + we can learn about Py_DEBUG from pyconfig.h, but it is unclear if + the same works for the other two macros. Py_DEBUG implies them, + but not the other way around. + + The implementation is messy (issue #350): on Windows, with _MSC_VER, + we have to define Py_LIMITED_API even before including pyconfig.h. + In that case, we guess what pyconfig.h will do to the macros above, + and check our guess after the #include. + + Note that on Windows, with CPython 3.x, you need >= 3.5 and virtualenv + version >= 16.0.0. With older versions of either, you don't get a + copy of PYTHON3.DLL in the virtualenv. We can't check the version of + CPython *before* we even include pyconfig.h. ffi.set_source() puts + a ``#define _CFFI_NO_LIMITED_API'' at the start of this file if it is + running on Windows < 3.5, as an attempt at fixing it, but that's + arguably wrong because it may not be the target version of Python. + Still better than nothing I guess. As another workaround, you can + remove the definition of Py_LIMITED_API here. + + See also 'py_limited_api' in cffi/setuptools_ext.py. +*/ +#if !defined(_CFFI_USE_EMBEDDING) && !defined(Py_LIMITED_API) +# ifdef _MSC_VER +# if !defined(_DEBUG) && !defined(Py_DEBUG) && !defined(Py_TRACE_REFS) && !defined(Py_REF_DEBUG) && !defined(_CFFI_NO_LIMITED_API) +# define Py_LIMITED_API +# endif +# include + /* sanity-check: Py_LIMITED_API will cause crashes if any of these + are also defined. Normally, the Python file PC/pyconfig.h does not + cause any of these to be defined, with the exception that _DEBUG + causes Py_DEBUG. Double-check that. */ +# ifdef Py_LIMITED_API +# if defined(Py_DEBUG) +# error "pyconfig.h unexpectedly defines Py_DEBUG, but Py_LIMITED_API is set" +# endif +# if defined(Py_TRACE_REFS) +# error "pyconfig.h unexpectedly defines Py_TRACE_REFS, but Py_LIMITED_API is set" +# endif +# if defined(Py_REF_DEBUG) +# error "pyconfig.h unexpectedly defines Py_REF_DEBUG, but Py_LIMITED_API is set" +# endif +# endif +# else +# include +# if !defined(Py_DEBUG) && !defined(Py_TRACE_REFS) && !defined(Py_REF_DEBUG) && !defined(_CFFI_NO_LIMITED_API) +# define Py_LIMITED_API +# endif +# endif +#endif + +#include +#ifdef __cplusplus +extern "C" { +#endif +#include +#include "parse_c_type.h" + +/* this block of #ifs should be kept exactly identical between + c/_cffi_backend.c, cffi/vengine_cpy.py, cffi/vengine_gen.py + and cffi/_cffi_include.h */ +#if defined(_MSC_VER) +# include /* for alloca() */ +# if _MSC_VER < 1600 /* MSVC < 2010 */ + typedef __int8 int8_t; + typedef __int16 int16_t; + typedef __int32 int32_t; + typedef __int64 int64_t; + typedef unsigned __int8 uint8_t; + typedef unsigned __int16 uint16_t; + typedef unsigned __int32 uint32_t; + typedef unsigned __int64 uint64_t; + typedef __int8 int_least8_t; + typedef __int16 int_least16_t; + typedef __int32 int_least32_t; + typedef __int64 int_least64_t; + typedef unsigned __int8 uint_least8_t; + typedef unsigned __int16 uint_least16_t; + typedef unsigned __int32 uint_least32_t; + typedef unsigned __int64 uint_least64_t; + typedef __int8 int_fast8_t; + typedef __int16 int_fast16_t; + typedef __int32 int_fast32_t; + typedef __int64 int_fast64_t; + typedef unsigned __int8 uint_fast8_t; + typedef unsigned __int16 uint_fast16_t; + typedef unsigned __int32 uint_fast32_t; + typedef unsigned __int64 uint_fast64_t; + typedef __int64 intmax_t; + typedef unsigned __int64 uintmax_t; +# else +# include +# endif +# if _MSC_VER < 1800 /* MSVC < 2013 */ +# ifndef __cplusplus + typedef unsigned char _Bool; +# endif +# endif +#else +# include +# if (defined (__SVR4) && defined (__sun)) || defined(_AIX) || defined(__hpux) +# include +# endif +#endif + +#ifdef __GNUC__ +# define _CFFI_UNUSED_FN __attribute__((unused)) +#else +# define _CFFI_UNUSED_FN /* nothing */ +#endif + +#ifdef __cplusplus +# ifndef _Bool + typedef bool _Bool; /* semi-hackish: C++ has no _Bool; bool is builtin */ +# endif +#endif + +/********** CPython-specific section **********/ +#ifndef PYPY_VERSION + + +#if PY_MAJOR_VERSION >= 3 +# define PyInt_FromLong PyLong_FromLong +#endif + +#define _cffi_from_c_double PyFloat_FromDouble +#define _cffi_from_c_float PyFloat_FromDouble +#define _cffi_from_c_long PyInt_FromLong +#define _cffi_from_c_ulong PyLong_FromUnsignedLong +#define _cffi_from_c_longlong PyLong_FromLongLong +#define _cffi_from_c_ulonglong PyLong_FromUnsignedLongLong +#define _cffi_from_c__Bool PyBool_FromLong + +#define _cffi_to_c_double PyFloat_AsDouble +#define _cffi_to_c_float PyFloat_AsDouble + +#define _cffi_from_c_int(x, type) \ + (((type)-1) > 0 ? /* unsigned */ \ + (sizeof(type) < sizeof(long) ? \ + PyInt_FromLong((long)x) : \ + sizeof(type) == sizeof(long) ? \ + PyLong_FromUnsignedLong((unsigned long)x) : \ + PyLong_FromUnsignedLongLong((unsigned long long)x)) : \ + (sizeof(type) <= sizeof(long) ? \ + PyInt_FromLong((long)x) : \ + PyLong_FromLongLong((long long)x))) + +#define _cffi_to_c_int(o, type) \ + ((type)( \ + sizeof(type) == 1 ? (((type)-1) > 0 ? (type)_cffi_to_c_u8(o) \ + : (type)_cffi_to_c_i8(o)) : \ + sizeof(type) == 2 ? (((type)-1) > 0 ? (type)_cffi_to_c_u16(o) \ + : (type)_cffi_to_c_i16(o)) : \ + sizeof(type) == 4 ? (((type)-1) > 0 ? (type)_cffi_to_c_u32(o) \ + : (type)_cffi_to_c_i32(o)) : \ + sizeof(type) == 8 ? (((type)-1) > 0 ? (type)_cffi_to_c_u64(o) \ + : (type)_cffi_to_c_i64(o)) : \ + (Py_FatalError("unsupported size for type " #type), (type)0))) + +#define _cffi_to_c_i8 \ + ((int(*)(PyObject *))_cffi_exports[1]) +#define _cffi_to_c_u8 \ + ((int(*)(PyObject *))_cffi_exports[2]) +#define _cffi_to_c_i16 \ + ((int(*)(PyObject *))_cffi_exports[3]) +#define _cffi_to_c_u16 \ + ((int(*)(PyObject *))_cffi_exports[4]) +#define _cffi_to_c_i32 \ + ((int(*)(PyObject *))_cffi_exports[5]) +#define _cffi_to_c_u32 \ + ((unsigned int(*)(PyObject *))_cffi_exports[6]) +#define _cffi_to_c_i64 \ + ((long long(*)(PyObject *))_cffi_exports[7]) +#define _cffi_to_c_u64 \ + ((unsigned long long(*)(PyObject *))_cffi_exports[8]) +#define _cffi_to_c_char \ + ((int(*)(PyObject *))_cffi_exports[9]) +#define _cffi_from_c_pointer \ + ((PyObject *(*)(char *, struct _cffi_ctypedescr *))_cffi_exports[10]) +#define _cffi_to_c_pointer \ + ((char *(*)(PyObject *, struct _cffi_ctypedescr *))_cffi_exports[11]) +#define _cffi_get_struct_layout \ + not used any more +#define _cffi_restore_errno \ + ((void(*)(void))_cffi_exports[13]) +#define _cffi_save_errno \ + ((void(*)(void))_cffi_exports[14]) +#define _cffi_from_c_char \ + ((PyObject *(*)(char))_cffi_exports[15]) +#define _cffi_from_c_deref \ + ((PyObject *(*)(char *, struct _cffi_ctypedescr *))_cffi_exports[16]) +#define _cffi_to_c \ + ((int(*)(char *, struct _cffi_ctypedescr *, PyObject *))_cffi_exports[17]) +#define _cffi_from_c_struct \ + ((PyObject *(*)(char *, struct _cffi_ctypedescr *))_cffi_exports[18]) +#define _cffi_to_c_wchar_t \ + ((_cffi_wchar_t(*)(PyObject *))_cffi_exports[19]) +#define _cffi_from_c_wchar_t \ + ((PyObject *(*)(_cffi_wchar_t))_cffi_exports[20]) +#define _cffi_to_c_long_double \ + ((long double(*)(PyObject *))_cffi_exports[21]) +#define _cffi_to_c__Bool \ + ((_Bool(*)(PyObject *))_cffi_exports[22]) +#define _cffi_prepare_pointer_call_argument \ + ((Py_ssize_t(*)(struct _cffi_ctypedescr *, \ + PyObject *, char **))_cffi_exports[23]) +#define _cffi_convert_array_from_object \ + ((int(*)(char *, struct _cffi_ctypedescr *, PyObject *))_cffi_exports[24]) +#define _CFFI_CPIDX 25 +#define _cffi_call_python \ + ((void(*)(struct _cffi_externpy_s *, char *))_cffi_exports[_CFFI_CPIDX]) +#define _cffi_to_c_wchar3216_t \ + ((int(*)(PyObject *))_cffi_exports[26]) +#define _cffi_from_c_wchar3216_t \ + ((PyObject *(*)(int))_cffi_exports[27]) +#define _CFFI_NUM_EXPORTS 28 + +struct _cffi_ctypedescr; + +static void *_cffi_exports[_CFFI_NUM_EXPORTS]; + +#define _cffi_type(index) ( \ + assert((((uintptr_t)_cffi_types[index]) & 1) == 0), \ + (struct _cffi_ctypedescr *)_cffi_types[index]) + +static PyObject *_cffi_init(const char *module_name, Py_ssize_t version, + const struct _cffi_type_context_s *ctx) +{ + PyObject *module, *o_arg, *new_module; + void *raw[] = { + (void *)module_name, + (void *)version, + (void *)_cffi_exports, + (void *)ctx, + }; + + module = PyImport_ImportModule("_cffi_backend"); + if (module == NULL) + goto failure; + + o_arg = PyLong_FromVoidPtr((void *)raw); + if (o_arg == NULL) + goto failure; + + new_module = PyObject_CallMethod( + module, (char *)"_init_cffi_1_0_external_module", (char *)"O", o_arg); + + Py_DECREF(o_arg); + Py_DECREF(module); + return new_module; + + failure: + Py_XDECREF(module); + return NULL; +} + + +#ifdef HAVE_WCHAR_H +typedef wchar_t _cffi_wchar_t; +#else +typedef uint16_t _cffi_wchar_t; /* same random pick as _cffi_backend.c */ +#endif + +_CFFI_UNUSED_FN static uint16_t _cffi_to_c_char16_t(PyObject *o) +{ + if (sizeof(_cffi_wchar_t) == 2) + return (uint16_t)_cffi_to_c_wchar_t(o); + else + return (uint16_t)_cffi_to_c_wchar3216_t(o); +} + +_CFFI_UNUSED_FN static PyObject *_cffi_from_c_char16_t(uint16_t x) +{ + if (sizeof(_cffi_wchar_t) == 2) + return _cffi_from_c_wchar_t((_cffi_wchar_t)x); + else + return _cffi_from_c_wchar3216_t((int)x); +} + +_CFFI_UNUSED_FN static int _cffi_to_c_char32_t(PyObject *o) +{ + if (sizeof(_cffi_wchar_t) == 4) + return (int)_cffi_to_c_wchar_t(o); + else + return (int)_cffi_to_c_wchar3216_t(o); +} + +_CFFI_UNUSED_FN static PyObject *_cffi_from_c_char32_t(unsigned int x) +{ + if (sizeof(_cffi_wchar_t) == 4) + return _cffi_from_c_wchar_t((_cffi_wchar_t)x); + else + return _cffi_from_c_wchar3216_t((int)x); +} + +union _cffi_union_alignment_u { + unsigned char m_char; + unsigned short m_short; + unsigned int m_int; + unsigned long m_long; + unsigned long long m_longlong; + float m_float; + double m_double; + long double m_longdouble; +}; + +struct _cffi_freeme_s { + struct _cffi_freeme_s *next; + union _cffi_union_alignment_u alignment; +}; + +_CFFI_UNUSED_FN static int +_cffi_convert_array_argument(struct _cffi_ctypedescr *ctptr, PyObject *arg, + char **output_data, Py_ssize_t datasize, + struct _cffi_freeme_s **freeme) +{ + char *p; + if (datasize < 0) + return -1; + + p = *output_data; + if (p == NULL) { + struct _cffi_freeme_s *fp = (struct _cffi_freeme_s *)PyObject_Malloc( + offsetof(struct _cffi_freeme_s, alignment) + (size_t)datasize); + if (fp == NULL) + return -1; + fp->next = *freeme; + *freeme = fp; + p = *output_data = (char *)&fp->alignment; + } + memset((void *)p, 0, (size_t)datasize); + return _cffi_convert_array_from_object(p, ctptr, arg); +} + +_CFFI_UNUSED_FN static void +_cffi_free_array_arguments(struct _cffi_freeme_s *freeme) +{ + do { + void *p = (void *)freeme; + freeme = freeme->next; + PyObject_Free(p); + } while (freeme != NULL); +} + +/********** end CPython-specific section **********/ +#else +_CFFI_UNUSED_FN +static void (*_cffi_call_python_org)(struct _cffi_externpy_s *, char *); +# define _cffi_call_python _cffi_call_python_org +#endif + + +#define _cffi_array_len(array) (sizeof(array) / sizeof((array)[0])) + +#define _cffi_prim_int(size, sign) \ + ((size) == 1 ? ((sign) ? _CFFI_PRIM_INT8 : _CFFI_PRIM_UINT8) : \ + (size) == 2 ? ((sign) ? _CFFI_PRIM_INT16 : _CFFI_PRIM_UINT16) : \ + (size) == 4 ? ((sign) ? _CFFI_PRIM_INT32 : _CFFI_PRIM_UINT32) : \ + (size) == 8 ? ((sign) ? _CFFI_PRIM_INT64 : _CFFI_PRIM_UINT64) : \ + _CFFI__UNKNOWN_PRIM) + +#define _cffi_prim_float(size) \ + ((size) == sizeof(float) ? _CFFI_PRIM_FLOAT : \ + (size) == sizeof(double) ? _CFFI_PRIM_DOUBLE : \ + (size) == sizeof(long double) ? _CFFI__UNKNOWN_LONG_DOUBLE : \ + _CFFI__UNKNOWN_FLOAT_PRIM) + +#define _cffi_check_int(got, got_nonpos, expected) \ + ((got_nonpos) == (expected <= 0) && \ + (got) == (unsigned long long)expected) + +#ifdef MS_WIN32 +# define _cffi_stdcall __stdcall +#else +# define _cffi_stdcall /* nothing */ +#endif + +#ifdef __cplusplus +} +#endif diff --git a/venv/Lib/site-packages/cffi/_embedding.h b/venv/Lib/site-packages/cffi/_embedding.h new file mode 100644 index 000000000..fdce22286 --- /dev/null +++ b/venv/Lib/site-packages/cffi/_embedding.h @@ -0,0 +1,527 @@ + +/***** Support code for embedding *****/ + +#ifdef __cplusplus +extern "C" { +#endif + + +#if defined(_WIN32) +# define CFFI_DLLEXPORT __declspec(dllexport) +#elif defined(__GNUC__) +# define CFFI_DLLEXPORT __attribute__((visibility("default"))) +#else +# define CFFI_DLLEXPORT /* nothing */ +#endif + + +/* There are two global variables of type _cffi_call_python_fnptr: + + * _cffi_call_python, which we declare just below, is the one called + by ``extern "Python"`` implementations. + + * _cffi_call_python_org, which on CPython is actually part of the + _cffi_exports[] array, is the function pointer copied from + _cffi_backend. + + After initialization is complete, both are equal. However, the + first one remains equal to &_cffi_start_and_call_python until the + very end of initialization, when we are (or should be) sure that + concurrent threads also see a completely initialized world, and + only then is it changed. +*/ +#undef _cffi_call_python +typedef void (*_cffi_call_python_fnptr)(struct _cffi_externpy_s *, char *); +static void _cffi_start_and_call_python(struct _cffi_externpy_s *, char *); +static _cffi_call_python_fnptr _cffi_call_python = &_cffi_start_and_call_python; + + +#ifndef _MSC_VER + /* --- Assuming a GCC not infinitely old --- */ +# define cffi_compare_and_swap(l,o,n) __sync_bool_compare_and_swap(l,o,n) +# define cffi_write_barrier() __sync_synchronize() +# if !defined(__amd64__) && !defined(__x86_64__) && \ + !defined(__i386__) && !defined(__i386) +# define cffi_read_barrier() __sync_synchronize() +# else +# define cffi_read_barrier() (void)0 +# endif +#else + /* --- Windows threads version --- */ +# include +# define cffi_compare_and_swap(l,o,n) \ + (InterlockedCompareExchangePointer(l,n,o) == (o)) +# define cffi_write_barrier() InterlockedCompareExchange(&_cffi_dummy,0,0) +# define cffi_read_barrier() (void)0 +static volatile LONG _cffi_dummy; +#endif + +#ifdef WITH_THREAD +# ifndef _MSC_VER +# include + static pthread_mutex_t _cffi_embed_startup_lock; +# else + static CRITICAL_SECTION _cffi_embed_startup_lock; +# endif + static char _cffi_embed_startup_lock_ready = 0; +#endif + +static void _cffi_acquire_reentrant_mutex(void) +{ + static void *volatile lock = NULL; + + while (!cffi_compare_and_swap(&lock, NULL, (void *)1)) { + /* should ideally do a spin loop instruction here, but + hard to do it portably and doesn't really matter I + think: pthread_mutex_init() should be very fast, and + this is only run at start-up anyway. */ + } + +#ifdef WITH_THREAD + if (!_cffi_embed_startup_lock_ready) { +# ifndef _MSC_VER + pthread_mutexattr_t attr; + pthread_mutexattr_init(&attr); + pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE); + pthread_mutex_init(&_cffi_embed_startup_lock, &attr); +# else + InitializeCriticalSection(&_cffi_embed_startup_lock); +# endif + _cffi_embed_startup_lock_ready = 1; + } +#endif + + while (!cffi_compare_and_swap(&lock, (void *)1, NULL)) + ; + +#ifndef _MSC_VER + pthread_mutex_lock(&_cffi_embed_startup_lock); +#else + EnterCriticalSection(&_cffi_embed_startup_lock); +#endif +} + +static void _cffi_release_reentrant_mutex(void) +{ +#ifndef _MSC_VER + pthread_mutex_unlock(&_cffi_embed_startup_lock); +#else + LeaveCriticalSection(&_cffi_embed_startup_lock); +#endif +} + + +/********** CPython-specific section **********/ +#ifndef PYPY_VERSION + +#include "_cffi_errors.h" + + +#define _cffi_call_python_org _cffi_exports[_CFFI_CPIDX] + +PyMODINIT_FUNC _CFFI_PYTHON_STARTUP_FUNC(void); /* forward */ + +static void _cffi_py_initialize(void) +{ + /* XXX use initsigs=0, which "skips initialization registration of + signal handlers, which might be useful when Python is + embedded" according to the Python docs. But review and think + if it should be a user-controllable setting. + + XXX we should also give a way to write errors to a buffer + instead of to stderr. + + XXX if importing 'site' fails, CPython (any version) calls + exit(). Should we try to work around this behavior here? + */ + Py_InitializeEx(0); +} + +static int _cffi_initialize_python(void) +{ + /* This initializes Python, imports _cffi_backend, and then the + present .dll/.so is set up as a CPython C extension module. + */ + int result; + PyGILState_STATE state; + PyObject *pycode=NULL, *global_dict=NULL, *x; + PyObject *builtins; + + state = PyGILState_Ensure(); + + /* Call the initxxx() function from the present module. It will + create and initialize us as a CPython extension module, instead + of letting the startup Python code do it---it might reimport + the same .dll/.so and get maybe confused on some platforms. + It might also have troubles locating the .dll/.so again for all + I know. + */ + (void)_CFFI_PYTHON_STARTUP_FUNC(); + if (PyErr_Occurred()) + goto error; + + /* Now run the Python code provided to ffi.embedding_init_code(). + */ + pycode = Py_CompileString(_CFFI_PYTHON_STARTUP_CODE, + "", + Py_file_input); + if (pycode == NULL) + goto error; + global_dict = PyDict_New(); + if (global_dict == NULL) + goto error; + builtins = PyEval_GetBuiltins(); + if (builtins == NULL) + goto error; + if (PyDict_SetItemString(global_dict, "__builtins__", builtins) < 0) + goto error; + x = PyEval_EvalCode( +#if PY_MAJOR_VERSION < 3 + (PyCodeObject *) +#endif + pycode, global_dict, global_dict); + if (x == NULL) + goto error; + Py_DECREF(x); + + /* Done! Now if we've been called from + _cffi_start_and_call_python() in an ``extern "Python"``, we can + only hope that the Python code did correctly set up the + corresponding @ffi.def_extern() function. Otherwise, the + general logic of ``extern "Python"`` functions (inside the + _cffi_backend module) will find that the reference is still + missing and print an error. + */ + result = 0; + done: + Py_XDECREF(pycode); + Py_XDECREF(global_dict); + PyGILState_Release(state); + return result; + + error:; + { + /* Print as much information as potentially useful. + Debugging load-time failures with embedding is not fun + */ + PyObject *ecap; + PyObject *exception, *v, *tb, *f, *modules, *mod; + PyErr_Fetch(&exception, &v, &tb); + ecap = _cffi_start_error_capture(); + f = PySys_GetObject((char *)"stderr"); + if (f != NULL && f != Py_None) { + PyFile_WriteString( + "Failed to initialize the Python-CFFI embedding logic:\n\n", f); + } + + if (exception != NULL) { + PyErr_NormalizeException(&exception, &v, &tb); + PyErr_Display(exception, v, tb); + } + Py_XDECREF(exception); + Py_XDECREF(v); + Py_XDECREF(tb); + + if (f != NULL && f != Py_None) { + PyFile_WriteString("\nFrom: " _CFFI_MODULE_NAME + "\ncompiled with cffi version: 1.14.3" + "\n_cffi_backend module: ", f); + modules = PyImport_GetModuleDict(); + mod = PyDict_GetItemString(modules, "_cffi_backend"); + if (mod == NULL) { + PyFile_WriteString("not loaded", f); + } + else { + v = PyObject_GetAttrString(mod, "__file__"); + PyFile_WriteObject(v, f, 0); + Py_XDECREF(v); + } + PyFile_WriteString("\nsys.path: ", f); + PyFile_WriteObject(PySys_GetObject((char *)"path"), f, 0); + PyFile_WriteString("\n\n", f); + } + _cffi_stop_error_capture(ecap); + } + result = -1; + goto done; +} + +#if PY_VERSION_HEX < 0x03080000 +PyAPI_DATA(char *) _PyParser_TokenNames[]; /* from CPython */ +#endif + +static int _cffi_carefully_make_gil(void) +{ + /* This does the basic initialization of Python. It can be called + completely concurrently from unrelated threads. It assumes + that we don't hold the GIL before (if it exists), and we don't + hold it afterwards. + + (What it really does used to be completely different in Python 2 + and Python 3, with the Python 2 solution avoiding the spin-lock + around the Py_InitializeEx() call. However, after recent changes + to CPython 2.7 (issue #358) it no longer works. So we use the + Python 3 solution everywhere.) + + This initializes Python by calling Py_InitializeEx(). + Important: this must not be called concurrently at all. + So we use a global variable as a simple spin lock. This global + variable must be from 'libpythonX.Y.so', not from this + cffi-based extension module, because it must be shared from + different cffi-based extension modules. + + In Python < 3.8, we choose + _PyParser_TokenNames[0] as a completely arbitrary pointer value + that is never written to. The default is to point to the + string "ENDMARKER". We change it temporarily to point to the + next character in that string. (Yes, I know it's REALLY + obscure.) + + In Python >= 3.8, this string array is no longer writable, so + instead we pick PyCapsuleType.tp_version_tag. We can't change + Python < 3.8 because someone might use a mixture of cffi + embedded modules, some of which were compiled before this file + changed. + */ + +#ifdef WITH_THREAD +# if PY_VERSION_HEX < 0x03080000 + char *volatile *lock = (char *volatile *)_PyParser_TokenNames; + char *old_value, *locked_value; + + while (1) { /* spin loop */ + old_value = *lock; + locked_value = old_value + 1; + if (old_value[0] == 'E') { + assert(old_value[1] == 'N'); + if (cffi_compare_and_swap(lock, old_value, locked_value)) + break; + } + else { + assert(old_value[0] == 'N'); + /* should ideally do a spin loop instruction here, but + hard to do it portably and doesn't really matter I + think: PyEval_InitThreads() should be very fast, and + this is only run at start-up anyway. */ + } + } +# else + int volatile *lock = (int volatile *)&PyCapsule_Type.tp_version_tag; + int old_value, locked_value; + assert(!(PyCapsule_Type.tp_flags & Py_TPFLAGS_HAVE_VERSION_TAG)); + + while (1) { /* spin loop */ + old_value = *lock; + locked_value = -42; + if (old_value == 0) { + if (cffi_compare_and_swap(lock, old_value, locked_value)) + break; + } + else { + assert(old_value == locked_value); + /* should ideally do a spin loop instruction here, but + hard to do it portably and doesn't really matter I + think: PyEval_InitThreads() should be very fast, and + this is only run at start-up anyway. */ + } + } +# endif +#endif + + /* call Py_InitializeEx() */ + if (!Py_IsInitialized()) { + _cffi_py_initialize(); +#if PY_VERSION_HEX < 0x03070000 + PyEval_InitThreads(); +#endif + PyEval_SaveThread(); /* release the GIL */ + /* the returned tstate must be the one that has been stored into the + autoTLSkey by _PyGILState_Init() called from Py_Initialize(). */ + } + else { +#if PY_VERSION_HEX < 0x03070000 + /* PyEval_InitThreads() is always a no-op from CPython 3.7 */ + PyGILState_STATE state = PyGILState_Ensure(); + PyEval_InitThreads(); + PyGILState_Release(state); +#endif + } + +#ifdef WITH_THREAD + /* release the lock */ + while (!cffi_compare_and_swap(lock, locked_value, old_value)) + ; +#endif + + return 0; +} + +/********** end CPython-specific section **********/ + + +#else + + +/********** PyPy-specific section **********/ + +PyMODINIT_FUNC _CFFI_PYTHON_STARTUP_FUNC(const void *[]); /* forward */ + +static struct _cffi_pypy_init_s { + const char *name; + void *func; /* function pointer */ + const char *code; +} _cffi_pypy_init = { + _CFFI_MODULE_NAME, + _CFFI_PYTHON_STARTUP_FUNC, + _CFFI_PYTHON_STARTUP_CODE, +}; + +extern int pypy_carefully_make_gil(const char *); +extern int pypy_init_embedded_cffi_module(int, struct _cffi_pypy_init_s *); + +static int _cffi_carefully_make_gil(void) +{ + return pypy_carefully_make_gil(_CFFI_MODULE_NAME); +} + +static int _cffi_initialize_python(void) +{ + return pypy_init_embedded_cffi_module(0xB011, &_cffi_pypy_init); +} + +/********** end PyPy-specific section **********/ + + +#endif + + +#ifdef __GNUC__ +__attribute__((noinline)) +#endif +static _cffi_call_python_fnptr _cffi_start_python(void) +{ + /* Delicate logic to initialize Python. This function can be + called multiple times concurrently, e.g. when the process calls + its first ``extern "Python"`` functions in multiple threads at + once. It can also be called recursively, in which case we must + ignore it. We also have to consider what occurs if several + different cffi-based extensions reach this code in parallel + threads---it is a different copy of the code, then, and we + can't have any shared global variable unless it comes from + 'libpythonX.Y.so'. + + Idea: + + * _cffi_carefully_make_gil(): "carefully" call + PyEval_InitThreads() (possibly with Py_InitializeEx() first). + + * then we use a (local) custom lock to make sure that a call to this + cffi-based extension will wait if another call to the *same* + extension is running the initialization in another thread. + It is reentrant, so that a recursive call will not block, but + only one from a different thread. + + * then we grab the GIL and (Python 2) we call Py_InitializeEx(). + At this point, concurrent calls to Py_InitializeEx() are not + possible: we have the GIL. + + * do the rest of the specific initialization, which may + temporarily release the GIL but not the custom lock. + Only release the custom lock when we are done. + */ + static char called = 0; + + if (_cffi_carefully_make_gil() != 0) + return NULL; + + _cffi_acquire_reentrant_mutex(); + + /* Here the GIL exists, but we don't have it. We're only protected + from concurrency by the reentrant mutex. */ + + /* This file only initializes the embedded module once, the first + time this is called, even if there are subinterpreters. */ + if (!called) { + called = 1; /* invoke _cffi_initialize_python() only once, + but don't set '_cffi_call_python' right now, + otherwise concurrent threads won't call + this function at all (we need them to wait) */ + if (_cffi_initialize_python() == 0) { + /* now initialization is finished. Switch to the fast-path. */ + + /* We would like nobody to see the new value of + '_cffi_call_python' without also seeing the rest of the + data initialized. However, this is not possible. But + the new value of '_cffi_call_python' is the function + 'cffi_call_python()' from _cffi_backend. So: */ + cffi_write_barrier(); + /* ^^^ we put a write barrier here, and a corresponding + read barrier at the start of cffi_call_python(). This + ensures that after that read barrier, we see everything + done here before the write barrier. + */ + + assert(_cffi_call_python_org != NULL); + _cffi_call_python = (_cffi_call_python_fnptr)_cffi_call_python_org; + } + else { + /* initialization failed. Reset this to NULL, even if it was + already set to some other value. Future calls to + _cffi_start_python() are still forced to occur, and will + always return NULL from now on. */ + _cffi_call_python_org = NULL; + } + } + + _cffi_release_reentrant_mutex(); + + return (_cffi_call_python_fnptr)_cffi_call_python_org; +} + +static +void _cffi_start_and_call_python(struct _cffi_externpy_s *externpy, char *args) +{ + _cffi_call_python_fnptr fnptr; + int current_err = errno; +#ifdef _MSC_VER + int current_lasterr = GetLastError(); +#endif + fnptr = _cffi_start_python(); + if (fnptr == NULL) { + fprintf(stderr, "function %s() called, but initialization code " + "failed. Returning 0.\n", externpy->name); + memset(args, 0, externpy->size_of_result); + } +#ifdef _MSC_VER + SetLastError(current_lasterr); +#endif + errno = current_err; + + if (fnptr != NULL) + fnptr(externpy, args); +} + + +/* The cffi_start_python() function makes sure Python is initialized + and our cffi module is set up. It can be called manually from the + user C code. The same effect is obtained automatically from any + dll-exported ``extern "Python"`` function. This function returns + -1 if initialization failed, 0 if all is OK. */ +_CFFI_UNUSED_FN +static int cffi_start_python(void) +{ + if (_cffi_call_python == &_cffi_start_and_call_python) { + if (_cffi_start_python() == NULL) + return -1; + } + cffi_read_barrier(); + return 0; +} + +#undef cffi_compare_and_swap +#undef cffi_write_barrier +#undef cffi_read_barrier + +#ifdef __cplusplus +} +#endif diff --git a/venv/Lib/site-packages/cffi/api.py b/venv/Lib/site-packages/cffi/api.py new file mode 100644 index 000000000..999a8aefc --- /dev/null +++ b/venv/Lib/site-packages/cffi/api.py @@ -0,0 +1,965 @@ +import sys, types +from .lock import allocate_lock +from .error import CDefError +from . import model + +try: + callable +except NameError: + # Python 3.1 + from collections import Callable + callable = lambda x: isinstance(x, Callable) + +try: + basestring +except NameError: + # Python 3.x + basestring = str + +_unspecified = object() + + + +class FFI(object): + r''' + The main top-level class that you instantiate once, or once per module. + + Example usage: + + ffi = FFI() + ffi.cdef(""" + int printf(const char *, ...); + """) + + C = ffi.dlopen(None) # standard library + -or- + C = ffi.verify() # use a C compiler: verify the decl above is right + + C.printf("hello, %s!\n", ffi.new("char[]", "world")) + ''' + + def __init__(self, backend=None): + """Create an FFI instance. The 'backend' argument is used to + select a non-default backend, mostly for tests. + """ + if backend is None: + # You need PyPy (>= 2.0 beta), or a CPython (>= 2.6) with + # _cffi_backend.so compiled. + import _cffi_backend as backend + from . import __version__ + if backend.__version__ != __version__: + # bad version! Try to be as explicit as possible. + if hasattr(backend, '__file__'): + # CPython + raise Exception("Version mismatch: this is the 'cffi' package version %s, located in %r. When we import the top-level '_cffi_backend' extension module, we get version %s, located in %r. The two versions should be equal; check your installation." % ( + __version__, __file__, + backend.__version__, backend.__file__)) + else: + # PyPy + raise Exception("Version mismatch: this is the 'cffi' package version %s, located in %r. This interpreter comes with a built-in '_cffi_backend' module, which is version %s. The two versions should be equal; check your installation." % ( + __version__, __file__, backend.__version__)) + # (If you insist you can also try to pass the option + # 'backend=backend_ctypes.CTypesBackend()', but don't + # rely on it! It's probably not going to work well.) + + from . import cparser + self._backend = backend + self._lock = allocate_lock() + self._parser = cparser.Parser() + self._cached_btypes = {} + self._parsed_types = types.ModuleType('parsed_types').__dict__ + self._new_types = types.ModuleType('new_types').__dict__ + self._function_caches = [] + self._libraries = [] + self._cdefsources = [] + self._included_ffis = [] + self._windows_unicode = None + self._init_once_cache = {} + self._cdef_version = None + self._embedding = None + self._typecache = model.get_typecache(backend) + if hasattr(backend, 'set_ffi'): + backend.set_ffi(self) + for name in list(backend.__dict__): + if name.startswith('RTLD_'): + setattr(self, name, getattr(backend, name)) + # + with self._lock: + self.BVoidP = self._get_cached_btype(model.voidp_type) + self.BCharA = self._get_cached_btype(model.char_array_type) + if isinstance(backend, types.ModuleType): + # _cffi_backend: attach these constants to the class + if not hasattr(FFI, 'NULL'): + FFI.NULL = self.cast(self.BVoidP, 0) + FFI.CData, FFI.CType = backend._get_types() + else: + # ctypes backend: attach these constants to the instance + self.NULL = self.cast(self.BVoidP, 0) + self.CData, self.CType = backend._get_types() + self.buffer = backend.buffer + + def cdef(self, csource, override=False, packed=False, pack=None): + """Parse the given C source. This registers all declared functions, + types, and global variables. The functions and global variables can + then be accessed via either 'ffi.dlopen()' or 'ffi.verify()'. + The types can be used in 'ffi.new()' and other functions. + If 'packed' is specified as True, all structs declared inside this + cdef are packed, i.e. laid out without any field alignment at all. + Alternatively, 'pack' can be a small integer, and requests for + alignment greater than that are ignored (pack=1 is equivalent to + packed=True). + """ + self._cdef(csource, override=override, packed=packed, pack=pack) + + def embedding_api(self, csource, packed=False, pack=None): + self._cdef(csource, packed=packed, pack=pack, dllexport=True) + if self._embedding is None: + self._embedding = '' + + def _cdef(self, csource, override=False, **options): + if not isinstance(csource, str): # unicode, on Python 2 + if not isinstance(csource, basestring): + raise TypeError("cdef() argument must be a string") + csource = csource.encode('ascii') + with self._lock: + self._cdef_version = object() + self._parser.parse(csource, override=override, **options) + self._cdefsources.append(csource) + if override: + for cache in self._function_caches: + cache.clear() + finishlist = self._parser._recomplete + if finishlist: + self._parser._recomplete = [] + for tp in finishlist: + tp.finish_backend_type(self, finishlist) + + def dlopen(self, name, flags=0): + """Load and return a dynamic library identified by 'name'. + The standard C library can be loaded by passing None. + Note that functions and types declared by 'ffi.cdef()' are not + linked to a particular library, just like C headers; in the + library we only look for the actual (untyped) symbols. + """ + if not (isinstance(name, basestring) or + name is None or + isinstance(name, self.CData)): + raise TypeError("dlopen(name): name must be a file name, None, " + "or an already-opened 'void *' handle") + with self._lock: + lib, function_cache = _make_ffi_library(self, name, flags) + self._function_caches.append(function_cache) + self._libraries.append(lib) + return lib + + def dlclose(self, lib): + """Close a library obtained with ffi.dlopen(). After this call, + access to functions or variables from the library will fail + (possibly with a segmentation fault). + """ + type(lib).__cffi_close__(lib) + + def _typeof_locked(self, cdecl): + # call me with the lock! + key = cdecl + if key in self._parsed_types: + return self._parsed_types[key] + # + if not isinstance(cdecl, str): # unicode, on Python 2 + cdecl = cdecl.encode('ascii') + # + type = self._parser.parse_type(cdecl) + really_a_function_type = type.is_raw_function + if really_a_function_type: + type = type.as_function_pointer() + btype = self._get_cached_btype(type) + result = btype, really_a_function_type + self._parsed_types[key] = result + return result + + def _typeof(self, cdecl, consider_function_as_funcptr=False): + # string -> ctype object + try: + result = self._parsed_types[cdecl] + except KeyError: + with self._lock: + result = self._typeof_locked(cdecl) + # + btype, really_a_function_type = result + if really_a_function_type and not consider_function_as_funcptr: + raise CDefError("the type %r is a function type, not a " + "pointer-to-function type" % (cdecl,)) + return btype + + def typeof(self, cdecl): + """Parse the C type given as a string and return the + corresponding object. + It can also be used on 'cdata' instance to get its C type. + """ + if isinstance(cdecl, basestring): + return self._typeof(cdecl) + if isinstance(cdecl, self.CData): + return self._backend.typeof(cdecl) + if isinstance(cdecl, types.BuiltinFunctionType): + res = _builtin_function_type(cdecl) + if res is not None: + return res + if (isinstance(cdecl, types.FunctionType) + and hasattr(cdecl, '_cffi_base_type')): + with self._lock: + return self._get_cached_btype(cdecl._cffi_base_type) + raise TypeError(type(cdecl)) + + def sizeof(self, cdecl): + """Return the size in bytes of the argument. It can be a + string naming a C type, or a 'cdata' instance. + """ + if isinstance(cdecl, basestring): + BType = self._typeof(cdecl) + return self._backend.sizeof(BType) + else: + return self._backend.sizeof(cdecl) + + def alignof(self, cdecl): + """Return the natural alignment size in bytes of the C type + given as a string. + """ + if isinstance(cdecl, basestring): + cdecl = self._typeof(cdecl) + return self._backend.alignof(cdecl) + + def offsetof(self, cdecl, *fields_or_indexes): + """Return the offset of the named field inside the given + structure or array, which must be given as a C type name. + You can give several field names in case of nested structures. + You can also give numeric values which correspond to array + items, in case of an array type. + """ + if isinstance(cdecl, basestring): + cdecl = self._typeof(cdecl) + return self._typeoffsetof(cdecl, *fields_or_indexes)[1] + + def new(self, cdecl, init=None): + """Allocate an instance according to the specified C type and + return a pointer to it. The specified C type must be either a + pointer or an array: ``new('X *')`` allocates an X and returns + a pointer to it, whereas ``new('X[n]')`` allocates an array of + n X'es and returns an array referencing it (which works + mostly like a pointer, like in C). You can also use + ``new('X[]', n)`` to allocate an array of a non-constant + length n. + + The memory is initialized following the rules of declaring a + global variable in C: by default it is zero-initialized, but + an explicit initializer can be given which can be used to + fill all or part of the memory. + + When the returned object goes out of scope, the memory + is freed. In other words the returned object has + ownership of the value of type 'cdecl' that it points to. This + means that the raw data can be used as long as this object is + kept alive, but must not be used for a longer time. Be careful + about that when copying the pointer to the memory somewhere + else, e.g. into another structure. + """ + if isinstance(cdecl, basestring): + cdecl = self._typeof(cdecl) + return self._backend.newp(cdecl, init) + + def new_allocator(self, alloc=None, free=None, + should_clear_after_alloc=True): + """Return a new allocator, i.e. a function that behaves like ffi.new() + but uses the provided low-level 'alloc' and 'free' functions. + + 'alloc' is called with the size as argument. If it returns NULL, a + MemoryError is raised. 'free' is called with the result of 'alloc' + as argument. Both can be either Python function or directly C + functions. If 'free' is None, then no free function is called. + If both 'alloc' and 'free' are None, the default is used. + + If 'should_clear_after_alloc' is set to False, then the memory + returned by 'alloc' is assumed to be already cleared (or you are + fine with garbage); otherwise CFFI will clear it. + """ + compiled_ffi = self._backend.FFI() + allocator = compiled_ffi.new_allocator(alloc, free, + should_clear_after_alloc) + def allocate(cdecl, init=None): + if isinstance(cdecl, basestring): + cdecl = self._typeof(cdecl) + return allocator(cdecl, init) + return allocate + + def cast(self, cdecl, source): + """Similar to a C cast: returns an instance of the named C + type initialized with the given 'source'. The source is + casted between integers or pointers of any type. + """ + if isinstance(cdecl, basestring): + cdecl = self._typeof(cdecl) + return self._backend.cast(cdecl, source) + + def string(self, cdata, maxlen=-1): + """Return a Python string (or unicode string) from the 'cdata'. + If 'cdata' is a pointer or array of characters or bytes, returns + the null-terminated string. The returned string extends until + the first null character, or at most 'maxlen' characters. If + 'cdata' is an array then 'maxlen' defaults to its length. + + If 'cdata' is a pointer or array of wchar_t, returns a unicode + string following the same rules. + + If 'cdata' is a single character or byte or a wchar_t, returns + it as a string or unicode string. + + If 'cdata' is an enum, returns the value of the enumerator as a + string, or 'NUMBER' if the value is out of range. + """ + return self._backend.string(cdata, maxlen) + + def unpack(self, cdata, length): + """Unpack an array of C data of the given length, + returning a Python string/unicode/list. + + If 'cdata' is a pointer to 'char', returns a byte string. + It does not stop at the first null. This is equivalent to: + ffi.buffer(cdata, length)[:] + + If 'cdata' is a pointer to 'wchar_t', returns a unicode string. + 'length' is measured in wchar_t's; it is not the size in bytes. + + If 'cdata' is a pointer to anything else, returns a list of + 'length' items. This is a faster equivalent to: + [cdata[i] for i in range(length)] + """ + return self._backend.unpack(cdata, length) + + #def buffer(self, cdata, size=-1): + # """Return a read-write buffer object that references the raw C data + # pointed to by the given 'cdata'. The 'cdata' must be a pointer or + # an array. Can be passed to functions expecting a buffer, or directly + # manipulated with: + # + # buf[:] get a copy of it in a regular string, or + # buf[idx] as a single character + # buf[:] = ... + # buf[idx] = ... change the content + # """ + # note that 'buffer' is a type, set on this instance by __init__ + + def from_buffer(self, cdecl, python_buffer=_unspecified, + require_writable=False): + """Return a cdata of the given type pointing to the data of the + given Python object, which must support the buffer interface. + Note that this is not meant to be used on the built-in types + str or unicode (you can build 'char[]' arrays explicitly) + but only on objects containing large quantities of raw data + in some other format, like 'array.array' or numpy arrays. + + The first argument is optional and default to 'char[]'. + """ + if python_buffer is _unspecified: + cdecl, python_buffer = self.BCharA, cdecl + elif isinstance(cdecl, basestring): + cdecl = self._typeof(cdecl) + return self._backend.from_buffer(cdecl, python_buffer, + require_writable) + + def memmove(self, dest, src, n): + """ffi.memmove(dest, src, n) copies n bytes of memory from src to dest. + + Like the C function memmove(), the memory areas may overlap; + apart from that it behaves like the C function memcpy(). + + 'src' can be any cdata ptr or array, or any Python buffer object. + 'dest' can be any cdata ptr or array, or a writable Python buffer + object. The size to copy, 'n', is always measured in bytes. + + Unlike other methods, this one supports all Python buffer including + byte strings and bytearrays---but it still does not support + non-contiguous buffers. + """ + return self._backend.memmove(dest, src, n) + + def callback(self, cdecl, python_callable=None, error=None, onerror=None): + """Return a callback object or a decorator making such a + callback object. 'cdecl' must name a C function pointer type. + The callback invokes the specified 'python_callable' (which may + be provided either directly or via a decorator). Important: the + callback object must be manually kept alive for as long as the + callback may be invoked from the C level. + """ + def callback_decorator_wrap(python_callable): + if not callable(python_callable): + raise TypeError("the 'python_callable' argument " + "is not callable") + return self._backend.callback(cdecl, python_callable, + error, onerror) + if isinstance(cdecl, basestring): + cdecl = self._typeof(cdecl, consider_function_as_funcptr=True) + if python_callable is None: + return callback_decorator_wrap # decorator mode + else: + return callback_decorator_wrap(python_callable) # direct mode + + def getctype(self, cdecl, replace_with=''): + """Return a string giving the C type 'cdecl', which may be itself + a string or a object. If 'replace_with' is given, it gives + extra text to append (or insert for more complicated C types), like + a variable name, or '*' to get actually the C type 'pointer-to-cdecl'. + """ + if isinstance(cdecl, basestring): + cdecl = self._typeof(cdecl) + replace_with = replace_with.strip() + if (replace_with.startswith('*') + and '&[' in self._backend.getcname(cdecl, '&')): + replace_with = '(%s)' % replace_with + elif replace_with and not replace_with[0] in '[(': + replace_with = ' ' + replace_with + return self._backend.getcname(cdecl, replace_with) + + def gc(self, cdata, destructor, size=0): + """Return a new cdata object that points to the same + data. Later, when this new cdata object is garbage-collected, + 'destructor(old_cdata_object)' will be called. + + The optional 'size' gives an estimate of the size, used to + trigger the garbage collection more eagerly. So far only used + on PyPy. It tells the GC that the returned object keeps alive + roughly 'size' bytes of external memory. + """ + return self._backend.gcp(cdata, destructor, size) + + def _get_cached_btype(self, type): + assert self._lock.acquire(False) is False + # call me with the lock! + try: + BType = self._cached_btypes[type] + except KeyError: + finishlist = [] + BType = type.get_cached_btype(self, finishlist) + for type in finishlist: + type.finish_backend_type(self, finishlist) + return BType + + def verify(self, source='', tmpdir=None, **kwargs): + """Verify that the current ffi signatures compile on this + machine, and return a dynamic library object. The dynamic + library can be used to call functions and access global + variables declared in this 'ffi'. The library is compiled + by the C compiler: it gives you C-level API compatibility + (including calling macros). This is unlike 'ffi.dlopen()', + which requires binary compatibility in the signatures. + """ + from .verifier import Verifier, _caller_dir_pycache + # + # If set_unicode(True) was called, insert the UNICODE and + # _UNICODE macro declarations + if self._windows_unicode: + self._apply_windows_unicode(kwargs) + # + # Set the tmpdir here, and not in Verifier.__init__: it picks + # up the caller's directory, which we want to be the caller of + # ffi.verify(), as opposed to the caller of Veritier(). + tmpdir = tmpdir or _caller_dir_pycache() + # + # Make a Verifier() and use it to load the library. + self.verifier = Verifier(self, source, tmpdir, **kwargs) + lib = self.verifier.load_library() + # + # Save the loaded library for keep-alive purposes, even + # if the caller doesn't keep it alive itself (it should). + self._libraries.append(lib) + return lib + + def _get_errno(self): + return self._backend.get_errno() + def _set_errno(self, errno): + self._backend.set_errno(errno) + errno = property(_get_errno, _set_errno, None, + "the value of 'errno' from/to the C calls") + + def getwinerror(self, code=-1): + return self._backend.getwinerror(code) + + def _pointer_to(self, ctype): + with self._lock: + return model.pointer_cache(self, ctype) + + def addressof(self, cdata, *fields_or_indexes): + """Return the address of a . + If 'fields_or_indexes' are given, returns the address of that + field or array item in the structure or array, recursively in + case of nested structures. + """ + try: + ctype = self._backend.typeof(cdata) + except TypeError: + if '__addressof__' in type(cdata).__dict__: + return type(cdata).__addressof__(cdata, *fields_or_indexes) + raise + if fields_or_indexes: + ctype, offset = self._typeoffsetof(ctype, *fields_or_indexes) + else: + if ctype.kind == "pointer": + raise TypeError("addressof(pointer)") + offset = 0 + ctypeptr = self._pointer_to(ctype) + return self._backend.rawaddressof(ctypeptr, cdata, offset) + + def _typeoffsetof(self, ctype, field_or_index, *fields_or_indexes): + ctype, offset = self._backend.typeoffsetof(ctype, field_or_index) + for field1 in fields_or_indexes: + ctype, offset1 = self._backend.typeoffsetof(ctype, field1, 1) + offset += offset1 + return ctype, offset + + def include(self, ffi_to_include): + """Includes the typedefs, structs, unions and enums defined + in another FFI instance. Usage is similar to a #include in C, + where a part of the program might include types defined in + another part for its own usage. Note that the include() + method has no effect on functions, constants and global + variables, which must anyway be accessed directly from the + lib object returned by the original FFI instance. + """ + if not isinstance(ffi_to_include, FFI): + raise TypeError("ffi.include() expects an argument that is also of" + " type cffi.FFI, not %r" % ( + type(ffi_to_include).__name__,)) + if ffi_to_include is self: + raise ValueError("self.include(self)") + with ffi_to_include._lock: + with self._lock: + self._parser.include(ffi_to_include._parser) + self._cdefsources.append('[') + self._cdefsources.extend(ffi_to_include._cdefsources) + self._cdefsources.append(']') + self._included_ffis.append(ffi_to_include) + + def new_handle(self, x): + return self._backend.newp_handle(self.BVoidP, x) + + def from_handle(self, x): + return self._backend.from_handle(x) + + def release(self, x): + self._backend.release(x) + + def set_unicode(self, enabled_flag): + """Windows: if 'enabled_flag' is True, enable the UNICODE and + _UNICODE defines in C, and declare the types like TCHAR and LPTCSTR + to be (pointers to) wchar_t. If 'enabled_flag' is False, + declare these types to be (pointers to) plain 8-bit characters. + This is mostly for backward compatibility; you usually want True. + """ + if self._windows_unicode is not None: + raise ValueError("set_unicode() can only be called once") + enabled_flag = bool(enabled_flag) + if enabled_flag: + self.cdef("typedef wchar_t TBYTE;" + "typedef wchar_t TCHAR;" + "typedef const wchar_t *LPCTSTR;" + "typedef const wchar_t *PCTSTR;" + "typedef wchar_t *LPTSTR;" + "typedef wchar_t *PTSTR;" + "typedef TBYTE *PTBYTE;" + "typedef TCHAR *PTCHAR;") + else: + self.cdef("typedef char TBYTE;" + "typedef char TCHAR;" + "typedef const char *LPCTSTR;" + "typedef const char *PCTSTR;" + "typedef char *LPTSTR;" + "typedef char *PTSTR;" + "typedef TBYTE *PTBYTE;" + "typedef TCHAR *PTCHAR;") + self._windows_unicode = enabled_flag + + def _apply_windows_unicode(self, kwds): + defmacros = kwds.get('define_macros', ()) + if not isinstance(defmacros, (list, tuple)): + raise TypeError("'define_macros' must be a list or tuple") + defmacros = list(defmacros) + [('UNICODE', '1'), + ('_UNICODE', '1')] + kwds['define_macros'] = defmacros + + def _apply_embedding_fix(self, kwds): + # must include an argument like "-lpython2.7" for the compiler + def ensure(key, value): + lst = kwds.setdefault(key, []) + if value not in lst: + lst.append(value) + # + if '__pypy__' in sys.builtin_module_names: + import os + if sys.platform == "win32": + # we need 'libpypy-c.lib'. Current distributions of + # pypy (>= 4.1) contain it as 'libs/python27.lib'. + pythonlib = "python{0[0]}{0[1]}".format(sys.version_info) + if hasattr(sys, 'prefix'): + ensure('library_dirs', os.path.join(sys.prefix, 'libs')) + else: + # we need 'libpypy-c.{so,dylib}', which should be by + # default located in 'sys.prefix/bin' for installed + # systems. + if sys.version_info < (3,): + pythonlib = "pypy-c" + else: + pythonlib = "pypy3-c" + if hasattr(sys, 'prefix'): + ensure('library_dirs', os.path.join(sys.prefix, 'bin')) + # On uninstalled pypy's, the libpypy-c is typically found in + # .../pypy/goal/. + if hasattr(sys, 'prefix'): + ensure('library_dirs', os.path.join(sys.prefix, 'pypy', 'goal')) + else: + if sys.platform == "win32": + template = "python%d%d" + if hasattr(sys, 'gettotalrefcount'): + template += '_d' + else: + try: + import sysconfig + except ImportError: # 2.6 + from distutils import sysconfig + template = "python%d.%d" + if sysconfig.get_config_var('DEBUG_EXT'): + template += sysconfig.get_config_var('DEBUG_EXT') + pythonlib = (template % + (sys.hexversion >> 24, (sys.hexversion >> 16) & 0xff)) + if hasattr(sys, 'abiflags'): + pythonlib += sys.abiflags + ensure('libraries', pythonlib) + if sys.platform == "win32": + ensure('extra_link_args', '/MANIFEST') + + def set_source(self, module_name, source, source_extension='.c', **kwds): + import os + if hasattr(self, '_assigned_source'): + raise ValueError("set_source() cannot be called several times " + "per ffi object") + if not isinstance(module_name, basestring): + raise TypeError("'module_name' must be a string") + if os.sep in module_name or (os.altsep and os.altsep in module_name): + raise ValueError("'module_name' must not contain '/': use a dotted " + "name to make a 'package.module' location") + self._assigned_source = (str(module_name), source, + source_extension, kwds) + + def set_source_pkgconfig(self, module_name, pkgconfig_libs, source, + source_extension='.c', **kwds): + from . import pkgconfig + if not isinstance(pkgconfig_libs, list): + raise TypeError("the pkgconfig_libs argument must be a list " + "of package names") + kwds2 = pkgconfig.flags_from_pkgconfig(pkgconfig_libs) + pkgconfig.merge_flags(kwds, kwds2) + self.set_source(module_name, source, source_extension, **kwds) + + def distutils_extension(self, tmpdir='build', verbose=True): + from distutils.dir_util import mkpath + from .recompiler import recompile + # + if not hasattr(self, '_assigned_source'): + if hasattr(self, 'verifier'): # fallback, 'tmpdir' ignored + return self.verifier.get_extension() + raise ValueError("set_source() must be called before" + " distutils_extension()") + module_name, source, source_extension, kwds = self._assigned_source + if source is None: + raise TypeError("distutils_extension() is only for C extension " + "modules, not for dlopen()-style pure Python " + "modules") + mkpath(tmpdir) + ext, updated = recompile(self, module_name, + source, tmpdir=tmpdir, extradir=tmpdir, + source_extension=source_extension, + call_c_compiler=False, **kwds) + if verbose: + if updated: + sys.stderr.write("regenerated: %r\n" % (ext.sources[0],)) + else: + sys.stderr.write("not modified: %r\n" % (ext.sources[0],)) + return ext + + def emit_c_code(self, filename): + from .recompiler import recompile + # + if not hasattr(self, '_assigned_source'): + raise ValueError("set_source() must be called before emit_c_code()") + module_name, source, source_extension, kwds = self._assigned_source + if source is None: + raise TypeError("emit_c_code() is only for C extension modules, " + "not for dlopen()-style pure Python modules") + recompile(self, module_name, source, + c_file=filename, call_c_compiler=False, **kwds) + + def emit_python_code(self, filename): + from .recompiler import recompile + # + if not hasattr(self, '_assigned_source'): + raise ValueError("set_source() must be called before emit_c_code()") + module_name, source, source_extension, kwds = self._assigned_source + if source is not None: + raise TypeError("emit_python_code() is only for dlopen()-style " + "pure Python modules, not for C extension modules") + recompile(self, module_name, source, + c_file=filename, call_c_compiler=False, **kwds) + + def compile(self, tmpdir='.', verbose=0, target=None, debug=None): + """The 'target' argument gives the final file name of the + compiled DLL. Use '*' to force distutils' choice, suitable for + regular CPython C API modules. Use a file name ending in '.*' + to ask for the system's default extension for dynamic libraries + (.so/.dll/.dylib). + + The default is '*' when building a non-embedded C API extension, + and (module_name + '.*') when building an embedded library. + """ + from .recompiler import recompile + # + if not hasattr(self, '_assigned_source'): + raise ValueError("set_source() must be called before compile()") + module_name, source, source_extension, kwds = self._assigned_source + return recompile(self, module_name, source, tmpdir=tmpdir, + target=target, source_extension=source_extension, + compiler_verbose=verbose, debug=debug, **kwds) + + def init_once(self, func, tag): + # Read _init_once_cache[tag], which is either (False, lock) if + # we're calling the function now in some thread, or (True, result). + # Don't call setdefault() in most cases, to avoid allocating and + # immediately freeing a lock; but still use setdefaut() to avoid + # races. + try: + x = self._init_once_cache[tag] + except KeyError: + x = self._init_once_cache.setdefault(tag, (False, allocate_lock())) + # Common case: we got (True, result), so we return the result. + if x[0]: + return x[1] + # Else, it's a lock. Acquire it to serialize the following tests. + with x[1]: + # Read again from _init_once_cache the current status. + x = self._init_once_cache[tag] + if x[0]: + return x[1] + # Call the function and store the result back. + result = func() + self._init_once_cache[tag] = (True, result) + return result + + def embedding_init_code(self, pysource): + if self._embedding: + raise ValueError("embedding_init_code() can only be called once") + # fix 'pysource' before it gets dumped into the C file: + # - remove empty lines at the beginning, so it starts at "line 1" + # - dedent, if all non-empty lines are indented + # - check for SyntaxErrors + import re + match = re.match(r'\s*\n', pysource) + if match: + pysource = pysource[match.end():] + lines = pysource.splitlines() or [''] + prefix = re.match(r'\s*', lines[0]).group() + for i in range(1, len(lines)): + line = lines[i] + if line.rstrip(): + while not line.startswith(prefix): + prefix = prefix[:-1] + i = len(prefix) + lines = [line[i:]+'\n' for line in lines] + pysource = ''.join(lines) + # + compile(pysource, "cffi_init", "exec") + # + self._embedding = pysource + + def def_extern(self, *args, **kwds): + raise ValueError("ffi.def_extern() is only available on API-mode FFI " + "objects") + + def list_types(self): + """Returns the user type names known to this FFI instance. + This returns a tuple containing three lists of names: + (typedef_names, names_of_structs, names_of_unions) + """ + typedefs = [] + structs = [] + unions = [] + for key in self._parser._declarations: + if key.startswith('typedef '): + typedefs.append(key[8:]) + elif key.startswith('struct '): + structs.append(key[7:]) + elif key.startswith('union '): + unions.append(key[6:]) + typedefs.sort() + structs.sort() + unions.sort() + return (typedefs, structs, unions) + + +def _load_backend_lib(backend, name, flags): + import os + if not isinstance(name, basestring): + if sys.platform != "win32" or name is not None: + return backend.load_library(name, flags) + name = "c" # Windows: load_library(None) fails, but this works + # on Python 2 (backward compatibility hack only) + first_error = None + if '.' in name or '/' in name or os.sep in name: + try: + return backend.load_library(name, flags) + except OSError as e: + first_error = e + import ctypes.util + path = ctypes.util.find_library(name) + if path is None: + if name == "c" and sys.platform == "win32" and sys.version_info >= (3,): + raise OSError("dlopen(None) cannot work on Windows for Python 3 " + "(see http://bugs.python.org/issue23606)") + msg = ("ctypes.util.find_library() did not manage " + "to locate a library called %r" % (name,)) + if first_error is not None: + msg = "%s. Additionally, %s" % (first_error, msg) + raise OSError(msg) + return backend.load_library(path, flags) + +def _make_ffi_library(ffi, libname, flags): + backend = ffi._backend + backendlib = _load_backend_lib(backend, libname, flags) + # + def accessor_function(name): + key = 'function ' + name + tp, _ = ffi._parser._declarations[key] + BType = ffi._get_cached_btype(tp) + value = backendlib.load_function(BType, name) + library.__dict__[name] = value + # + def accessor_variable(name): + key = 'variable ' + name + tp, _ = ffi._parser._declarations[key] + BType = ffi._get_cached_btype(tp) + read_variable = backendlib.read_variable + write_variable = backendlib.write_variable + setattr(FFILibrary, name, property( + lambda self: read_variable(BType, name), + lambda self, value: write_variable(BType, name, value))) + # + def addressof_var(name): + try: + return addr_variables[name] + except KeyError: + with ffi._lock: + if name not in addr_variables: + key = 'variable ' + name + tp, _ = ffi._parser._declarations[key] + BType = ffi._get_cached_btype(tp) + if BType.kind != 'array': + BType = model.pointer_cache(ffi, BType) + p = backendlib.load_function(BType, name) + addr_variables[name] = p + return addr_variables[name] + # + def accessor_constant(name): + raise NotImplementedError("non-integer constant '%s' cannot be " + "accessed from a dlopen() library" % (name,)) + # + def accessor_int_constant(name): + library.__dict__[name] = ffi._parser._int_constants[name] + # + accessors = {} + accessors_version = [False] + addr_variables = {} + # + def update_accessors(): + if accessors_version[0] is ffi._cdef_version: + return + # + for key, (tp, _) in ffi._parser._declarations.items(): + if not isinstance(tp, model.EnumType): + tag, name = key.split(' ', 1) + if tag == 'function': + accessors[name] = accessor_function + elif tag == 'variable': + accessors[name] = accessor_variable + elif tag == 'constant': + accessors[name] = accessor_constant + else: + for i, enumname in enumerate(tp.enumerators): + def accessor_enum(name, tp=tp, i=i): + tp.check_not_partial() + library.__dict__[name] = tp.enumvalues[i] + accessors[enumname] = accessor_enum + for name in ffi._parser._int_constants: + accessors.setdefault(name, accessor_int_constant) + accessors_version[0] = ffi._cdef_version + # + def make_accessor(name): + with ffi._lock: + if name in library.__dict__ or name in FFILibrary.__dict__: + return # added by another thread while waiting for the lock + if name not in accessors: + update_accessors() + if name not in accessors: + raise AttributeError(name) + accessors[name](name) + # + class FFILibrary(object): + def __getattr__(self, name): + make_accessor(name) + return getattr(self, name) + def __setattr__(self, name, value): + try: + property = getattr(self.__class__, name) + except AttributeError: + make_accessor(name) + setattr(self, name, value) + else: + property.__set__(self, value) + def __dir__(self): + with ffi._lock: + update_accessors() + return accessors.keys() + def __addressof__(self, name): + if name in library.__dict__: + return library.__dict__[name] + if name in FFILibrary.__dict__: + return addressof_var(name) + make_accessor(name) + if name in library.__dict__: + return library.__dict__[name] + if name in FFILibrary.__dict__: + return addressof_var(name) + raise AttributeError("cffi library has no function or " + "global variable named '%s'" % (name,)) + def __cffi_close__(self): + backendlib.close_lib() + self.__dict__.clear() + # + if isinstance(libname, basestring): + try: + if not isinstance(libname, str): # unicode, on Python 2 + libname = libname.encode('utf-8') + FFILibrary.__name__ = 'FFILibrary_%s' % libname + except UnicodeError: + pass + library = FFILibrary() + return library, library.__dict__ + +def _builtin_function_type(func): + # a hack to make at least ffi.typeof(builtin_function) work, + # if the builtin function was obtained by 'vengine_cpy'. + import sys + try: + module = sys.modules[func.__module__] + ffi = module._cffi_original_ffi + types_of_builtin_funcs = module._cffi_types_of_builtin_funcs + tp = types_of_builtin_funcs[func] + except (KeyError, AttributeError, TypeError): + return None + else: + with ffi._lock: + return ffi._get_cached_btype(tp) diff --git a/venv/Lib/site-packages/cffi/backend_ctypes.py b/venv/Lib/site-packages/cffi/backend_ctypes.py new file mode 100644 index 000000000..e7956a79c --- /dev/null +++ b/venv/Lib/site-packages/cffi/backend_ctypes.py @@ -0,0 +1,1121 @@ +import ctypes, ctypes.util, operator, sys +from . import model + +if sys.version_info < (3,): + bytechr = chr +else: + unicode = str + long = int + xrange = range + bytechr = lambda num: bytes([num]) + +class CTypesType(type): + pass + +class CTypesData(object): + __metaclass__ = CTypesType + __slots__ = ['__weakref__'] + __name__ = '' + + def __init__(self, *args): + raise TypeError("cannot instantiate %r" % (self.__class__,)) + + @classmethod + def _newp(cls, init): + raise TypeError("expected a pointer or array ctype, got '%s'" + % (cls._get_c_name(),)) + + @staticmethod + def _to_ctypes(value): + raise TypeError + + @classmethod + def _arg_to_ctypes(cls, *value): + try: + ctype = cls._ctype + except AttributeError: + raise TypeError("cannot create an instance of %r" % (cls,)) + if value: + res = cls._to_ctypes(*value) + if not isinstance(res, ctype): + res = cls._ctype(res) + else: + res = cls._ctype() + return res + + @classmethod + def _create_ctype_obj(cls, init): + if init is None: + return cls._arg_to_ctypes() + else: + return cls._arg_to_ctypes(init) + + @staticmethod + def _from_ctypes(ctypes_value): + raise TypeError + + @classmethod + def _get_c_name(cls, replace_with=''): + return cls._reftypename.replace(' &', replace_with) + + @classmethod + def _fix_class(cls): + cls.__name__ = 'CData<%s>' % (cls._get_c_name(),) + cls.__qualname__ = 'CData<%s>' % (cls._get_c_name(),) + cls.__module__ = 'ffi' + + def _get_own_repr(self): + raise NotImplementedError + + def _addr_repr(self, address): + if address == 0: + return 'NULL' + else: + if address < 0: + address += 1 << (8*ctypes.sizeof(ctypes.c_void_p)) + return '0x%x' % address + + def __repr__(self, c_name=None): + own = self._get_own_repr() + return '' % (c_name or self._get_c_name(), own) + + def _convert_to_address(self, BClass): + if BClass is None: + raise TypeError("cannot convert %r to an address" % ( + self._get_c_name(),)) + else: + raise TypeError("cannot convert %r to %r" % ( + self._get_c_name(), BClass._get_c_name())) + + @classmethod + def _get_size(cls): + return ctypes.sizeof(cls._ctype) + + def _get_size_of_instance(self): + return ctypes.sizeof(self._ctype) + + @classmethod + def _cast_from(cls, source): + raise TypeError("cannot cast to %r" % (cls._get_c_name(),)) + + def _cast_to_integer(self): + return self._convert_to_address(None) + + @classmethod + def _alignment(cls): + return ctypes.alignment(cls._ctype) + + def __iter__(self): + raise TypeError("cdata %r does not support iteration" % ( + self._get_c_name()),) + + def _make_cmp(name): + cmpfunc = getattr(operator, name) + def cmp(self, other): + v_is_ptr = not isinstance(self, CTypesGenericPrimitive) + w_is_ptr = (isinstance(other, CTypesData) and + not isinstance(other, CTypesGenericPrimitive)) + if v_is_ptr and w_is_ptr: + return cmpfunc(self._convert_to_address(None), + other._convert_to_address(None)) + elif v_is_ptr or w_is_ptr: + return NotImplemented + else: + if isinstance(self, CTypesGenericPrimitive): + self = self._value + if isinstance(other, CTypesGenericPrimitive): + other = other._value + return cmpfunc(self, other) + cmp.func_name = name + return cmp + + __eq__ = _make_cmp('__eq__') + __ne__ = _make_cmp('__ne__') + __lt__ = _make_cmp('__lt__') + __le__ = _make_cmp('__le__') + __gt__ = _make_cmp('__gt__') + __ge__ = _make_cmp('__ge__') + + def __hash__(self): + return hash(self._convert_to_address(None)) + + def _to_string(self, maxlen): + raise TypeError("string(): %r" % (self,)) + + +class CTypesGenericPrimitive(CTypesData): + __slots__ = [] + + def __hash__(self): + return hash(self._value) + + def _get_own_repr(self): + return repr(self._from_ctypes(self._value)) + + +class CTypesGenericArray(CTypesData): + __slots__ = [] + + @classmethod + def _newp(cls, init): + return cls(init) + + def __iter__(self): + for i in xrange(len(self)): + yield self[i] + + def _get_own_repr(self): + return self._addr_repr(ctypes.addressof(self._blob)) + + +class CTypesGenericPtr(CTypesData): + __slots__ = ['_address', '_as_ctype_ptr'] + _automatic_casts = False + kind = "pointer" + + @classmethod + def _newp(cls, init): + return cls(init) + + @classmethod + def _cast_from(cls, source): + if source is None: + address = 0 + elif isinstance(source, CTypesData): + address = source._cast_to_integer() + elif isinstance(source, (int, long)): + address = source + else: + raise TypeError("bad type for cast to %r: %r" % + (cls, type(source).__name__)) + return cls._new_pointer_at(address) + + @classmethod + def _new_pointer_at(cls, address): + self = cls.__new__(cls) + self._address = address + self._as_ctype_ptr = ctypes.cast(address, cls._ctype) + return self + + def _get_own_repr(self): + try: + return self._addr_repr(self._address) + except AttributeError: + return '???' + + def _cast_to_integer(self): + return self._address + + def __nonzero__(self): + return bool(self._address) + __bool__ = __nonzero__ + + @classmethod + def _to_ctypes(cls, value): + if not isinstance(value, CTypesData): + raise TypeError("unexpected %s object" % type(value).__name__) + address = value._convert_to_address(cls) + return ctypes.cast(address, cls._ctype) + + @classmethod + def _from_ctypes(cls, ctypes_ptr): + address = ctypes.cast(ctypes_ptr, ctypes.c_void_p).value or 0 + return cls._new_pointer_at(address) + + @classmethod + def _initialize(cls, ctypes_ptr, value): + if value: + ctypes_ptr.contents = cls._to_ctypes(value).contents + + def _convert_to_address(self, BClass): + if (BClass in (self.__class__, None) or BClass._automatic_casts + or self._automatic_casts): + return self._address + else: + return CTypesData._convert_to_address(self, BClass) + + +class CTypesBaseStructOrUnion(CTypesData): + __slots__ = ['_blob'] + + @classmethod + def _create_ctype_obj(cls, init): + # may be overridden + raise TypeError("cannot instantiate opaque type %s" % (cls,)) + + def _get_own_repr(self): + return self._addr_repr(ctypes.addressof(self._blob)) + + @classmethod + def _offsetof(cls, fieldname): + return getattr(cls._ctype, fieldname).offset + + def _convert_to_address(self, BClass): + if getattr(BClass, '_BItem', None) is self.__class__: + return ctypes.addressof(self._blob) + else: + return CTypesData._convert_to_address(self, BClass) + + @classmethod + def _from_ctypes(cls, ctypes_struct_or_union): + self = cls.__new__(cls) + self._blob = ctypes_struct_or_union + return self + + @classmethod + def _to_ctypes(cls, value): + return value._blob + + def __repr__(self, c_name=None): + return CTypesData.__repr__(self, c_name or self._get_c_name(' &')) + + +class CTypesBackend(object): + + PRIMITIVE_TYPES = { + 'char': ctypes.c_char, + 'short': ctypes.c_short, + 'int': ctypes.c_int, + 'long': ctypes.c_long, + 'long long': ctypes.c_longlong, + 'signed char': ctypes.c_byte, + 'unsigned char': ctypes.c_ubyte, + 'unsigned short': ctypes.c_ushort, + 'unsigned int': ctypes.c_uint, + 'unsigned long': ctypes.c_ulong, + 'unsigned long long': ctypes.c_ulonglong, + 'float': ctypes.c_float, + 'double': ctypes.c_double, + '_Bool': ctypes.c_bool, + } + + for _name in ['unsigned long long', 'unsigned long', + 'unsigned int', 'unsigned short', 'unsigned char']: + _size = ctypes.sizeof(PRIMITIVE_TYPES[_name]) + PRIMITIVE_TYPES['uint%d_t' % (8*_size)] = PRIMITIVE_TYPES[_name] + if _size == ctypes.sizeof(ctypes.c_void_p): + PRIMITIVE_TYPES['uintptr_t'] = PRIMITIVE_TYPES[_name] + if _size == ctypes.sizeof(ctypes.c_size_t): + PRIMITIVE_TYPES['size_t'] = PRIMITIVE_TYPES[_name] + + for _name in ['long long', 'long', 'int', 'short', 'signed char']: + _size = ctypes.sizeof(PRIMITIVE_TYPES[_name]) + PRIMITIVE_TYPES['int%d_t' % (8*_size)] = PRIMITIVE_TYPES[_name] + if _size == ctypes.sizeof(ctypes.c_void_p): + PRIMITIVE_TYPES['intptr_t'] = PRIMITIVE_TYPES[_name] + PRIMITIVE_TYPES['ptrdiff_t'] = PRIMITIVE_TYPES[_name] + if _size == ctypes.sizeof(ctypes.c_size_t): + PRIMITIVE_TYPES['ssize_t'] = PRIMITIVE_TYPES[_name] + + + def __init__(self): + self.RTLD_LAZY = 0 # not supported anyway by ctypes + self.RTLD_NOW = 0 + self.RTLD_GLOBAL = ctypes.RTLD_GLOBAL + self.RTLD_LOCAL = ctypes.RTLD_LOCAL + + def set_ffi(self, ffi): + self.ffi = ffi + + def _get_types(self): + return CTypesData, CTypesType + + def load_library(self, path, flags=0): + cdll = ctypes.CDLL(path, flags) + return CTypesLibrary(self, cdll) + + def new_void_type(self): + class CTypesVoid(CTypesData): + __slots__ = [] + _reftypename = 'void &' + @staticmethod + def _from_ctypes(novalue): + return None + @staticmethod + def _to_ctypes(novalue): + if novalue is not None: + raise TypeError("None expected, got %s object" % + (type(novalue).__name__,)) + return None + CTypesVoid._fix_class() + return CTypesVoid + + def new_primitive_type(self, name): + if name == 'wchar_t': + raise NotImplementedError(name) + ctype = self.PRIMITIVE_TYPES[name] + if name == 'char': + kind = 'char' + elif name in ('float', 'double'): + kind = 'float' + else: + if name in ('signed char', 'unsigned char'): + kind = 'byte' + elif name == '_Bool': + kind = 'bool' + else: + kind = 'int' + is_signed = (ctype(-1).value == -1) + # + def _cast_source_to_int(source): + if isinstance(source, (int, long, float)): + source = int(source) + elif isinstance(source, CTypesData): + source = source._cast_to_integer() + elif isinstance(source, bytes): + source = ord(source) + elif source is None: + source = 0 + else: + raise TypeError("bad type for cast to %r: %r" % + (CTypesPrimitive, type(source).__name__)) + return source + # + kind1 = kind + class CTypesPrimitive(CTypesGenericPrimitive): + __slots__ = ['_value'] + _ctype = ctype + _reftypename = '%s &' % name + kind = kind1 + + def __init__(self, value): + self._value = value + + @staticmethod + def _create_ctype_obj(init): + if init is None: + return ctype() + return ctype(CTypesPrimitive._to_ctypes(init)) + + if kind == 'int' or kind == 'byte': + @classmethod + def _cast_from(cls, source): + source = _cast_source_to_int(source) + source = ctype(source).value # cast within range + return cls(source) + def __int__(self): + return self._value + + if kind == 'bool': + @classmethod + def _cast_from(cls, source): + if not isinstance(source, (int, long, float)): + source = _cast_source_to_int(source) + return cls(bool(source)) + def __int__(self): + return int(self._value) + + if kind == 'char': + @classmethod + def _cast_from(cls, source): + source = _cast_source_to_int(source) + source = bytechr(source & 0xFF) + return cls(source) + def __int__(self): + return ord(self._value) + + if kind == 'float': + @classmethod + def _cast_from(cls, source): + if isinstance(source, float): + pass + elif isinstance(source, CTypesGenericPrimitive): + if hasattr(source, '__float__'): + source = float(source) + else: + source = int(source) + else: + source = _cast_source_to_int(source) + source = ctype(source).value # fix precision + return cls(source) + def __int__(self): + return int(self._value) + def __float__(self): + return self._value + + _cast_to_integer = __int__ + + if kind == 'int' or kind == 'byte' or kind == 'bool': + @staticmethod + def _to_ctypes(x): + if not isinstance(x, (int, long)): + if isinstance(x, CTypesData): + x = int(x) + else: + raise TypeError("integer expected, got %s" % + type(x).__name__) + if ctype(x).value != x: + if not is_signed and x < 0: + raise OverflowError("%s: negative integer" % name) + else: + raise OverflowError("%s: integer out of bounds" + % name) + return x + + if kind == 'char': + @staticmethod + def _to_ctypes(x): + if isinstance(x, bytes) and len(x) == 1: + return x + if isinstance(x, CTypesPrimitive): # > + return x._value + raise TypeError("character expected, got %s" % + type(x).__name__) + def __nonzero__(self): + return ord(self._value) != 0 + else: + def __nonzero__(self): + return self._value != 0 + __bool__ = __nonzero__ + + if kind == 'float': + @staticmethod + def _to_ctypes(x): + if not isinstance(x, (int, long, float, CTypesData)): + raise TypeError("float expected, got %s" % + type(x).__name__) + return ctype(x).value + + @staticmethod + def _from_ctypes(value): + return getattr(value, 'value', value) + + @staticmethod + def _initialize(blob, init): + blob.value = CTypesPrimitive._to_ctypes(init) + + if kind == 'char': + def _to_string(self, maxlen): + return self._value + if kind == 'byte': + def _to_string(self, maxlen): + return chr(self._value & 0xff) + # + CTypesPrimitive._fix_class() + return CTypesPrimitive + + def new_pointer_type(self, BItem): + getbtype = self.ffi._get_cached_btype + if BItem is getbtype(model.PrimitiveType('char')): + kind = 'charp' + elif BItem in (getbtype(model.PrimitiveType('signed char')), + getbtype(model.PrimitiveType('unsigned char'))): + kind = 'bytep' + elif BItem is getbtype(model.void_type): + kind = 'voidp' + else: + kind = 'generic' + # + class CTypesPtr(CTypesGenericPtr): + __slots__ = ['_own'] + if kind == 'charp': + __slots__ += ['__as_strbuf'] + _BItem = BItem + if hasattr(BItem, '_ctype'): + _ctype = ctypes.POINTER(BItem._ctype) + _bitem_size = ctypes.sizeof(BItem._ctype) + else: + _ctype = ctypes.c_void_p + if issubclass(BItem, CTypesGenericArray): + _reftypename = BItem._get_c_name('(* &)') + else: + _reftypename = BItem._get_c_name(' * &') + + def __init__(self, init): + ctypeobj = BItem._create_ctype_obj(init) + if kind == 'charp': + self.__as_strbuf = ctypes.create_string_buffer( + ctypeobj.value + b'\x00') + self._as_ctype_ptr = ctypes.cast( + self.__as_strbuf, self._ctype) + else: + self._as_ctype_ptr = ctypes.pointer(ctypeobj) + self._address = ctypes.cast(self._as_ctype_ptr, + ctypes.c_void_p).value + self._own = True + + def __add__(self, other): + if isinstance(other, (int, long)): + return self._new_pointer_at(self._address + + other * self._bitem_size) + else: + return NotImplemented + + def __sub__(self, other): + if isinstance(other, (int, long)): + return self._new_pointer_at(self._address - + other * self._bitem_size) + elif type(self) is type(other): + return (self._address - other._address) // self._bitem_size + else: + return NotImplemented + + def __getitem__(self, index): + if getattr(self, '_own', False) and index != 0: + raise IndexError + return BItem._from_ctypes(self._as_ctype_ptr[index]) + + def __setitem__(self, index, value): + self._as_ctype_ptr[index] = BItem._to_ctypes(value) + + if kind == 'charp' or kind == 'voidp': + @classmethod + def _arg_to_ctypes(cls, *value): + if value and isinstance(value[0], bytes): + return ctypes.c_char_p(value[0]) + else: + return super(CTypesPtr, cls)._arg_to_ctypes(*value) + + if kind == 'charp' or kind == 'bytep': + def _to_string(self, maxlen): + if maxlen < 0: + maxlen = sys.maxsize + p = ctypes.cast(self._as_ctype_ptr, + ctypes.POINTER(ctypes.c_char)) + n = 0 + while n < maxlen and p[n] != b'\x00': + n += 1 + return b''.join([p[i] for i in range(n)]) + + def _get_own_repr(self): + if getattr(self, '_own', False): + return 'owning %d bytes' % ( + ctypes.sizeof(self._as_ctype_ptr.contents),) + return super(CTypesPtr, self)._get_own_repr() + # + if (BItem is self.ffi._get_cached_btype(model.void_type) or + BItem is self.ffi._get_cached_btype(model.PrimitiveType('char'))): + CTypesPtr._automatic_casts = True + # + CTypesPtr._fix_class() + return CTypesPtr + + def new_array_type(self, CTypesPtr, length): + if length is None: + brackets = ' &[]' + else: + brackets = ' &[%d]' % length + BItem = CTypesPtr._BItem + getbtype = self.ffi._get_cached_btype + if BItem is getbtype(model.PrimitiveType('char')): + kind = 'char' + elif BItem in (getbtype(model.PrimitiveType('signed char')), + getbtype(model.PrimitiveType('unsigned char'))): + kind = 'byte' + else: + kind = 'generic' + # + class CTypesArray(CTypesGenericArray): + __slots__ = ['_blob', '_own'] + if length is not None: + _ctype = BItem._ctype * length + else: + __slots__.append('_ctype') + _reftypename = BItem._get_c_name(brackets) + _declared_length = length + _CTPtr = CTypesPtr + + def __init__(self, init): + if length is None: + if isinstance(init, (int, long)): + len1 = init + init = None + elif kind == 'char' and isinstance(init, bytes): + len1 = len(init) + 1 # extra null + else: + init = tuple(init) + len1 = len(init) + self._ctype = BItem._ctype * len1 + self._blob = self._ctype() + self._own = True + if init is not None: + self._initialize(self._blob, init) + + @staticmethod + def _initialize(blob, init): + if isinstance(init, bytes): + init = [init[i:i+1] for i in range(len(init))] + else: + if isinstance(init, CTypesGenericArray): + if (len(init) != len(blob) or + not isinstance(init, CTypesArray)): + raise TypeError("length/type mismatch: %s" % (init,)) + init = tuple(init) + if len(init) > len(blob): + raise IndexError("too many initializers") + addr = ctypes.cast(blob, ctypes.c_void_p).value + PTR = ctypes.POINTER(BItem._ctype) + itemsize = ctypes.sizeof(BItem._ctype) + for i, value in enumerate(init): + p = ctypes.cast(addr + i * itemsize, PTR) + BItem._initialize(p.contents, value) + + def __len__(self): + return len(self._blob) + + def __getitem__(self, index): + if not (0 <= index < len(self._blob)): + raise IndexError + return BItem._from_ctypes(self._blob[index]) + + def __setitem__(self, index, value): + if not (0 <= index < len(self._blob)): + raise IndexError + self._blob[index] = BItem._to_ctypes(value) + + if kind == 'char' or kind == 'byte': + def _to_string(self, maxlen): + if maxlen < 0: + maxlen = len(self._blob) + p = ctypes.cast(self._blob, + ctypes.POINTER(ctypes.c_char)) + n = 0 + while n < maxlen and p[n] != b'\x00': + n += 1 + return b''.join([p[i] for i in range(n)]) + + def _get_own_repr(self): + if getattr(self, '_own', False): + return 'owning %d bytes' % (ctypes.sizeof(self._blob),) + return super(CTypesArray, self)._get_own_repr() + + def _convert_to_address(self, BClass): + if BClass in (CTypesPtr, None) or BClass._automatic_casts: + return ctypes.addressof(self._blob) + else: + return CTypesData._convert_to_address(self, BClass) + + @staticmethod + def _from_ctypes(ctypes_array): + self = CTypesArray.__new__(CTypesArray) + self._blob = ctypes_array + return self + + @staticmethod + def _arg_to_ctypes(value): + return CTypesPtr._arg_to_ctypes(value) + + def __add__(self, other): + if isinstance(other, (int, long)): + return CTypesPtr._new_pointer_at( + ctypes.addressof(self._blob) + + other * ctypes.sizeof(BItem._ctype)) + else: + return NotImplemented + + @classmethod + def _cast_from(cls, source): + raise NotImplementedError("casting to %r" % ( + cls._get_c_name(),)) + # + CTypesArray._fix_class() + return CTypesArray + + def _new_struct_or_union(self, kind, name, base_ctypes_class): + # + class struct_or_union(base_ctypes_class): + pass + struct_or_union.__name__ = '%s_%s' % (kind, name) + kind1 = kind + # + class CTypesStructOrUnion(CTypesBaseStructOrUnion): + __slots__ = ['_blob'] + _ctype = struct_or_union + _reftypename = '%s &' % (name,) + _kind = kind = kind1 + # + CTypesStructOrUnion._fix_class() + return CTypesStructOrUnion + + def new_struct_type(self, name): + return self._new_struct_or_union('struct', name, ctypes.Structure) + + def new_union_type(self, name): + return self._new_struct_or_union('union', name, ctypes.Union) + + def complete_struct_or_union(self, CTypesStructOrUnion, fields, tp, + totalsize=-1, totalalignment=-1, sflags=0, + pack=0): + if totalsize >= 0 or totalalignment >= 0: + raise NotImplementedError("the ctypes backend of CFFI does not support " + "structures completed by verify(); please " + "compile and install the _cffi_backend module.") + struct_or_union = CTypesStructOrUnion._ctype + fnames = [fname for (fname, BField, bitsize) in fields] + btypes = [BField for (fname, BField, bitsize) in fields] + bitfields = [bitsize for (fname, BField, bitsize) in fields] + # + bfield_types = {} + cfields = [] + for (fname, BField, bitsize) in fields: + if bitsize < 0: + cfields.append((fname, BField._ctype)) + bfield_types[fname] = BField + else: + cfields.append((fname, BField._ctype, bitsize)) + bfield_types[fname] = Ellipsis + if sflags & 8: + struct_or_union._pack_ = 1 + elif pack: + struct_or_union._pack_ = pack + struct_or_union._fields_ = cfields + CTypesStructOrUnion._bfield_types = bfield_types + # + @staticmethod + def _create_ctype_obj(init): + result = struct_or_union() + if init is not None: + initialize(result, init) + return result + CTypesStructOrUnion._create_ctype_obj = _create_ctype_obj + # + def initialize(blob, init): + if is_union: + if len(init) > 1: + raise ValueError("union initializer: %d items given, but " + "only one supported (use a dict if needed)" + % (len(init),)) + if not isinstance(init, dict): + if isinstance(init, (bytes, unicode)): + raise TypeError("union initializer: got a str") + init = tuple(init) + if len(init) > len(fnames): + raise ValueError("too many values for %s initializer" % + CTypesStructOrUnion._get_c_name()) + init = dict(zip(fnames, init)) + addr = ctypes.addressof(blob) + for fname, value in init.items(): + BField, bitsize = name2fieldtype[fname] + assert bitsize < 0, \ + "not implemented: initializer with bit fields" + offset = CTypesStructOrUnion._offsetof(fname) + PTR = ctypes.POINTER(BField._ctype) + p = ctypes.cast(addr + offset, PTR) + BField._initialize(p.contents, value) + is_union = CTypesStructOrUnion._kind == 'union' + name2fieldtype = dict(zip(fnames, zip(btypes, bitfields))) + # + for fname, BField, bitsize in fields: + if fname == '': + raise NotImplementedError("nested anonymous structs/unions") + if hasattr(CTypesStructOrUnion, fname): + raise ValueError("the field name %r conflicts in " + "the ctypes backend" % fname) + if bitsize < 0: + def getter(self, fname=fname, BField=BField, + offset=CTypesStructOrUnion._offsetof(fname), + PTR=ctypes.POINTER(BField._ctype)): + addr = ctypes.addressof(self._blob) + p = ctypes.cast(addr + offset, PTR) + return BField._from_ctypes(p.contents) + def setter(self, value, fname=fname, BField=BField): + setattr(self._blob, fname, BField._to_ctypes(value)) + # + if issubclass(BField, CTypesGenericArray): + setter = None + if BField._declared_length == 0: + def getter(self, fname=fname, BFieldPtr=BField._CTPtr, + offset=CTypesStructOrUnion._offsetof(fname), + PTR=ctypes.POINTER(BField._ctype)): + addr = ctypes.addressof(self._blob) + p = ctypes.cast(addr + offset, PTR) + return BFieldPtr._from_ctypes(p) + # + else: + def getter(self, fname=fname, BField=BField): + return BField._from_ctypes(getattr(self._blob, fname)) + def setter(self, value, fname=fname, BField=BField): + # xxx obscure workaround + value = BField._to_ctypes(value) + oldvalue = getattr(self._blob, fname) + setattr(self._blob, fname, value) + if value != getattr(self._blob, fname): + setattr(self._blob, fname, oldvalue) + raise OverflowError("value too large for bitfield") + setattr(CTypesStructOrUnion, fname, property(getter, setter)) + # + CTypesPtr = self.ffi._get_cached_btype(model.PointerType(tp)) + for fname in fnames: + if hasattr(CTypesPtr, fname): + raise ValueError("the field name %r conflicts in " + "the ctypes backend" % fname) + def getter(self, fname=fname): + return getattr(self[0], fname) + def setter(self, value, fname=fname): + setattr(self[0], fname, value) + setattr(CTypesPtr, fname, property(getter, setter)) + + def new_function_type(self, BArgs, BResult, has_varargs): + nameargs = [BArg._get_c_name() for BArg in BArgs] + if has_varargs: + nameargs.append('...') + nameargs = ', '.join(nameargs) + # + class CTypesFunctionPtr(CTypesGenericPtr): + __slots__ = ['_own_callback', '_name'] + _ctype = ctypes.CFUNCTYPE(getattr(BResult, '_ctype', None), + *[BArg._ctype for BArg in BArgs], + use_errno=True) + _reftypename = BResult._get_c_name('(* &)(%s)' % (nameargs,)) + + def __init__(self, init, error=None): + # create a callback to the Python callable init() + import traceback + assert not has_varargs, "varargs not supported for callbacks" + if getattr(BResult, '_ctype', None) is not None: + error = BResult._from_ctypes( + BResult._create_ctype_obj(error)) + else: + error = None + def callback(*args): + args2 = [] + for arg, BArg in zip(args, BArgs): + args2.append(BArg._from_ctypes(arg)) + try: + res2 = init(*args2) + res2 = BResult._to_ctypes(res2) + except: + traceback.print_exc() + res2 = error + if issubclass(BResult, CTypesGenericPtr): + if res2: + res2 = ctypes.cast(res2, ctypes.c_void_p).value + # .value: http://bugs.python.org/issue1574593 + else: + res2 = None + #print repr(res2) + return res2 + if issubclass(BResult, CTypesGenericPtr): + # The only pointers callbacks can return are void*s: + # http://bugs.python.org/issue5710 + callback_ctype = ctypes.CFUNCTYPE( + ctypes.c_void_p, + *[BArg._ctype for BArg in BArgs], + use_errno=True) + else: + callback_ctype = CTypesFunctionPtr._ctype + self._as_ctype_ptr = callback_ctype(callback) + self._address = ctypes.cast(self._as_ctype_ptr, + ctypes.c_void_p).value + self._own_callback = init + + @staticmethod + def _initialize(ctypes_ptr, value): + if value: + raise NotImplementedError("ctypes backend: not supported: " + "initializers for function pointers") + + def __repr__(self): + c_name = getattr(self, '_name', None) + if c_name: + i = self._reftypename.index('(* &)') + if self._reftypename[i-1] not in ' )*': + c_name = ' ' + c_name + c_name = self._reftypename.replace('(* &)', c_name) + return CTypesData.__repr__(self, c_name) + + def _get_own_repr(self): + if getattr(self, '_own_callback', None) is not None: + return 'calling %r' % (self._own_callback,) + return super(CTypesFunctionPtr, self)._get_own_repr() + + def __call__(self, *args): + if has_varargs: + assert len(args) >= len(BArgs) + extraargs = args[len(BArgs):] + args = args[:len(BArgs)] + else: + assert len(args) == len(BArgs) + ctypes_args = [] + for arg, BArg in zip(args, BArgs): + ctypes_args.append(BArg._arg_to_ctypes(arg)) + if has_varargs: + for i, arg in enumerate(extraargs): + if arg is None: + ctypes_args.append(ctypes.c_void_p(0)) # NULL + continue + if not isinstance(arg, CTypesData): + raise TypeError( + "argument %d passed in the variadic part " + "needs to be a cdata object (got %s)" % + (1 + len(BArgs) + i, type(arg).__name__)) + ctypes_args.append(arg._arg_to_ctypes(arg)) + result = self._as_ctype_ptr(*ctypes_args) + return BResult._from_ctypes(result) + # + CTypesFunctionPtr._fix_class() + return CTypesFunctionPtr + + def new_enum_type(self, name, enumerators, enumvalues, CTypesInt): + assert isinstance(name, str) + reverse_mapping = dict(zip(reversed(enumvalues), + reversed(enumerators))) + # + class CTypesEnum(CTypesInt): + __slots__ = [] + _reftypename = '%s &' % name + + def _get_own_repr(self): + value = self._value + try: + return '%d: %s' % (value, reverse_mapping[value]) + except KeyError: + return str(value) + + def _to_string(self, maxlen): + value = self._value + try: + return reverse_mapping[value] + except KeyError: + return str(value) + # + CTypesEnum._fix_class() + return CTypesEnum + + def get_errno(self): + return ctypes.get_errno() + + def set_errno(self, value): + ctypes.set_errno(value) + + def string(self, b, maxlen=-1): + return b._to_string(maxlen) + + def buffer(self, bptr, size=-1): + raise NotImplementedError("buffer() with ctypes backend") + + def sizeof(self, cdata_or_BType): + if isinstance(cdata_or_BType, CTypesData): + return cdata_or_BType._get_size_of_instance() + else: + assert issubclass(cdata_or_BType, CTypesData) + return cdata_or_BType._get_size() + + def alignof(self, BType): + assert issubclass(BType, CTypesData) + return BType._alignment() + + def newp(self, BType, source): + if not issubclass(BType, CTypesData): + raise TypeError + return BType._newp(source) + + def cast(self, BType, source): + return BType._cast_from(source) + + def callback(self, BType, source, error, onerror): + assert onerror is None # XXX not implemented + return BType(source, error) + + _weakref_cache_ref = None + + def gcp(self, cdata, destructor, size=0): + if self._weakref_cache_ref is None: + import weakref + class MyRef(weakref.ref): + def __eq__(self, other): + myref = self() + return self is other or ( + myref is not None and myref is other()) + def __ne__(self, other): + return not (self == other) + def __hash__(self): + try: + return self._hash + except AttributeError: + self._hash = hash(self()) + return self._hash + self._weakref_cache_ref = {}, MyRef + weak_cache, MyRef = self._weakref_cache_ref + + if destructor is None: + try: + del weak_cache[MyRef(cdata)] + except KeyError: + raise TypeError("Can remove destructor only on a object " + "previously returned by ffi.gc()") + return None + + def remove(k): + cdata, destructor = weak_cache.pop(k, (None, None)) + if destructor is not None: + destructor(cdata) + + new_cdata = self.cast(self.typeof(cdata), cdata) + assert new_cdata is not cdata + weak_cache[MyRef(new_cdata, remove)] = (cdata, destructor) + return new_cdata + + typeof = type + + def getcname(self, BType, replace_with): + return BType._get_c_name(replace_with) + + def typeoffsetof(self, BType, fieldname, num=0): + if isinstance(fieldname, str): + if num == 0 and issubclass(BType, CTypesGenericPtr): + BType = BType._BItem + if not issubclass(BType, CTypesBaseStructOrUnion): + raise TypeError("expected a struct or union ctype") + BField = BType._bfield_types[fieldname] + if BField is Ellipsis: + raise TypeError("not supported for bitfields") + return (BField, BType._offsetof(fieldname)) + elif isinstance(fieldname, (int, long)): + if issubclass(BType, CTypesGenericArray): + BType = BType._CTPtr + if not issubclass(BType, CTypesGenericPtr): + raise TypeError("expected an array or ptr ctype") + BItem = BType._BItem + offset = BItem._get_size() * fieldname + if offset > sys.maxsize: + raise OverflowError + return (BItem, offset) + else: + raise TypeError(type(fieldname)) + + def rawaddressof(self, BTypePtr, cdata, offset=None): + if isinstance(cdata, CTypesBaseStructOrUnion): + ptr = ctypes.pointer(type(cdata)._to_ctypes(cdata)) + elif isinstance(cdata, CTypesGenericPtr): + if offset is None or not issubclass(type(cdata)._BItem, + CTypesBaseStructOrUnion): + raise TypeError("unexpected cdata type") + ptr = type(cdata)._to_ctypes(cdata) + elif isinstance(cdata, CTypesGenericArray): + ptr = type(cdata)._to_ctypes(cdata) + else: + raise TypeError("expected a ") + if offset: + ptr = ctypes.cast( + ctypes.c_void_p( + ctypes.cast(ptr, ctypes.c_void_p).value + offset), + type(ptr)) + return BTypePtr._from_ctypes(ptr) + + +class CTypesLibrary(object): + + def __init__(self, backend, cdll): + self.backend = backend + self.cdll = cdll + + def load_function(self, BType, name): + c_func = getattr(self.cdll, name) + funcobj = BType._from_ctypes(c_func) + funcobj._name = name + return funcobj + + def read_variable(self, BType, name): + try: + ctypes_obj = BType._ctype.in_dll(self.cdll, name) + except AttributeError as e: + raise NotImplementedError(e) + return BType._from_ctypes(ctypes_obj) + + def write_variable(self, BType, name, value): + new_ctypes_obj = BType._to_ctypes(value) + ctypes_obj = BType._ctype.in_dll(self.cdll, name) + ctypes.memmove(ctypes.addressof(ctypes_obj), + ctypes.addressof(new_ctypes_obj), + ctypes.sizeof(BType._ctype)) diff --git a/venv/Lib/site-packages/cffi/cffi_opcode.py b/venv/Lib/site-packages/cffi/cffi_opcode.py new file mode 100644 index 000000000..a0df98d1c --- /dev/null +++ b/venv/Lib/site-packages/cffi/cffi_opcode.py @@ -0,0 +1,187 @@ +from .error import VerificationError + +class CffiOp(object): + def __init__(self, op, arg): + self.op = op + self.arg = arg + + def as_c_expr(self): + if self.op is None: + assert isinstance(self.arg, str) + return '(_cffi_opcode_t)(%s)' % (self.arg,) + classname = CLASS_NAME[self.op] + return '_CFFI_OP(_CFFI_OP_%s, %s)' % (classname, self.arg) + + def as_python_bytes(self): + if self.op is None and self.arg.isdigit(): + value = int(self.arg) # non-negative: '-' not in self.arg + if value >= 2**31: + raise OverflowError("cannot emit %r: limited to 2**31-1" + % (self.arg,)) + return format_four_bytes(value) + if isinstance(self.arg, str): + raise VerificationError("cannot emit to Python: %r" % (self.arg,)) + return format_four_bytes((self.arg << 8) | self.op) + + def __str__(self): + classname = CLASS_NAME.get(self.op, self.op) + return '(%s %s)' % (classname, self.arg) + +def format_four_bytes(num): + return '\\x%02X\\x%02X\\x%02X\\x%02X' % ( + (num >> 24) & 0xFF, + (num >> 16) & 0xFF, + (num >> 8) & 0xFF, + (num ) & 0xFF) + +OP_PRIMITIVE = 1 +OP_POINTER = 3 +OP_ARRAY = 5 +OP_OPEN_ARRAY = 7 +OP_STRUCT_UNION = 9 +OP_ENUM = 11 +OP_FUNCTION = 13 +OP_FUNCTION_END = 15 +OP_NOOP = 17 +OP_BITFIELD = 19 +OP_TYPENAME = 21 +OP_CPYTHON_BLTN_V = 23 # varargs +OP_CPYTHON_BLTN_N = 25 # noargs +OP_CPYTHON_BLTN_O = 27 # O (i.e. a single arg) +OP_CONSTANT = 29 +OP_CONSTANT_INT = 31 +OP_GLOBAL_VAR = 33 +OP_DLOPEN_FUNC = 35 +OP_DLOPEN_CONST = 37 +OP_GLOBAL_VAR_F = 39 +OP_EXTERN_PYTHON = 41 + +PRIM_VOID = 0 +PRIM_BOOL = 1 +PRIM_CHAR = 2 +PRIM_SCHAR = 3 +PRIM_UCHAR = 4 +PRIM_SHORT = 5 +PRIM_USHORT = 6 +PRIM_INT = 7 +PRIM_UINT = 8 +PRIM_LONG = 9 +PRIM_ULONG = 10 +PRIM_LONGLONG = 11 +PRIM_ULONGLONG = 12 +PRIM_FLOAT = 13 +PRIM_DOUBLE = 14 +PRIM_LONGDOUBLE = 15 + +PRIM_WCHAR = 16 +PRIM_INT8 = 17 +PRIM_UINT8 = 18 +PRIM_INT16 = 19 +PRIM_UINT16 = 20 +PRIM_INT32 = 21 +PRIM_UINT32 = 22 +PRIM_INT64 = 23 +PRIM_UINT64 = 24 +PRIM_INTPTR = 25 +PRIM_UINTPTR = 26 +PRIM_PTRDIFF = 27 +PRIM_SIZE = 28 +PRIM_SSIZE = 29 +PRIM_INT_LEAST8 = 30 +PRIM_UINT_LEAST8 = 31 +PRIM_INT_LEAST16 = 32 +PRIM_UINT_LEAST16 = 33 +PRIM_INT_LEAST32 = 34 +PRIM_UINT_LEAST32 = 35 +PRIM_INT_LEAST64 = 36 +PRIM_UINT_LEAST64 = 37 +PRIM_INT_FAST8 = 38 +PRIM_UINT_FAST8 = 39 +PRIM_INT_FAST16 = 40 +PRIM_UINT_FAST16 = 41 +PRIM_INT_FAST32 = 42 +PRIM_UINT_FAST32 = 43 +PRIM_INT_FAST64 = 44 +PRIM_UINT_FAST64 = 45 +PRIM_INTMAX = 46 +PRIM_UINTMAX = 47 +PRIM_FLOATCOMPLEX = 48 +PRIM_DOUBLECOMPLEX = 49 +PRIM_CHAR16 = 50 +PRIM_CHAR32 = 51 + +_NUM_PRIM = 52 +_UNKNOWN_PRIM = -1 +_UNKNOWN_FLOAT_PRIM = -2 +_UNKNOWN_LONG_DOUBLE = -3 + +_IO_FILE_STRUCT = -1 + +PRIMITIVE_TO_INDEX = { + 'char': PRIM_CHAR, + 'short': PRIM_SHORT, + 'int': PRIM_INT, + 'long': PRIM_LONG, + 'long long': PRIM_LONGLONG, + 'signed char': PRIM_SCHAR, + 'unsigned char': PRIM_UCHAR, + 'unsigned short': PRIM_USHORT, + 'unsigned int': PRIM_UINT, + 'unsigned long': PRIM_ULONG, + 'unsigned long long': PRIM_ULONGLONG, + 'float': PRIM_FLOAT, + 'double': PRIM_DOUBLE, + 'long double': PRIM_LONGDOUBLE, + 'float _Complex': PRIM_FLOATCOMPLEX, + 'double _Complex': PRIM_DOUBLECOMPLEX, + '_Bool': PRIM_BOOL, + 'wchar_t': PRIM_WCHAR, + 'char16_t': PRIM_CHAR16, + 'char32_t': PRIM_CHAR32, + 'int8_t': PRIM_INT8, + 'uint8_t': PRIM_UINT8, + 'int16_t': PRIM_INT16, + 'uint16_t': PRIM_UINT16, + 'int32_t': PRIM_INT32, + 'uint32_t': PRIM_UINT32, + 'int64_t': PRIM_INT64, + 'uint64_t': PRIM_UINT64, + 'intptr_t': PRIM_INTPTR, + 'uintptr_t': PRIM_UINTPTR, + 'ptrdiff_t': PRIM_PTRDIFF, + 'size_t': PRIM_SIZE, + 'ssize_t': PRIM_SSIZE, + 'int_least8_t': PRIM_INT_LEAST8, + 'uint_least8_t': PRIM_UINT_LEAST8, + 'int_least16_t': PRIM_INT_LEAST16, + 'uint_least16_t': PRIM_UINT_LEAST16, + 'int_least32_t': PRIM_INT_LEAST32, + 'uint_least32_t': PRIM_UINT_LEAST32, + 'int_least64_t': PRIM_INT_LEAST64, + 'uint_least64_t': PRIM_UINT_LEAST64, + 'int_fast8_t': PRIM_INT_FAST8, + 'uint_fast8_t': PRIM_UINT_FAST8, + 'int_fast16_t': PRIM_INT_FAST16, + 'uint_fast16_t': PRIM_UINT_FAST16, + 'int_fast32_t': PRIM_INT_FAST32, + 'uint_fast32_t': PRIM_UINT_FAST32, + 'int_fast64_t': PRIM_INT_FAST64, + 'uint_fast64_t': PRIM_UINT_FAST64, + 'intmax_t': PRIM_INTMAX, + 'uintmax_t': PRIM_UINTMAX, + } + +F_UNION = 0x01 +F_CHECK_FIELDS = 0x02 +F_PACKED = 0x04 +F_EXTERNAL = 0x08 +F_OPAQUE = 0x10 + +G_FLAGS = dict([('_CFFI_' + _key, globals()[_key]) + for _key in ['F_UNION', 'F_CHECK_FIELDS', 'F_PACKED', + 'F_EXTERNAL', 'F_OPAQUE']]) + +CLASS_NAME = {} +for _name, _value in list(globals().items()): + if _name.startswith('OP_') and isinstance(_value, int): + CLASS_NAME[_value] = _name[3:] diff --git a/venv/Lib/site-packages/cffi/commontypes.py b/venv/Lib/site-packages/cffi/commontypes.py new file mode 100644 index 000000000..8ec97c756 --- /dev/null +++ b/venv/Lib/site-packages/cffi/commontypes.py @@ -0,0 +1,80 @@ +import sys +from . import model +from .error import FFIError + + +COMMON_TYPES = {} + +try: + # fetch "bool" and all simple Windows types + from _cffi_backend import _get_common_types + _get_common_types(COMMON_TYPES) +except ImportError: + pass + +COMMON_TYPES['FILE'] = model.unknown_type('FILE', '_IO_FILE') +COMMON_TYPES['bool'] = '_Bool' # in case we got ImportError above + +for _type in model.PrimitiveType.ALL_PRIMITIVE_TYPES: + if _type.endswith('_t'): + COMMON_TYPES[_type] = _type +del _type + +_CACHE = {} + +def resolve_common_type(parser, commontype): + try: + return _CACHE[commontype] + except KeyError: + cdecl = COMMON_TYPES.get(commontype, commontype) + if not isinstance(cdecl, str): + result, quals = cdecl, 0 # cdecl is already a BaseType + elif cdecl in model.PrimitiveType.ALL_PRIMITIVE_TYPES: + result, quals = model.PrimitiveType(cdecl), 0 + elif cdecl == 'set-unicode-needed': + raise FFIError("The Windows type %r is only available after " + "you call ffi.set_unicode()" % (commontype,)) + else: + if commontype == cdecl: + raise FFIError( + "Unsupported type: %r. Please look at " + "http://cffi.readthedocs.io/en/latest/cdef.html#ffi-cdef-limitations " + "and file an issue if you think this type should really " + "be supported." % (commontype,)) + result, quals = parser.parse_type_and_quals(cdecl) # recursive + + assert isinstance(result, model.BaseTypeByIdentity) + _CACHE[commontype] = result, quals + return result, quals + + +# ____________________________________________________________ +# extra types for Windows (most of them are in commontypes.c) + + +def win_common_types(): + return { + "UNICODE_STRING": model.StructType( + "_UNICODE_STRING", + ["Length", + "MaximumLength", + "Buffer"], + [model.PrimitiveType("unsigned short"), + model.PrimitiveType("unsigned short"), + model.PointerType(model.PrimitiveType("wchar_t"))], + [-1, -1, -1]), + "PUNICODE_STRING": "UNICODE_STRING *", + "PCUNICODE_STRING": "const UNICODE_STRING *", + + "TBYTE": "set-unicode-needed", + "TCHAR": "set-unicode-needed", + "LPCTSTR": "set-unicode-needed", + "PCTSTR": "set-unicode-needed", + "LPTSTR": "set-unicode-needed", + "PTSTR": "set-unicode-needed", + "PTBYTE": "set-unicode-needed", + "PTCHAR": "set-unicode-needed", + } + +if sys.platform == 'win32': + COMMON_TYPES.update(win_common_types()) diff --git a/venv/Lib/site-packages/cffi/cparser.py b/venv/Lib/site-packages/cffi/cparser.py new file mode 100644 index 000000000..74830e913 --- /dev/null +++ b/venv/Lib/site-packages/cffi/cparser.py @@ -0,0 +1,1006 @@ +from . import model +from .commontypes import COMMON_TYPES, resolve_common_type +from .error import FFIError, CDefError +try: + from . import _pycparser as pycparser +except ImportError: + import pycparser +import weakref, re, sys + +try: + if sys.version_info < (3,): + import thread as _thread + else: + import _thread + lock = _thread.allocate_lock() +except ImportError: + lock = None + +def _workaround_for_static_import_finders(): + # Issue #392: packaging tools like cx_Freeze can not find these + # because pycparser uses exec dynamic import. This is an obscure + # workaround. This function is never called. + import pycparser.yacctab + import pycparser.lextab + +CDEF_SOURCE_STRING = "" +_r_comment = re.compile(r"/\*.*?\*/|//([^\n\\]|\\.)*?$", + re.DOTALL | re.MULTILINE) +_r_define = re.compile(r"^\s*#\s*define\s+([A-Za-z_][A-Za-z_0-9]*)" + r"\b((?:[^\n\\]|\\.)*?)$", + re.DOTALL | re.MULTILINE) +_r_line_directive = re.compile(r"^[ \t]*#[ \t]*(?:line|\d+)\b.*$", re.MULTILINE) +_r_partial_enum = re.compile(r"=\s*\.\.\.\s*[,}]|\.\.\.\s*\}") +_r_enum_dotdotdot = re.compile(r"__dotdotdot\d+__$") +_r_partial_array = re.compile(r"\[\s*\.\.\.\s*\]") +_r_words = re.compile(r"\w+|\S") +_parser_cache = None +_r_int_literal = re.compile(r"-?0?x?[0-9a-f]+[lu]*$", re.IGNORECASE) +_r_stdcall1 = re.compile(r"\b(__stdcall|WINAPI)\b") +_r_stdcall2 = re.compile(r"[(]\s*(__stdcall|WINAPI)\b") +_r_cdecl = re.compile(r"\b__cdecl\b") +_r_extern_python = re.compile(r'\bextern\s*"' + r'(Python|Python\s*\+\s*C|C\s*\+\s*Python)"\s*.') +_r_star_const_space = re.compile( # matches "* const " + r"[*]\s*((const|volatile|restrict)\b\s*)+") +_r_int_dotdotdot = re.compile(r"(\b(int|long|short|signed|unsigned|char)\s*)+" + r"\.\.\.") +_r_float_dotdotdot = re.compile(r"\b(double|float)\s*\.\.\.") + +def _get_parser(): + global _parser_cache + if _parser_cache is None: + _parser_cache = pycparser.CParser() + return _parser_cache + +def _workaround_for_old_pycparser(csource): + # Workaround for a pycparser issue (fixed between pycparser 2.10 and + # 2.14): "char*const***" gives us a wrong syntax tree, the same as + # for "char***(*const)". This means we can't tell the difference + # afterwards. But "char(*const(***))" gives us the right syntax + # tree. The issue only occurs if there are several stars in + # sequence with no parenthesis inbetween, just possibly qualifiers. + # Attempt to fix it by adding some parentheses in the source: each + # time we see "* const" or "* const *", we add an opening + # parenthesis before each star---the hard part is figuring out where + # to close them. + parts = [] + while True: + match = _r_star_const_space.search(csource) + if not match: + break + #print repr(''.join(parts)+csource), '=>', + parts.append(csource[:match.start()]) + parts.append('('); closing = ')' + parts.append(match.group()) # e.g. "* const " + endpos = match.end() + if csource.startswith('*', endpos): + parts.append('('); closing += ')' + level = 0 + i = endpos + while i < len(csource): + c = csource[i] + if c == '(': + level += 1 + elif c == ')': + if level == 0: + break + level -= 1 + elif c in ',;=': + if level == 0: + break + i += 1 + csource = csource[endpos:i] + closing + csource[i:] + #print repr(''.join(parts)+csource) + parts.append(csource) + return ''.join(parts) + +def _preprocess_extern_python(csource): + # input: `extern "Python" int foo(int);` or + # `extern "Python" { int foo(int); }` + # output: + # void __cffi_extern_python_start; + # int foo(int); + # void __cffi_extern_python_stop; + # + # input: `extern "Python+C" int foo(int);` + # output: + # void __cffi_extern_python_plus_c_start; + # int foo(int); + # void __cffi_extern_python_stop; + parts = [] + while True: + match = _r_extern_python.search(csource) + if not match: + break + endpos = match.end() - 1 + #print + #print ''.join(parts)+csource + #print '=>' + parts.append(csource[:match.start()]) + if 'C' in match.group(1): + parts.append('void __cffi_extern_python_plus_c_start; ') + else: + parts.append('void __cffi_extern_python_start; ') + if csource[endpos] == '{': + # grouping variant + closing = csource.find('}', endpos) + if closing < 0: + raise CDefError("'extern \"Python\" {': no '}' found") + if csource.find('{', endpos + 1, closing) >= 0: + raise NotImplementedError("cannot use { } inside a block " + "'extern \"Python\" { ... }'") + parts.append(csource[endpos+1:closing]) + csource = csource[closing+1:] + else: + # non-grouping variant + semicolon = csource.find(';', endpos) + if semicolon < 0: + raise CDefError("'extern \"Python\": no ';' found") + parts.append(csource[endpos:semicolon+1]) + csource = csource[semicolon+1:] + parts.append(' void __cffi_extern_python_stop;') + #print ''.join(parts)+csource + #print + parts.append(csource) + return ''.join(parts) + +def _warn_for_string_literal(csource): + if '"' not in csource: + return + for line in csource.splitlines(): + if '"' in line and not line.lstrip().startswith('#'): + import warnings + warnings.warn("String literal found in cdef() or type source. " + "String literals are ignored here, but you should " + "remove them anyway because some character sequences " + "confuse pre-parsing.") + break + +def _warn_for_non_extern_non_static_global_variable(decl): + if not decl.storage: + import warnings + warnings.warn("Global variable '%s' in cdef(): for consistency " + "with C it should have a storage class specifier " + "(usually 'extern')" % (decl.name,)) + +def _remove_line_directives(csource): + # _r_line_directive matches whole lines, without the final \n, if they + # start with '#line' with some spacing allowed, or '#NUMBER'. This + # function stores them away and replaces them with exactly the string + # '#line@N', where N is the index in the list 'line_directives'. + line_directives = [] + def replace(m): + i = len(line_directives) + line_directives.append(m.group()) + return '#line@%d' % i + csource = _r_line_directive.sub(replace, csource) + return csource, line_directives + +def _put_back_line_directives(csource, line_directives): + def replace(m): + s = m.group() + if not s.startswith('#line@'): + raise AssertionError("unexpected #line directive " + "(should have been processed and removed") + return line_directives[int(s[6:])] + return _r_line_directive.sub(replace, csource) + +def _preprocess(csource): + # First, remove the lines of the form '#line N "filename"' because + # the "filename" part could confuse the rest + csource, line_directives = _remove_line_directives(csource) + # Remove comments. NOTE: this only work because the cdef() section + # should not contain any string literals (except in line directives)! + def replace_keeping_newlines(m): + return ' ' + m.group().count('\n') * '\n' + csource = _r_comment.sub(replace_keeping_newlines, csource) + # Remove the "#define FOO x" lines + macros = {} + for match in _r_define.finditer(csource): + macroname, macrovalue = match.groups() + macrovalue = macrovalue.replace('\\\n', '').strip() + macros[macroname] = macrovalue + csource = _r_define.sub('', csource) + # + if pycparser.__version__ < '2.14': + csource = _workaround_for_old_pycparser(csource) + # + # BIG HACK: replace WINAPI or __stdcall with "volatile const". + # It doesn't make sense for the return type of a function to be + # "volatile volatile const", so we abuse it to detect __stdcall... + # Hack number 2 is that "int(volatile *fptr)();" is not valid C + # syntax, so we place the "volatile" before the opening parenthesis. + csource = _r_stdcall2.sub(' volatile volatile const(', csource) + csource = _r_stdcall1.sub(' volatile volatile const ', csource) + csource = _r_cdecl.sub(' ', csource) + # + # Replace `extern "Python"` with start/end markers + csource = _preprocess_extern_python(csource) + # + # Now there should not be any string literal left; warn if we get one + _warn_for_string_literal(csource) + # + # Replace "[...]" with "[__dotdotdotarray__]" + csource = _r_partial_array.sub('[__dotdotdotarray__]', csource) + # + # Replace "...}" with "__dotdotdotNUM__}". This construction should + # occur only at the end of enums; at the end of structs we have "...;}" + # and at the end of vararg functions "...);". Also replace "=...[,}]" + # with ",__dotdotdotNUM__[,}]": this occurs in the enums too, when + # giving an unknown value. + matches = list(_r_partial_enum.finditer(csource)) + for number, match in enumerate(reversed(matches)): + p = match.start() + if csource[p] == '=': + p2 = csource.find('...', p, match.end()) + assert p2 > p + csource = '%s,__dotdotdot%d__ %s' % (csource[:p], number, + csource[p2+3:]) + else: + assert csource[p:p+3] == '...' + csource = '%s __dotdotdot%d__ %s' % (csource[:p], number, + csource[p+3:]) + # Replace "int ..." or "unsigned long int..." with "__dotdotdotint__" + csource = _r_int_dotdotdot.sub(' __dotdotdotint__ ', csource) + # Replace "float ..." or "double..." with "__dotdotdotfloat__" + csource = _r_float_dotdotdot.sub(' __dotdotdotfloat__ ', csource) + # Replace all remaining "..." with the same name, "__dotdotdot__", + # which is declared with a typedef for the purpose of C parsing. + csource = csource.replace('...', ' __dotdotdot__ ') + # Finally, put back the line directives + csource = _put_back_line_directives(csource, line_directives) + return csource, macros + +def _common_type_names(csource): + # Look in the source for what looks like usages of types from the + # list of common types. A "usage" is approximated here as the + # appearance of the word, minus a "definition" of the type, which + # is the last word in a "typedef" statement. Approximative only + # but should be fine for all the common types. + look_for_words = set(COMMON_TYPES) + look_for_words.add(';') + look_for_words.add(',') + look_for_words.add('(') + look_for_words.add(')') + look_for_words.add('typedef') + words_used = set() + is_typedef = False + paren = 0 + previous_word = '' + for word in _r_words.findall(csource): + if word in look_for_words: + if word == ';': + if is_typedef: + words_used.discard(previous_word) + look_for_words.discard(previous_word) + is_typedef = False + elif word == 'typedef': + is_typedef = True + paren = 0 + elif word == '(': + paren += 1 + elif word == ')': + paren -= 1 + elif word == ',': + if is_typedef and paren == 0: + words_used.discard(previous_word) + look_for_words.discard(previous_word) + else: # word in COMMON_TYPES + words_used.add(word) + previous_word = word + return words_used + + +class Parser(object): + + def __init__(self): + self._declarations = {} + self._included_declarations = set() + self._anonymous_counter = 0 + self._structnode2type = weakref.WeakKeyDictionary() + self._options = {} + self._int_constants = {} + self._recomplete = [] + self._uses_new_feature = None + + def _parse(self, csource): + csource, macros = _preprocess(csource) + # XXX: for more efficiency we would need to poke into the + # internals of CParser... the following registers the + # typedefs, because their presence or absence influences the + # parsing itself (but what they are typedef'ed to plays no role) + ctn = _common_type_names(csource) + typenames = [] + for name in sorted(self._declarations): + if name.startswith('typedef '): + name = name[8:] + typenames.append(name) + ctn.discard(name) + typenames += sorted(ctn) + # + csourcelines = [] + csourcelines.append('# 1 ""') + for typename in typenames: + csourcelines.append('typedef int %s;' % typename) + csourcelines.append('typedef int __dotdotdotint__, __dotdotdotfloat__,' + ' __dotdotdot__;') + # this forces pycparser to consider the following in the file + # called from line 1 + csourcelines.append('# 1 "%s"' % (CDEF_SOURCE_STRING,)) + csourcelines.append(csource) + fullcsource = '\n'.join(csourcelines) + if lock is not None: + lock.acquire() # pycparser is not thread-safe... + try: + ast = _get_parser().parse(fullcsource) + except pycparser.c_parser.ParseError as e: + self.convert_pycparser_error(e, csource) + finally: + if lock is not None: + lock.release() + # csource will be used to find buggy source text + return ast, macros, csource + + def _convert_pycparser_error(self, e, csource): + # xxx look for ":NUM:" at the start of str(e) + # and interpret that as a line number. This will not work if + # the user gives explicit ``# NUM "FILE"`` directives. + line = None + msg = str(e) + match = re.match(r"%s:(\d+):" % (CDEF_SOURCE_STRING,), msg) + if match: + linenum = int(match.group(1), 10) + csourcelines = csource.splitlines() + if 1 <= linenum <= len(csourcelines): + line = csourcelines[linenum-1] + return line + + def convert_pycparser_error(self, e, csource): + line = self._convert_pycparser_error(e, csource) + + msg = str(e) + if line: + msg = 'cannot parse "%s"\n%s' % (line.strip(), msg) + else: + msg = 'parse error\n%s' % (msg,) + raise CDefError(msg) + + def parse(self, csource, override=False, packed=False, pack=None, + dllexport=False): + if packed: + if packed != True: + raise ValueError("'packed' should be False or True; use " + "'pack' to give another value") + if pack: + raise ValueError("cannot give both 'pack' and 'packed'") + pack = 1 + elif pack: + if pack & (pack - 1): + raise ValueError("'pack' must be a power of two, not %r" % + (pack,)) + else: + pack = 0 + prev_options = self._options + try: + self._options = {'override': override, + 'packed': pack, + 'dllexport': dllexport} + self._internal_parse(csource) + finally: + self._options = prev_options + + def _internal_parse(self, csource): + ast, macros, csource = self._parse(csource) + # add the macros + self._process_macros(macros) + # find the first "__dotdotdot__" and use that as a separator + # between the repeated typedefs and the real csource + iterator = iter(ast.ext) + for decl in iterator: + if decl.name == '__dotdotdot__': + break + else: + assert 0 + current_decl = None + # + try: + self._inside_extern_python = '__cffi_extern_python_stop' + for decl in iterator: + current_decl = decl + if isinstance(decl, pycparser.c_ast.Decl): + self._parse_decl(decl) + elif isinstance(decl, pycparser.c_ast.Typedef): + if not decl.name: + raise CDefError("typedef does not declare any name", + decl) + quals = 0 + if (isinstance(decl.type.type, pycparser.c_ast.IdentifierType) and + decl.type.type.names[-1].startswith('__dotdotdot')): + realtype = self._get_unknown_type(decl) + elif (isinstance(decl.type, pycparser.c_ast.PtrDecl) and + isinstance(decl.type.type, pycparser.c_ast.TypeDecl) and + isinstance(decl.type.type.type, + pycparser.c_ast.IdentifierType) and + decl.type.type.type.names[-1].startswith('__dotdotdot')): + realtype = self._get_unknown_ptr_type(decl) + else: + realtype, quals = self._get_type_and_quals( + decl.type, name=decl.name, partial_length_ok=True, + typedef_example="*(%s *)0" % (decl.name,)) + self._declare('typedef ' + decl.name, realtype, quals=quals) + elif decl.__class__.__name__ == 'Pragma': + pass # skip pragma, only in pycparser 2.15 + else: + raise CDefError("unexpected <%s>: this construct is valid " + "C but not valid in cdef()" % + decl.__class__.__name__, decl) + except CDefError as e: + if len(e.args) == 1: + e.args = e.args + (current_decl,) + raise + except FFIError as e: + msg = self._convert_pycparser_error(e, csource) + if msg: + e.args = (e.args[0] + "\n *** Err: %s" % msg,) + raise + + def _add_constants(self, key, val): + if key in self._int_constants: + if self._int_constants[key] == val: + return # ignore identical double declarations + raise FFIError( + "multiple declarations of constant: %s" % (key,)) + self._int_constants[key] = val + + def _add_integer_constant(self, name, int_str): + int_str = int_str.lower().rstrip("ul") + neg = int_str.startswith('-') + if neg: + int_str = int_str[1:] + # "010" is not valid oct in py3 + if (int_str.startswith("0") and int_str != '0' + and not int_str.startswith("0x")): + int_str = "0o" + int_str[1:] + pyvalue = int(int_str, 0) + if neg: + pyvalue = -pyvalue + self._add_constants(name, pyvalue) + self._declare('macro ' + name, pyvalue) + + def _process_macros(self, macros): + for key, value in macros.items(): + value = value.strip() + if _r_int_literal.match(value): + self._add_integer_constant(key, value) + elif value == '...': + self._declare('macro ' + key, value) + else: + raise CDefError( + 'only supports one of the following syntax:\n' + ' #define %s ... (literally dot-dot-dot)\n' + ' #define %s NUMBER (with NUMBER an integer' + ' constant, decimal/hex/octal)\n' + 'got:\n' + ' #define %s %s' + % (key, key, key, value)) + + def _declare_function(self, tp, quals, decl): + tp = self._get_type_pointer(tp, quals) + if self._options.get('dllexport'): + tag = 'dllexport_python ' + elif self._inside_extern_python == '__cffi_extern_python_start': + tag = 'extern_python ' + elif self._inside_extern_python == '__cffi_extern_python_plus_c_start': + tag = 'extern_python_plus_c ' + else: + tag = 'function ' + self._declare(tag + decl.name, tp) + + def _parse_decl(self, decl): + node = decl.type + if isinstance(node, pycparser.c_ast.FuncDecl): + tp, quals = self._get_type_and_quals(node, name=decl.name) + assert isinstance(tp, model.RawFunctionType) + self._declare_function(tp, quals, decl) + else: + if isinstance(node, pycparser.c_ast.Struct): + self._get_struct_union_enum_type('struct', node) + elif isinstance(node, pycparser.c_ast.Union): + self._get_struct_union_enum_type('union', node) + elif isinstance(node, pycparser.c_ast.Enum): + self._get_struct_union_enum_type('enum', node) + elif not decl.name: + raise CDefError("construct does not declare any variable", + decl) + # + if decl.name: + tp, quals = self._get_type_and_quals(node, + partial_length_ok=True) + if tp.is_raw_function: + self._declare_function(tp, quals, decl) + elif (tp.is_integer_type() and + hasattr(decl, 'init') and + hasattr(decl.init, 'value') and + _r_int_literal.match(decl.init.value)): + self._add_integer_constant(decl.name, decl.init.value) + elif (tp.is_integer_type() and + isinstance(decl.init, pycparser.c_ast.UnaryOp) and + decl.init.op == '-' and + hasattr(decl.init.expr, 'value') and + _r_int_literal.match(decl.init.expr.value)): + self._add_integer_constant(decl.name, + '-' + decl.init.expr.value) + elif (tp is model.void_type and + decl.name.startswith('__cffi_extern_python_')): + # hack: `extern "Python"` in the C source is replaced + # with "void __cffi_extern_python_start;" and + # "void __cffi_extern_python_stop;" + self._inside_extern_python = decl.name + else: + if self._inside_extern_python !='__cffi_extern_python_stop': + raise CDefError( + "cannot declare constants or " + "variables with 'extern \"Python\"'") + if (quals & model.Q_CONST) and not tp.is_array_type: + self._declare('constant ' + decl.name, tp, quals=quals) + else: + _warn_for_non_extern_non_static_global_variable(decl) + self._declare('variable ' + decl.name, tp, quals=quals) + + def parse_type(self, cdecl): + return self.parse_type_and_quals(cdecl)[0] + + def parse_type_and_quals(self, cdecl): + ast, macros = self._parse('void __dummy(\n%s\n);' % cdecl)[:2] + assert not macros + exprnode = ast.ext[-1].type.args.params[0] + if isinstance(exprnode, pycparser.c_ast.ID): + raise CDefError("unknown identifier '%s'" % (exprnode.name,)) + return self._get_type_and_quals(exprnode.type) + + def _declare(self, name, obj, included=False, quals=0): + if name in self._declarations: + prevobj, prevquals = self._declarations[name] + if prevobj is obj and prevquals == quals: + return + if not self._options.get('override'): + raise FFIError( + "multiple declarations of %s (for interactive usage, " + "try cdef(xx, override=True))" % (name,)) + assert '__dotdotdot__' not in name.split() + self._declarations[name] = (obj, quals) + if included: + self._included_declarations.add(obj) + + def _extract_quals(self, type): + quals = 0 + if isinstance(type, (pycparser.c_ast.TypeDecl, + pycparser.c_ast.PtrDecl)): + if 'const' in type.quals: + quals |= model.Q_CONST + if 'volatile' in type.quals: + quals |= model.Q_VOLATILE + if 'restrict' in type.quals: + quals |= model.Q_RESTRICT + return quals + + def _get_type_pointer(self, type, quals, declname=None): + if isinstance(type, model.RawFunctionType): + return type.as_function_pointer() + if (isinstance(type, model.StructOrUnionOrEnum) and + type.name.startswith('$') and type.name[1:].isdigit() and + type.forcename is None and declname is not None): + return model.NamedPointerType(type, declname, quals) + return model.PointerType(type, quals) + + def _get_type_and_quals(self, typenode, name=None, partial_length_ok=False, + typedef_example=None): + # first, dereference typedefs, if we have it already parsed, we're good + if (isinstance(typenode, pycparser.c_ast.TypeDecl) and + isinstance(typenode.type, pycparser.c_ast.IdentifierType) and + len(typenode.type.names) == 1 and + ('typedef ' + typenode.type.names[0]) in self._declarations): + tp, quals = self._declarations['typedef ' + typenode.type.names[0]] + quals |= self._extract_quals(typenode) + return tp, quals + # + if isinstance(typenode, pycparser.c_ast.ArrayDecl): + # array type + if typenode.dim is None: + length = None + else: + length = self._parse_constant( + typenode.dim, partial_length_ok=partial_length_ok) + # a hack: in 'typedef int foo_t[...][...];', don't use '...' as + # the length but use directly the C expression that would be + # generated by recompiler.py. This lets the typedef be used in + # many more places within recompiler.py + if typedef_example is not None: + if length == '...': + length = '_cffi_array_len(%s)' % (typedef_example,) + typedef_example = "*" + typedef_example + # + tp, quals = self._get_type_and_quals(typenode.type, + partial_length_ok=partial_length_ok, + typedef_example=typedef_example) + return model.ArrayType(tp, length), quals + # + if isinstance(typenode, pycparser.c_ast.PtrDecl): + # pointer type + itemtype, itemquals = self._get_type_and_quals(typenode.type) + tp = self._get_type_pointer(itemtype, itemquals, declname=name) + quals = self._extract_quals(typenode) + return tp, quals + # + if isinstance(typenode, pycparser.c_ast.TypeDecl): + quals = self._extract_quals(typenode) + type = typenode.type + if isinstance(type, pycparser.c_ast.IdentifierType): + # assume a primitive type. get it from .names, but reduce + # synonyms to a single chosen combination + names = list(type.names) + if names != ['signed', 'char']: # keep this unmodified + prefixes = {} + while names: + name = names[0] + if name in ('short', 'long', 'signed', 'unsigned'): + prefixes[name] = prefixes.get(name, 0) + 1 + del names[0] + else: + break + # ignore the 'signed' prefix below, and reorder the others + newnames = [] + for prefix in ('unsigned', 'short', 'long'): + for i in range(prefixes.get(prefix, 0)): + newnames.append(prefix) + if not names: + names = ['int'] # implicitly + if names == ['int']: # but kill it if 'short' or 'long' + if 'short' in prefixes or 'long' in prefixes: + names = [] + names = newnames + names + ident = ' '.join(names) + if ident == 'void': + return model.void_type, quals + if ident == '__dotdotdot__': + raise FFIError(':%d: bad usage of "..."' % + typenode.coord.line) + tp0, quals0 = resolve_common_type(self, ident) + return tp0, (quals | quals0) + # + if isinstance(type, pycparser.c_ast.Struct): + # 'struct foobar' + tp = self._get_struct_union_enum_type('struct', type, name) + return tp, quals + # + if isinstance(type, pycparser.c_ast.Union): + # 'union foobar' + tp = self._get_struct_union_enum_type('union', type, name) + return tp, quals + # + if isinstance(type, pycparser.c_ast.Enum): + # 'enum foobar' + tp = self._get_struct_union_enum_type('enum', type, name) + return tp, quals + # + if isinstance(typenode, pycparser.c_ast.FuncDecl): + # a function type + return self._parse_function_type(typenode, name), 0 + # + # nested anonymous structs or unions end up here + if isinstance(typenode, pycparser.c_ast.Struct): + return self._get_struct_union_enum_type('struct', typenode, name, + nested=True), 0 + if isinstance(typenode, pycparser.c_ast.Union): + return self._get_struct_union_enum_type('union', typenode, name, + nested=True), 0 + # + raise FFIError(":%d: bad or unsupported type declaration" % + typenode.coord.line) + + def _parse_function_type(self, typenode, funcname=None): + params = list(getattr(typenode.args, 'params', [])) + for i, arg in enumerate(params): + if not hasattr(arg, 'type'): + raise CDefError("%s arg %d: unknown type '%s'" + " (if you meant to use the old C syntax of giving" + " untyped arguments, it is not supported)" + % (funcname or 'in expression', i + 1, + getattr(arg, 'name', '?'))) + ellipsis = ( + len(params) > 0 and + isinstance(params[-1].type, pycparser.c_ast.TypeDecl) and + isinstance(params[-1].type.type, + pycparser.c_ast.IdentifierType) and + params[-1].type.type.names == ['__dotdotdot__']) + if ellipsis: + params.pop() + if not params: + raise CDefError( + "%s: a function with only '(...)' as argument" + " is not correct C" % (funcname or 'in expression')) + args = [self._as_func_arg(*self._get_type_and_quals(argdeclnode.type)) + for argdeclnode in params] + if not ellipsis and args == [model.void_type]: + args = [] + result, quals = self._get_type_and_quals(typenode.type) + # the 'quals' on the result type are ignored. HACK: we absure them + # to detect __stdcall functions: we textually replace "__stdcall" + # with "volatile volatile const" above. + abi = None + if hasattr(typenode.type, 'quals'): # else, probable syntax error anyway + if typenode.type.quals[-3:] == ['volatile', 'volatile', 'const']: + abi = '__stdcall' + return model.RawFunctionType(tuple(args), result, ellipsis, abi) + + def _as_func_arg(self, type, quals): + if isinstance(type, model.ArrayType): + return model.PointerType(type.item, quals) + elif isinstance(type, model.RawFunctionType): + return type.as_function_pointer() + else: + return type + + def _get_struct_union_enum_type(self, kind, type, name=None, nested=False): + # First, a level of caching on the exact 'type' node of the AST. + # This is obscure, but needed because pycparser "unrolls" declarations + # such as "typedef struct { } foo_t, *foo_p" and we end up with + # an AST that is not a tree, but a DAG, with the "type" node of the + # two branches foo_t and foo_p of the trees being the same node. + # It's a bit silly but detecting "DAG-ness" in the AST tree seems + # to be the only way to distinguish this case from two independent + # structs. See test_struct_with_two_usages. + try: + return self._structnode2type[type] + except KeyError: + pass + # + # Note that this must handle parsing "struct foo" any number of + # times and always return the same StructType object. Additionally, + # one of these times (not necessarily the first), the fields of + # the struct can be specified with "struct foo { ...fields... }". + # If no name is given, then we have to create a new anonymous struct + # with no caching; in this case, the fields are either specified + # right now or never. + # + force_name = name + name = type.name + # + # get the type or create it if needed + if name is None: + # 'force_name' is used to guess a more readable name for + # anonymous structs, for the common case "typedef struct { } foo". + if force_name is not None: + explicit_name = '$%s' % force_name + else: + self._anonymous_counter += 1 + explicit_name = '$%d' % self._anonymous_counter + tp = None + else: + explicit_name = name + key = '%s %s' % (kind, name) + tp, _ = self._declarations.get(key, (None, None)) + # + if tp is None: + if kind == 'struct': + tp = model.StructType(explicit_name, None, None, None) + elif kind == 'union': + tp = model.UnionType(explicit_name, None, None, None) + elif kind == 'enum': + if explicit_name == '__dotdotdot__': + raise CDefError("Enums cannot be declared with ...") + tp = self._build_enum_type(explicit_name, type.values) + else: + raise AssertionError("kind = %r" % (kind,)) + if name is not None: + self._declare(key, tp) + else: + if kind == 'enum' and type.values is not None: + raise NotImplementedError( + "enum %s: the '{}' declaration should appear on the first " + "time the enum is mentioned, not later" % explicit_name) + if not tp.forcename: + tp.force_the_name(force_name) + if tp.forcename and '$' in tp.name: + self._declare('anonymous %s' % tp.forcename, tp) + # + self._structnode2type[type] = tp + # + # enums: done here + if kind == 'enum': + return tp + # + # is there a 'type.decls'? If yes, then this is the place in the + # C sources that declare the fields. If no, then just return the + # existing type, possibly still incomplete. + if type.decls is None: + return tp + # + if tp.fldnames is not None: + raise CDefError("duplicate declaration of struct %s" % name) + fldnames = [] + fldtypes = [] + fldbitsize = [] + fldquals = [] + for decl in type.decls: + if (isinstance(decl.type, pycparser.c_ast.IdentifierType) and + ''.join(decl.type.names) == '__dotdotdot__'): + # XXX pycparser is inconsistent: 'names' should be a list + # of strings, but is sometimes just one string. Use + # str.join() as a way to cope with both. + self._make_partial(tp, nested) + continue + if decl.bitsize is None: + bitsize = -1 + else: + bitsize = self._parse_constant(decl.bitsize) + self._partial_length = False + type, fqual = self._get_type_and_quals(decl.type, + partial_length_ok=True) + if self._partial_length: + self._make_partial(tp, nested) + if isinstance(type, model.StructType) and type.partial: + self._make_partial(tp, nested) + fldnames.append(decl.name or '') + fldtypes.append(type) + fldbitsize.append(bitsize) + fldquals.append(fqual) + tp.fldnames = tuple(fldnames) + tp.fldtypes = tuple(fldtypes) + tp.fldbitsize = tuple(fldbitsize) + tp.fldquals = tuple(fldquals) + if fldbitsize != [-1] * len(fldbitsize): + if isinstance(tp, model.StructType) and tp.partial: + raise NotImplementedError("%s: using both bitfields and '...;'" + % (tp,)) + tp.packed = self._options.get('packed') + if tp.completed: # must be re-completed: it is not opaque any more + tp.completed = 0 + self._recomplete.append(tp) + return tp + + def _make_partial(self, tp, nested): + if not isinstance(tp, model.StructOrUnion): + raise CDefError("%s cannot be partial" % (tp,)) + if not tp.has_c_name() and not nested: + raise NotImplementedError("%s is partial but has no C name" %(tp,)) + tp.partial = True + + def _parse_constant(self, exprnode, partial_length_ok=False): + # for now, limited to expressions that are an immediate number + # or positive/negative number + if isinstance(exprnode, pycparser.c_ast.Constant): + s = exprnode.value + if '0' <= s[0] <= '9': + s = s.rstrip('uUlL') + try: + if s.startswith('0'): + return int(s, 8) + else: + return int(s, 10) + except ValueError: + if len(s) > 1: + if s.lower()[0:2] == '0x': + return int(s, 16) + elif s.lower()[0:2] == '0b': + return int(s, 2) + raise CDefError("invalid constant %r" % (s,)) + elif s[0] == "'" and s[-1] == "'" and ( + len(s) == 3 or (len(s) == 4 and s[1] == "\\")): + return ord(s[-2]) + else: + raise CDefError("invalid constant %r" % (s,)) + # + if (isinstance(exprnode, pycparser.c_ast.UnaryOp) and + exprnode.op == '+'): + return self._parse_constant(exprnode.expr) + # + if (isinstance(exprnode, pycparser.c_ast.UnaryOp) and + exprnode.op == '-'): + return -self._parse_constant(exprnode.expr) + # load previously defined int constant + if (isinstance(exprnode, pycparser.c_ast.ID) and + exprnode.name in self._int_constants): + return self._int_constants[exprnode.name] + # + if (isinstance(exprnode, pycparser.c_ast.ID) and + exprnode.name == '__dotdotdotarray__'): + if partial_length_ok: + self._partial_length = True + return '...' + raise FFIError(":%d: unsupported '[...]' here, cannot derive " + "the actual array length in this context" + % exprnode.coord.line) + # + if isinstance(exprnode, pycparser.c_ast.BinaryOp): + left = self._parse_constant(exprnode.left) + right = self._parse_constant(exprnode.right) + if exprnode.op == '+': + return left + right + elif exprnode.op == '-': + return left - right + elif exprnode.op == '*': + return left * right + elif exprnode.op == '/': + return self._c_div(left, right) + elif exprnode.op == '%': + return left - self._c_div(left, right) * right + elif exprnode.op == '<<': + return left << right + elif exprnode.op == '>>': + return left >> right + elif exprnode.op == '&': + return left & right + elif exprnode.op == '|': + return left | right + elif exprnode.op == '^': + return left ^ right + # + raise FFIError(":%d: unsupported expression: expected a " + "simple numeric constant" % exprnode.coord.line) + + def _c_div(self, a, b): + result = a // b + if ((a < 0) ^ (b < 0)) and (a % b) != 0: + result += 1 + return result + + def _build_enum_type(self, explicit_name, decls): + if decls is not None: + partial = False + enumerators = [] + enumvalues = [] + nextenumvalue = 0 + for enum in decls.enumerators: + if _r_enum_dotdotdot.match(enum.name): + partial = True + continue + if enum.value is not None: + nextenumvalue = self._parse_constant(enum.value) + enumerators.append(enum.name) + enumvalues.append(nextenumvalue) + self._add_constants(enum.name, nextenumvalue) + nextenumvalue += 1 + enumerators = tuple(enumerators) + enumvalues = tuple(enumvalues) + tp = model.EnumType(explicit_name, enumerators, enumvalues) + tp.partial = partial + else: # opaque enum + tp = model.EnumType(explicit_name, (), ()) + return tp + + def include(self, other): + for name, (tp, quals) in other._declarations.items(): + if name.startswith('anonymous $enum_$'): + continue # fix for test_anonymous_enum_include + kind = name.split(' ', 1)[0] + if kind in ('struct', 'union', 'enum', 'anonymous', 'typedef'): + self._declare(name, tp, included=True, quals=quals) + for k, v in other._int_constants.items(): + self._add_constants(k, v) + + def _get_unknown_type(self, decl): + typenames = decl.type.type.names + if typenames == ['__dotdotdot__']: + return model.unknown_type(decl.name) + + if typenames == ['__dotdotdotint__']: + if self._uses_new_feature is None: + self._uses_new_feature = "'typedef int... %s'" % decl.name + return model.UnknownIntegerType(decl.name) + + if typenames == ['__dotdotdotfloat__']: + # note: not for 'long double' so far + if self._uses_new_feature is None: + self._uses_new_feature = "'typedef float... %s'" % decl.name + return model.UnknownFloatType(decl.name) + + raise FFIError(':%d: unsupported usage of "..." in typedef' + % decl.coord.line) + + def _get_unknown_ptr_type(self, decl): + if decl.type.type.type.names == ['__dotdotdot__']: + return model.unknown_ptr_type(decl.name) + raise FFIError(':%d: unsupported usage of "..." in typedef' + % decl.coord.line) diff --git a/venv/Lib/site-packages/cffi/error.py b/venv/Lib/site-packages/cffi/error.py new file mode 100644 index 000000000..0a27247c3 --- /dev/null +++ b/venv/Lib/site-packages/cffi/error.py @@ -0,0 +1,31 @@ + +class FFIError(Exception): + __module__ = 'cffi' + +class CDefError(Exception): + __module__ = 'cffi' + def __str__(self): + try: + current_decl = self.args[1] + filename = current_decl.coord.file + linenum = current_decl.coord.line + prefix = '%s:%d: ' % (filename, linenum) + except (AttributeError, TypeError, IndexError): + prefix = '' + return '%s%s' % (prefix, self.args[0]) + +class VerificationError(Exception): + """ An error raised when verification fails + """ + __module__ = 'cffi' + +class VerificationMissing(Exception): + """ An error raised when incomplete structures are passed into + cdef, but no verification has been done + """ + __module__ = 'cffi' + +class PkgConfigError(Exception): + """ An error raised for missing modules in pkg-config + """ + __module__ = 'cffi' diff --git a/venv/Lib/site-packages/cffi/ffiplatform.py b/venv/Lib/site-packages/cffi/ffiplatform.py new file mode 100644 index 000000000..85313460a --- /dev/null +++ b/venv/Lib/site-packages/cffi/ffiplatform.py @@ -0,0 +1,127 @@ +import sys, os +from .error import VerificationError + + +LIST_OF_FILE_NAMES = ['sources', 'include_dirs', 'library_dirs', + 'extra_objects', 'depends'] + +def get_extension(srcfilename, modname, sources=(), **kwds): + _hack_at_distutils() + from distutils.core import Extension + allsources = [srcfilename] + for src in sources: + allsources.append(os.path.normpath(src)) + return Extension(name=modname, sources=allsources, **kwds) + +def compile(tmpdir, ext, compiler_verbose=0, debug=None): + """Compile a C extension module using distutils.""" + + _hack_at_distutils() + saved_environ = os.environ.copy() + try: + outputfilename = _build(tmpdir, ext, compiler_verbose, debug) + outputfilename = os.path.abspath(outputfilename) + finally: + # workaround for a distutils bugs where some env vars can + # become longer and longer every time it is used + for key, value in saved_environ.items(): + if os.environ.get(key) != value: + os.environ[key] = value + return outputfilename + +def _build(tmpdir, ext, compiler_verbose=0, debug=None): + # XXX compact but horrible :-( + from distutils.core import Distribution + import distutils.errors, distutils.log + # + dist = Distribution({'ext_modules': [ext]}) + dist.parse_config_files() + options = dist.get_option_dict('build_ext') + if debug is None: + debug = sys.flags.debug + options['debug'] = ('ffiplatform', debug) + options['force'] = ('ffiplatform', True) + options['build_lib'] = ('ffiplatform', tmpdir) + options['build_temp'] = ('ffiplatform', tmpdir) + # + try: + old_level = distutils.log.set_threshold(0) or 0 + try: + distutils.log.set_verbosity(compiler_verbose) + dist.run_command('build_ext') + cmd_obj = dist.get_command_obj('build_ext') + [soname] = cmd_obj.get_outputs() + finally: + distutils.log.set_threshold(old_level) + except (distutils.errors.CompileError, + distutils.errors.LinkError) as e: + raise VerificationError('%s: %s' % (e.__class__.__name__, e)) + # + return soname + +try: + from os.path import samefile +except ImportError: + def samefile(f1, f2): + return os.path.abspath(f1) == os.path.abspath(f2) + +def maybe_relative_path(path): + if not os.path.isabs(path): + return path # already relative + dir = path + names = [] + while True: + prevdir = dir + dir, name = os.path.split(prevdir) + if dir == prevdir or not dir: + return path # failed to make it relative + names.append(name) + try: + if samefile(dir, os.curdir): + names.reverse() + return os.path.join(*names) + except OSError: + pass + +# ____________________________________________________________ + +try: + int_or_long = (int, long) + import cStringIO +except NameError: + int_or_long = int # Python 3 + import io as cStringIO + +def _flatten(x, f): + if isinstance(x, str): + f.write('%ds%s' % (len(x), x)) + elif isinstance(x, dict): + keys = sorted(x.keys()) + f.write('%dd' % len(keys)) + for key in keys: + _flatten(key, f) + _flatten(x[key], f) + elif isinstance(x, (list, tuple)): + f.write('%dl' % len(x)) + for value in x: + _flatten(value, f) + elif isinstance(x, int_or_long): + f.write('%di' % (x,)) + else: + raise TypeError( + "the keywords to verify() contains unsupported object %r" % (x,)) + +def flatten(x): + f = cStringIO.StringIO() + _flatten(x, f) + return f.getvalue() + +def _hack_at_distutils(): + # Windows-only workaround for some configurations: see + # https://bugs.python.org/issue23246 (Python 2.7 with + # a specific MS compiler suite download) + if sys.platform == "win32": + try: + import setuptools # for side-effects, patches distutils + except ImportError: + pass diff --git a/venv/Lib/site-packages/cffi/lock.py b/venv/Lib/site-packages/cffi/lock.py new file mode 100644 index 000000000..db91b7158 --- /dev/null +++ b/venv/Lib/site-packages/cffi/lock.py @@ -0,0 +1,30 @@ +import sys + +if sys.version_info < (3,): + try: + from thread import allocate_lock + except ImportError: + from dummy_thread import allocate_lock +else: + try: + from _thread import allocate_lock + except ImportError: + from _dummy_thread import allocate_lock + + +##import sys +##l1 = allocate_lock + +##class allocate_lock(object): +## def __init__(self): +## self._real = l1() +## def __enter__(self): +## for i in range(4, 0, -1): +## print sys._getframe(i).f_code +## print +## return self._real.__enter__() +## def __exit__(self, *args): +## return self._real.__exit__(*args) +## def acquire(self, f): +## assert f is False +## return self._real.acquire(f) diff --git a/venv/Lib/site-packages/cffi/model.py b/venv/Lib/site-packages/cffi/model.py new file mode 100644 index 000000000..ad1c17648 --- /dev/null +++ b/venv/Lib/site-packages/cffi/model.py @@ -0,0 +1,617 @@ +import types +import weakref + +from .lock import allocate_lock +from .error import CDefError, VerificationError, VerificationMissing + +# type qualifiers +Q_CONST = 0x01 +Q_RESTRICT = 0x02 +Q_VOLATILE = 0x04 + +def qualify(quals, replace_with): + if quals & Q_CONST: + replace_with = ' const ' + replace_with.lstrip() + if quals & Q_VOLATILE: + replace_with = ' volatile ' + replace_with.lstrip() + if quals & Q_RESTRICT: + # It seems that __restrict is supported by gcc and msvc. + # If you hit some different compiler, add a #define in + # _cffi_include.h for it (and in its copies, documented there) + replace_with = ' __restrict ' + replace_with.lstrip() + return replace_with + + +class BaseTypeByIdentity(object): + is_array_type = False + is_raw_function = False + + def get_c_name(self, replace_with='', context='a C file', quals=0): + result = self.c_name_with_marker + assert result.count('&') == 1 + # some logic duplication with ffi.getctype()... :-( + replace_with = replace_with.strip() + if replace_with: + if replace_with.startswith('*') and '&[' in result: + replace_with = '(%s)' % replace_with + elif not replace_with[0] in '[(': + replace_with = ' ' + replace_with + replace_with = qualify(quals, replace_with) + result = result.replace('&', replace_with) + if '$' in result: + raise VerificationError( + "cannot generate '%s' in %s: unknown type name" + % (self._get_c_name(), context)) + return result + + def _get_c_name(self): + return self.c_name_with_marker.replace('&', '') + + def has_c_name(self): + return '$' not in self._get_c_name() + + def is_integer_type(self): + return False + + def get_cached_btype(self, ffi, finishlist, can_delay=False): + try: + BType = ffi._cached_btypes[self] + except KeyError: + BType = self.build_backend_type(ffi, finishlist) + BType2 = ffi._cached_btypes.setdefault(self, BType) + assert BType2 is BType + return BType + + def __repr__(self): + return '<%s>' % (self._get_c_name(),) + + def _get_items(self): + return [(name, getattr(self, name)) for name in self._attrs_] + + +class BaseType(BaseTypeByIdentity): + + def __eq__(self, other): + return (self.__class__ == other.__class__ and + self._get_items() == other._get_items()) + + def __ne__(self, other): + return not self == other + + def __hash__(self): + return hash((self.__class__, tuple(self._get_items()))) + + +class VoidType(BaseType): + _attrs_ = () + + def __init__(self): + self.c_name_with_marker = 'void&' + + def build_backend_type(self, ffi, finishlist): + return global_cache(self, ffi, 'new_void_type') + +void_type = VoidType() + + +class BasePrimitiveType(BaseType): + def is_complex_type(self): + return False + + +class PrimitiveType(BasePrimitiveType): + _attrs_ = ('name',) + + ALL_PRIMITIVE_TYPES = { + 'char': 'c', + 'short': 'i', + 'int': 'i', + 'long': 'i', + 'long long': 'i', + 'signed char': 'i', + 'unsigned char': 'i', + 'unsigned short': 'i', + 'unsigned int': 'i', + 'unsigned long': 'i', + 'unsigned long long': 'i', + 'float': 'f', + 'double': 'f', + 'long double': 'f', + 'float _Complex': 'j', + 'double _Complex': 'j', + '_Bool': 'i', + # the following types are not primitive in the C sense + 'wchar_t': 'c', + 'char16_t': 'c', + 'char32_t': 'c', + 'int8_t': 'i', + 'uint8_t': 'i', + 'int16_t': 'i', + 'uint16_t': 'i', + 'int32_t': 'i', + 'uint32_t': 'i', + 'int64_t': 'i', + 'uint64_t': 'i', + 'int_least8_t': 'i', + 'uint_least8_t': 'i', + 'int_least16_t': 'i', + 'uint_least16_t': 'i', + 'int_least32_t': 'i', + 'uint_least32_t': 'i', + 'int_least64_t': 'i', + 'uint_least64_t': 'i', + 'int_fast8_t': 'i', + 'uint_fast8_t': 'i', + 'int_fast16_t': 'i', + 'uint_fast16_t': 'i', + 'int_fast32_t': 'i', + 'uint_fast32_t': 'i', + 'int_fast64_t': 'i', + 'uint_fast64_t': 'i', + 'intptr_t': 'i', + 'uintptr_t': 'i', + 'intmax_t': 'i', + 'uintmax_t': 'i', + 'ptrdiff_t': 'i', + 'size_t': 'i', + 'ssize_t': 'i', + } + + def __init__(self, name): + assert name in self.ALL_PRIMITIVE_TYPES + self.name = name + self.c_name_with_marker = name + '&' + + def is_char_type(self): + return self.ALL_PRIMITIVE_TYPES[self.name] == 'c' + def is_integer_type(self): + return self.ALL_PRIMITIVE_TYPES[self.name] == 'i' + def is_float_type(self): + return self.ALL_PRIMITIVE_TYPES[self.name] == 'f' + def is_complex_type(self): + return self.ALL_PRIMITIVE_TYPES[self.name] == 'j' + + def build_backend_type(self, ffi, finishlist): + return global_cache(self, ffi, 'new_primitive_type', self.name) + + +class UnknownIntegerType(BasePrimitiveType): + _attrs_ = ('name',) + + def __init__(self, name): + self.name = name + self.c_name_with_marker = name + '&' + + def is_integer_type(self): + return True + + def build_backend_type(self, ffi, finishlist): + raise NotImplementedError("integer type '%s' can only be used after " + "compilation" % self.name) + +class UnknownFloatType(BasePrimitiveType): + _attrs_ = ('name', ) + + def __init__(self, name): + self.name = name + self.c_name_with_marker = name + '&' + + def build_backend_type(self, ffi, finishlist): + raise NotImplementedError("float type '%s' can only be used after " + "compilation" % self.name) + + +class BaseFunctionType(BaseType): + _attrs_ = ('args', 'result', 'ellipsis', 'abi') + + def __init__(self, args, result, ellipsis, abi=None): + self.args = args + self.result = result + self.ellipsis = ellipsis + self.abi = abi + # + reprargs = [arg._get_c_name() for arg in self.args] + if self.ellipsis: + reprargs.append('...') + reprargs = reprargs or ['void'] + replace_with = self._base_pattern % (', '.join(reprargs),) + if abi is not None: + replace_with = replace_with[:1] + abi + ' ' + replace_with[1:] + self.c_name_with_marker = ( + self.result.c_name_with_marker.replace('&', replace_with)) + + +class RawFunctionType(BaseFunctionType): + # Corresponds to a C type like 'int(int)', which is the C type of + # a function, but not a pointer-to-function. The backend has no + # notion of such a type; it's used temporarily by parsing. + _base_pattern = '(&)(%s)' + is_raw_function = True + + def build_backend_type(self, ffi, finishlist): + raise CDefError("cannot render the type %r: it is a function " + "type, not a pointer-to-function type" % (self,)) + + def as_function_pointer(self): + return FunctionPtrType(self.args, self.result, self.ellipsis, self.abi) + + +class FunctionPtrType(BaseFunctionType): + _base_pattern = '(*&)(%s)' + + def build_backend_type(self, ffi, finishlist): + result = self.result.get_cached_btype(ffi, finishlist) + args = [] + for tp in self.args: + args.append(tp.get_cached_btype(ffi, finishlist)) + abi_args = () + if self.abi == "__stdcall": + if not self.ellipsis: # __stdcall ignored for variadic funcs + try: + abi_args = (ffi._backend.FFI_STDCALL,) + except AttributeError: + pass + return global_cache(self, ffi, 'new_function_type', + tuple(args), result, self.ellipsis, *abi_args) + + def as_raw_function(self): + return RawFunctionType(self.args, self.result, self.ellipsis, self.abi) + + +class PointerType(BaseType): + _attrs_ = ('totype', 'quals') + + def __init__(self, totype, quals=0): + self.totype = totype + self.quals = quals + extra = qualify(quals, " *&") + if totype.is_array_type: + extra = "(%s)" % (extra.lstrip(),) + self.c_name_with_marker = totype.c_name_with_marker.replace('&', extra) + + def build_backend_type(self, ffi, finishlist): + BItem = self.totype.get_cached_btype(ffi, finishlist, can_delay=True) + return global_cache(self, ffi, 'new_pointer_type', BItem) + +voidp_type = PointerType(void_type) + +def ConstPointerType(totype): + return PointerType(totype, Q_CONST) + +const_voidp_type = ConstPointerType(void_type) + + +class NamedPointerType(PointerType): + _attrs_ = ('totype', 'name') + + def __init__(self, totype, name, quals=0): + PointerType.__init__(self, totype, quals) + self.name = name + self.c_name_with_marker = name + '&' + + +class ArrayType(BaseType): + _attrs_ = ('item', 'length') + is_array_type = True + + def __init__(self, item, length): + self.item = item + self.length = length + # + if length is None: + brackets = '&[]' + elif length == '...': + brackets = '&[/*...*/]' + else: + brackets = '&[%s]' % length + self.c_name_with_marker = ( + self.item.c_name_with_marker.replace('&', brackets)) + + def length_is_unknown(self): + return isinstance(self.length, str) + + def resolve_length(self, newlength): + return ArrayType(self.item, newlength) + + def build_backend_type(self, ffi, finishlist): + if self.length_is_unknown(): + raise CDefError("cannot render the type %r: unknown length" % + (self,)) + self.item.get_cached_btype(ffi, finishlist) # force the item BType + BPtrItem = PointerType(self.item).get_cached_btype(ffi, finishlist) + return global_cache(self, ffi, 'new_array_type', BPtrItem, self.length) + +char_array_type = ArrayType(PrimitiveType('char'), None) + + +class StructOrUnionOrEnum(BaseTypeByIdentity): + _attrs_ = ('name',) + forcename = None + + def build_c_name_with_marker(self): + name = self.forcename or '%s %s' % (self.kind, self.name) + self.c_name_with_marker = name + '&' + + def force_the_name(self, forcename): + self.forcename = forcename + self.build_c_name_with_marker() + + def get_official_name(self): + assert self.c_name_with_marker.endswith('&') + return self.c_name_with_marker[:-1] + + +class StructOrUnion(StructOrUnionOrEnum): + fixedlayout = None + completed = 0 + partial = False + packed = 0 + + def __init__(self, name, fldnames, fldtypes, fldbitsize, fldquals=None): + self.name = name + self.fldnames = fldnames + self.fldtypes = fldtypes + self.fldbitsize = fldbitsize + self.fldquals = fldquals + self.build_c_name_with_marker() + + def anonymous_struct_fields(self): + if self.fldtypes is not None: + for name, type in zip(self.fldnames, self.fldtypes): + if name == '' and isinstance(type, StructOrUnion): + yield type + + def enumfields(self, expand_anonymous_struct_union=True): + fldquals = self.fldquals + if fldquals is None: + fldquals = (0,) * len(self.fldnames) + for name, type, bitsize, quals in zip(self.fldnames, self.fldtypes, + self.fldbitsize, fldquals): + if (name == '' and isinstance(type, StructOrUnion) + and expand_anonymous_struct_union): + # nested anonymous struct/union + for result in type.enumfields(): + yield result + else: + yield (name, type, bitsize, quals) + + def force_flatten(self): + # force the struct or union to have a declaration that lists + # directly all fields returned by enumfields(), flattening + # nested anonymous structs/unions. + names = [] + types = [] + bitsizes = [] + fldquals = [] + for name, type, bitsize, quals in self.enumfields(): + names.append(name) + types.append(type) + bitsizes.append(bitsize) + fldquals.append(quals) + self.fldnames = tuple(names) + self.fldtypes = tuple(types) + self.fldbitsize = tuple(bitsizes) + self.fldquals = tuple(fldquals) + + def get_cached_btype(self, ffi, finishlist, can_delay=False): + BType = StructOrUnionOrEnum.get_cached_btype(self, ffi, finishlist, + can_delay) + if not can_delay: + self.finish_backend_type(ffi, finishlist) + return BType + + def finish_backend_type(self, ffi, finishlist): + if self.completed: + if self.completed != 2: + raise NotImplementedError("recursive structure declaration " + "for '%s'" % (self.name,)) + return + BType = ffi._cached_btypes[self] + # + self.completed = 1 + # + if self.fldtypes is None: + pass # not completing it: it's an opaque struct + # + elif self.fixedlayout is None: + fldtypes = [tp.get_cached_btype(ffi, finishlist) + for tp in self.fldtypes] + lst = list(zip(self.fldnames, fldtypes, self.fldbitsize)) + extra_flags = () + if self.packed: + if self.packed == 1: + extra_flags = (8,) # SF_PACKED + else: + extra_flags = (0, self.packed) + ffi._backend.complete_struct_or_union(BType, lst, self, + -1, -1, *extra_flags) + # + else: + fldtypes = [] + fieldofs, fieldsize, totalsize, totalalignment = self.fixedlayout + for i in range(len(self.fldnames)): + fsize = fieldsize[i] + ftype = self.fldtypes[i] + # + if isinstance(ftype, ArrayType) and ftype.length_is_unknown(): + # fix the length to match the total size + BItemType = ftype.item.get_cached_btype(ffi, finishlist) + nlen, nrest = divmod(fsize, ffi.sizeof(BItemType)) + if nrest != 0: + self._verification_error( + "field '%s.%s' has a bogus size?" % ( + self.name, self.fldnames[i] or '{}')) + ftype = ftype.resolve_length(nlen) + self.fldtypes = (self.fldtypes[:i] + (ftype,) + + self.fldtypes[i+1:]) + # + BFieldType = ftype.get_cached_btype(ffi, finishlist) + if isinstance(ftype, ArrayType) and ftype.length is None: + assert fsize == 0 + else: + bitemsize = ffi.sizeof(BFieldType) + if bitemsize != fsize: + self._verification_error( + "field '%s.%s' is declared as %d bytes, but is " + "really %d bytes" % (self.name, + self.fldnames[i] or '{}', + bitemsize, fsize)) + fldtypes.append(BFieldType) + # + lst = list(zip(self.fldnames, fldtypes, self.fldbitsize, fieldofs)) + ffi._backend.complete_struct_or_union(BType, lst, self, + totalsize, totalalignment) + self.completed = 2 + + def _verification_error(self, msg): + raise VerificationError(msg) + + def check_not_partial(self): + if self.partial and self.fixedlayout is None: + raise VerificationMissing(self._get_c_name()) + + def build_backend_type(self, ffi, finishlist): + self.check_not_partial() + finishlist.append(self) + # + return global_cache(self, ffi, 'new_%s_type' % self.kind, + self.get_official_name(), key=self) + + +class StructType(StructOrUnion): + kind = 'struct' + + +class UnionType(StructOrUnion): + kind = 'union' + + +class EnumType(StructOrUnionOrEnum): + kind = 'enum' + partial = False + partial_resolved = False + + def __init__(self, name, enumerators, enumvalues, baseinttype=None): + self.name = name + self.enumerators = enumerators + self.enumvalues = enumvalues + self.baseinttype = baseinttype + self.build_c_name_with_marker() + + def force_the_name(self, forcename): + StructOrUnionOrEnum.force_the_name(self, forcename) + if self.forcename is None: + name = self.get_official_name() + self.forcename = '$' + name.replace(' ', '_') + + def check_not_partial(self): + if self.partial and not self.partial_resolved: + raise VerificationMissing(self._get_c_name()) + + def build_backend_type(self, ffi, finishlist): + self.check_not_partial() + base_btype = self.build_baseinttype(ffi, finishlist) + return global_cache(self, ffi, 'new_enum_type', + self.get_official_name(), + self.enumerators, self.enumvalues, + base_btype, key=self) + + def build_baseinttype(self, ffi, finishlist): + if self.baseinttype is not None: + return self.baseinttype.get_cached_btype(ffi, finishlist) + # + if self.enumvalues: + smallest_value = min(self.enumvalues) + largest_value = max(self.enumvalues) + else: + import warnings + try: + # XXX! The goal is to ensure that the warnings.warn() + # will not suppress the warning. We want to get it + # several times if we reach this point several times. + __warningregistry__.clear() + except NameError: + pass + warnings.warn("%r has no values explicitly defined; " + "guessing that it is equivalent to 'unsigned int'" + % self._get_c_name()) + smallest_value = largest_value = 0 + if smallest_value < 0: # needs a signed type + sign = 1 + candidate1 = PrimitiveType("int") + candidate2 = PrimitiveType("long") + else: + sign = 0 + candidate1 = PrimitiveType("unsigned int") + candidate2 = PrimitiveType("unsigned long") + btype1 = candidate1.get_cached_btype(ffi, finishlist) + btype2 = candidate2.get_cached_btype(ffi, finishlist) + size1 = ffi.sizeof(btype1) + size2 = ffi.sizeof(btype2) + if (smallest_value >= ((-1) << (8*size1-1)) and + largest_value < (1 << (8*size1-sign))): + return btype1 + if (smallest_value >= ((-1) << (8*size2-1)) and + largest_value < (1 << (8*size2-sign))): + return btype2 + raise CDefError("%s values don't all fit into either 'long' " + "or 'unsigned long'" % self._get_c_name()) + +def unknown_type(name, structname=None): + if structname is None: + structname = '$%s' % name + tp = StructType(structname, None, None, None) + tp.force_the_name(name) + tp.origin = "unknown_type" + return tp + +def unknown_ptr_type(name, structname=None): + if structname is None: + structname = '$$%s' % name + tp = StructType(structname, None, None, None) + return NamedPointerType(tp, name) + + +global_lock = allocate_lock() +_typecache_cffi_backend = weakref.WeakValueDictionary() + +def get_typecache(backend): + # returns _typecache_cffi_backend if backend is the _cffi_backend + # module, or type(backend).__typecache if backend is an instance of + # CTypesBackend (or some FakeBackend class during tests) + if isinstance(backend, types.ModuleType): + return _typecache_cffi_backend + with global_lock: + if not hasattr(type(backend), '__typecache'): + type(backend).__typecache = weakref.WeakValueDictionary() + return type(backend).__typecache + +def global_cache(srctype, ffi, funcname, *args, **kwds): + key = kwds.pop('key', (funcname, args)) + assert not kwds + try: + return ffi._typecache[key] + except KeyError: + pass + try: + res = getattr(ffi._backend, funcname)(*args) + except NotImplementedError as e: + raise NotImplementedError("%s: %r: %s" % (funcname, srctype, e)) + # note that setdefault() on WeakValueDictionary is not atomic + # and contains a rare bug (http://bugs.python.org/issue19542); + # we have to use a lock and do it ourselves + cache = ffi._typecache + with global_lock: + res1 = cache.get(key) + if res1 is None: + cache[key] = res + return res + else: + return res1 + +def pointer_cache(ffi, BType): + return global_cache('?', ffi, 'new_pointer_type', BType) + +def attach_exception_info(e, name): + if e.args and type(e.args[0]) is str: + e.args = ('%s: %s' % (name, e.args[0]),) + e.args[1:] diff --git a/venv/Lib/site-packages/cffi/parse_c_type.h b/venv/Lib/site-packages/cffi/parse_c_type.h new file mode 100644 index 000000000..84e4ef856 --- /dev/null +++ b/venv/Lib/site-packages/cffi/parse_c_type.h @@ -0,0 +1,181 @@ + +/* This part is from file 'cffi/parse_c_type.h'. It is copied at the + beginning of C sources generated by CFFI's ffi.set_source(). */ + +typedef void *_cffi_opcode_t; + +#define _CFFI_OP(opcode, arg) (_cffi_opcode_t)(opcode | (((uintptr_t)(arg)) << 8)) +#define _CFFI_GETOP(cffi_opcode) ((unsigned char)(uintptr_t)cffi_opcode) +#define _CFFI_GETARG(cffi_opcode) (((intptr_t)cffi_opcode) >> 8) + +#define _CFFI_OP_PRIMITIVE 1 +#define _CFFI_OP_POINTER 3 +#define _CFFI_OP_ARRAY 5 +#define _CFFI_OP_OPEN_ARRAY 7 +#define _CFFI_OP_STRUCT_UNION 9 +#define _CFFI_OP_ENUM 11 +#define _CFFI_OP_FUNCTION 13 +#define _CFFI_OP_FUNCTION_END 15 +#define _CFFI_OP_NOOP 17 +#define _CFFI_OP_BITFIELD 19 +#define _CFFI_OP_TYPENAME 21 +#define _CFFI_OP_CPYTHON_BLTN_V 23 // varargs +#define _CFFI_OP_CPYTHON_BLTN_N 25 // noargs +#define _CFFI_OP_CPYTHON_BLTN_O 27 // O (i.e. a single arg) +#define _CFFI_OP_CONSTANT 29 +#define _CFFI_OP_CONSTANT_INT 31 +#define _CFFI_OP_GLOBAL_VAR 33 +#define _CFFI_OP_DLOPEN_FUNC 35 +#define _CFFI_OP_DLOPEN_CONST 37 +#define _CFFI_OP_GLOBAL_VAR_F 39 +#define _CFFI_OP_EXTERN_PYTHON 41 + +#define _CFFI_PRIM_VOID 0 +#define _CFFI_PRIM_BOOL 1 +#define _CFFI_PRIM_CHAR 2 +#define _CFFI_PRIM_SCHAR 3 +#define _CFFI_PRIM_UCHAR 4 +#define _CFFI_PRIM_SHORT 5 +#define _CFFI_PRIM_USHORT 6 +#define _CFFI_PRIM_INT 7 +#define _CFFI_PRIM_UINT 8 +#define _CFFI_PRIM_LONG 9 +#define _CFFI_PRIM_ULONG 10 +#define _CFFI_PRIM_LONGLONG 11 +#define _CFFI_PRIM_ULONGLONG 12 +#define _CFFI_PRIM_FLOAT 13 +#define _CFFI_PRIM_DOUBLE 14 +#define _CFFI_PRIM_LONGDOUBLE 15 + +#define _CFFI_PRIM_WCHAR 16 +#define _CFFI_PRIM_INT8 17 +#define _CFFI_PRIM_UINT8 18 +#define _CFFI_PRIM_INT16 19 +#define _CFFI_PRIM_UINT16 20 +#define _CFFI_PRIM_INT32 21 +#define _CFFI_PRIM_UINT32 22 +#define _CFFI_PRIM_INT64 23 +#define _CFFI_PRIM_UINT64 24 +#define _CFFI_PRIM_INTPTR 25 +#define _CFFI_PRIM_UINTPTR 26 +#define _CFFI_PRIM_PTRDIFF 27 +#define _CFFI_PRIM_SIZE 28 +#define _CFFI_PRIM_SSIZE 29 +#define _CFFI_PRIM_INT_LEAST8 30 +#define _CFFI_PRIM_UINT_LEAST8 31 +#define _CFFI_PRIM_INT_LEAST16 32 +#define _CFFI_PRIM_UINT_LEAST16 33 +#define _CFFI_PRIM_INT_LEAST32 34 +#define _CFFI_PRIM_UINT_LEAST32 35 +#define _CFFI_PRIM_INT_LEAST64 36 +#define _CFFI_PRIM_UINT_LEAST64 37 +#define _CFFI_PRIM_INT_FAST8 38 +#define _CFFI_PRIM_UINT_FAST8 39 +#define _CFFI_PRIM_INT_FAST16 40 +#define _CFFI_PRIM_UINT_FAST16 41 +#define _CFFI_PRIM_INT_FAST32 42 +#define _CFFI_PRIM_UINT_FAST32 43 +#define _CFFI_PRIM_INT_FAST64 44 +#define _CFFI_PRIM_UINT_FAST64 45 +#define _CFFI_PRIM_INTMAX 46 +#define _CFFI_PRIM_UINTMAX 47 +#define _CFFI_PRIM_FLOATCOMPLEX 48 +#define _CFFI_PRIM_DOUBLECOMPLEX 49 +#define _CFFI_PRIM_CHAR16 50 +#define _CFFI_PRIM_CHAR32 51 + +#define _CFFI__NUM_PRIM 52 +#define _CFFI__UNKNOWN_PRIM (-1) +#define _CFFI__UNKNOWN_FLOAT_PRIM (-2) +#define _CFFI__UNKNOWN_LONG_DOUBLE (-3) + +#define _CFFI__IO_FILE_STRUCT (-1) + + +struct _cffi_global_s { + const char *name; + void *address; + _cffi_opcode_t type_op; + void *size_or_direct_fn; // OP_GLOBAL_VAR: size, or 0 if unknown + // OP_CPYTHON_BLTN_*: addr of direct function +}; + +struct _cffi_getconst_s { + unsigned long long value; + const struct _cffi_type_context_s *ctx; + int gindex; +}; + +struct _cffi_struct_union_s { + const char *name; + int type_index; // -> _cffi_types, on a OP_STRUCT_UNION + int flags; // _CFFI_F_* flags below + size_t size; + int alignment; + int first_field_index; // -> _cffi_fields array + int num_fields; +}; +#define _CFFI_F_UNION 0x01 // is a union, not a struct +#define _CFFI_F_CHECK_FIELDS 0x02 // complain if fields are not in the + // "standard layout" or if some are missing +#define _CFFI_F_PACKED 0x04 // for CHECK_FIELDS, assume a packed struct +#define _CFFI_F_EXTERNAL 0x08 // in some other ffi.include() +#define _CFFI_F_OPAQUE 0x10 // opaque + +struct _cffi_field_s { + const char *name; + size_t field_offset; + size_t field_size; + _cffi_opcode_t field_type_op; +}; + +struct _cffi_enum_s { + const char *name; + int type_index; // -> _cffi_types, on a OP_ENUM + int type_prim; // _CFFI_PRIM_xxx + const char *enumerators; // comma-delimited string +}; + +struct _cffi_typename_s { + const char *name; + int type_index; /* if opaque, points to a possibly artificial + OP_STRUCT which is itself opaque */ +}; + +struct _cffi_type_context_s { + _cffi_opcode_t *types; + const struct _cffi_global_s *globals; + const struct _cffi_field_s *fields; + const struct _cffi_struct_union_s *struct_unions; + const struct _cffi_enum_s *enums; + const struct _cffi_typename_s *typenames; + int num_globals; + int num_struct_unions; + int num_enums; + int num_typenames; + const char *const *includes; + int num_types; + int flags; /* future extension */ +}; + +struct _cffi_parse_info_s { + const struct _cffi_type_context_s *ctx; + _cffi_opcode_t *output; + unsigned int output_size; + size_t error_location; + const char *error_message; +}; + +struct _cffi_externpy_s { + const char *name; + size_t size_of_result; + void *reserved1, *reserved2; +}; + +#ifdef _CFFI_INTERNAL +static int parse_c_type(struct _cffi_parse_info_s *info, const char *input); +static int search_in_globals(const struct _cffi_type_context_s *ctx, + const char *search, size_t search_len); +static int search_in_struct_unions(const struct _cffi_type_context_s *ctx, + const char *search, size_t search_len); +#endif diff --git a/venv/Lib/site-packages/cffi/pkgconfig.py b/venv/Lib/site-packages/cffi/pkgconfig.py new file mode 100644 index 000000000..5c93f15a6 --- /dev/null +++ b/venv/Lib/site-packages/cffi/pkgconfig.py @@ -0,0 +1,121 @@ +# pkg-config, https://www.freedesktop.org/wiki/Software/pkg-config/ integration for cffi +import sys, os, subprocess + +from .error import PkgConfigError + + +def merge_flags(cfg1, cfg2): + """Merge values from cffi config flags cfg2 to cf1 + + Example: + merge_flags({"libraries": ["one"]}, {"libraries": ["two"]}) + {"libraries": ["one", "two"]} + """ + for key, value in cfg2.items(): + if key not in cfg1: + cfg1[key] = value + else: + if not isinstance(cfg1[key], list): + raise TypeError("cfg1[%r] should be a list of strings" % (key,)) + if not isinstance(value, list): + raise TypeError("cfg2[%r] should be a list of strings" % (key,)) + cfg1[key].extend(value) + return cfg1 + + +def call(libname, flag, encoding=sys.getfilesystemencoding()): + """Calls pkg-config and returns the output if found + """ + a = ["pkg-config", "--print-errors"] + a.append(flag) + a.append(libname) + try: + pc = subprocess.Popen(a, stdout=subprocess.PIPE, stderr=subprocess.PIPE) + except EnvironmentError as e: + raise PkgConfigError("cannot run pkg-config: %s" % (str(e).strip(),)) + + bout, berr = pc.communicate() + if pc.returncode != 0: + try: + berr = berr.decode(encoding) + except Exception: + pass + raise PkgConfigError(berr.strip()) + + if sys.version_info >= (3,) and not isinstance(bout, str): # Python 3.x + try: + bout = bout.decode(encoding) + except UnicodeDecodeError: + raise PkgConfigError("pkg-config %s %s returned bytes that cannot " + "be decoded with encoding %r:\n%r" % + (flag, libname, encoding, bout)) + + if os.altsep != '\\' and '\\' in bout: + raise PkgConfigError("pkg-config %s %s returned an unsupported " + "backslash-escaped output:\n%r" % + (flag, libname, bout)) + return bout + + +def flags_from_pkgconfig(libs): + r"""Return compiler line flags for FFI.set_source based on pkg-config output + + Usage + ... + ffibuilder.set_source("_foo", pkgconfig = ["libfoo", "libbar >= 1.8.3"]) + + If pkg-config is installed on build machine, then arguments include_dirs, + library_dirs, libraries, define_macros, extra_compile_args and + extra_link_args are extended with an output of pkg-config for libfoo and + libbar. + + Raises PkgConfigError in case the pkg-config call fails. + """ + + def get_include_dirs(string): + return [x[2:] for x in string.split() if x.startswith("-I")] + + def get_library_dirs(string): + return [x[2:] for x in string.split() if x.startswith("-L")] + + def get_libraries(string): + return [x[2:] for x in string.split() if x.startswith("-l")] + + # convert -Dfoo=bar to list of tuples [("foo", "bar")] expected by distutils + def get_macros(string): + def _macro(x): + x = x[2:] # drop "-D" + if '=' in x: + return tuple(x.split("=", 1)) # "-Dfoo=bar" => ("foo", "bar") + else: + return (x, None) # "-Dfoo" => ("foo", None) + return [_macro(x) for x in string.split() if x.startswith("-D")] + + def get_other_cflags(string): + return [x for x in string.split() if not x.startswith("-I") and + not x.startswith("-D")] + + def get_other_libs(string): + return [x for x in string.split() if not x.startswith("-L") and + not x.startswith("-l")] + + # return kwargs for given libname + def kwargs(libname): + fse = sys.getfilesystemencoding() + all_cflags = call(libname, "--cflags") + all_libs = call(libname, "--libs") + return { + "include_dirs": get_include_dirs(all_cflags), + "library_dirs": get_library_dirs(all_libs), + "libraries": get_libraries(all_libs), + "define_macros": get_macros(all_cflags), + "extra_compile_args": get_other_cflags(all_cflags), + "extra_link_args": get_other_libs(all_libs), + } + + # merge all arguments together + ret = {} + for libname in libs: + lib_flags = kwargs(libname) + merge_flags(ret, lib_flags) + return ret diff --git a/venv/Lib/site-packages/cffi/recompiler.py b/venv/Lib/site-packages/cffi/recompiler.py new file mode 100644 index 000000000..1aeae5b92 --- /dev/null +++ b/venv/Lib/site-packages/cffi/recompiler.py @@ -0,0 +1,1571 @@ +import os, sys, io +from . import ffiplatform, model +from .error import VerificationError +from .cffi_opcode import * + +VERSION_BASE = 0x2601 +VERSION_EMBEDDED = 0x2701 +VERSION_CHAR16CHAR32 = 0x2801 + +USE_LIMITED_API = (sys.platform != 'win32' or sys.version_info < (3, 0) or + sys.version_info >= (3, 5)) + + +class GlobalExpr: + def __init__(self, name, address, type_op, size=0, check_value=0): + self.name = name + self.address = address + self.type_op = type_op + self.size = size + self.check_value = check_value + + def as_c_expr(self): + return ' { "%s", (void *)%s, %s, (void *)%s },' % ( + self.name, self.address, self.type_op.as_c_expr(), self.size) + + def as_python_expr(self): + return "b'%s%s',%d" % (self.type_op.as_python_bytes(), self.name, + self.check_value) + +class FieldExpr: + def __init__(self, name, field_offset, field_size, fbitsize, field_type_op): + self.name = name + self.field_offset = field_offset + self.field_size = field_size + self.fbitsize = fbitsize + self.field_type_op = field_type_op + + def as_c_expr(self): + spaces = " " * len(self.name) + return (' { "%s", %s,\n' % (self.name, self.field_offset) + + ' %s %s,\n' % (spaces, self.field_size) + + ' %s %s },' % (spaces, self.field_type_op.as_c_expr())) + + def as_python_expr(self): + raise NotImplementedError + + def as_field_python_expr(self): + if self.field_type_op.op == OP_NOOP: + size_expr = '' + elif self.field_type_op.op == OP_BITFIELD: + size_expr = format_four_bytes(self.fbitsize) + else: + raise NotImplementedError + return "b'%s%s%s'" % (self.field_type_op.as_python_bytes(), + size_expr, + self.name) + +class StructUnionExpr: + def __init__(self, name, type_index, flags, size, alignment, comment, + first_field_index, c_fields): + self.name = name + self.type_index = type_index + self.flags = flags + self.size = size + self.alignment = alignment + self.comment = comment + self.first_field_index = first_field_index + self.c_fields = c_fields + + def as_c_expr(self): + return (' { "%s", %d, %s,' % (self.name, self.type_index, self.flags) + + '\n %s, %s, ' % (self.size, self.alignment) + + '%d, %d ' % (self.first_field_index, len(self.c_fields)) + + ('/* %s */ ' % self.comment if self.comment else '') + + '},') + + def as_python_expr(self): + flags = eval(self.flags, G_FLAGS) + fields_expr = [c_field.as_field_python_expr() + for c_field in self.c_fields] + return "(b'%s%s%s',%s)" % ( + format_four_bytes(self.type_index), + format_four_bytes(flags), + self.name, + ','.join(fields_expr)) + +class EnumExpr: + def __init__(self, name, type_index, size, signed, allenums): + self.name = name + self.type_index = type_index + self.size = size + self.signed = signed + self.allenums = allenums + + def as_c_expr(self): + return (' { "%s", %d, _cffi_prim_int(%s, %s),\n' + ' "%s" },' % (self.name, self.type_index, + self.size, self.signed, self.allenums)) + + def as_python_expr(self): + prim_index = { + (1, 0): PRIM_UINT8, (1, 1): PRIM_INT8, + (2, 0): PRIM_UINT16, (2, 1): PRIM_INT16, + (4, 0): PRIM_UINT32, (4, 1): PRIM_INT32, + (8, 0): PRIM_UINT64, (8, 1): PRIM_INT64, + }[self.size, self.signed] + return "b'%s%s%s\\x00%s'" % (format_four_bytes(self.type_index), + format_four_bytes(prim_index), + self.name, self.allenums) + +class TypenameExpr: + def __init__(self, name, type_index): + self.name = name + self.type_index = type_index + + def as_c_expr(self): + return ' { "%s", %d },' % (self.name, self.type_index) + + def as_python_expr(self): + return "b'%s%s'" % (format_four_bytes(self.type_index), self.name) + + +# ____________________________________________________________ + + +class Recompiler: + _num_externpy = 0 + + def __init__(self, ffi, module_name, target_is_python=False): + self.ffi = ffi + self.module_name = module_name + self.target_is_python = target_is_python + self._version = VERSION_BASE + + def needs_version(self, ver): + self._version = max(self._version, ver) + + def collect_type_table(self): + self._typesdict = {} + self._generate("collecttype") + # + all_decls = sorted(self._typesdict, key=str) + # + # prepare all FUNCTION bytecode sequences first + self.cffi_types = [] + for tp in all_decls: + if tp.is_raw_function: + assert self._typesdict[tp] is None + self._typesdict[tp] = len(self.cffi_types) + self.cffi_types.append(tp) # placeholder + for tp1 in tp.args: + assert isinstance(tp1, (model.VoidType, + model.BasePrimitiveType, + model.PointerType, + model.StructOrUnionOrEnum, + model.FunctionPtrType)) + if self._typesdict[tp1] is None: + self._typesdict[tp1] = len(self.cffi_types) + self.cffi_types.append(tp1) # placeholder + self.cffi_types.append('END') # placeholder + # + # prepare all OTHER bytecode sequences + for tp in all_decls: + if not tp.is_raw_function and self._typesdict[tp] is None: + self._typesdict[tp] = len(self.cffi_types) + self.cffi_types.append(tp) # placeholder + if tp.is_array_type and tp.length is not None: + self.cffi_types.append('LEN') # placeholder + assert None not in self._typesdict.values() + # + # collect all structs and unions and enums + self._struct_unions = {} + self._enums = {} + for tp in all_decls: + if isinstance(tp, model.StructOrUnion): + self._struct_unions[tp] = None + elif isinstance(tp, model.EnumType): + self._enums[tp] = None + for i, tp in enumerate(sorted(self._struct_unions, + key=lambda tp: tp.name)): + self._struct_unions[tp] = i + for i, tp in enumerate(sorted(self._enums, + key=lambda tp: tp.name)): + self._enums[tp] = i + # + # emit all bytecode sequences now + for tp in all_decls: + method = getattr(self, '_emit_bytecode_' + tp.__class__.__name__) + method(tp, self._typesdict[tp]) + # + # consistency check + for op in self.cffi_types: + assert isinstance(op, CffiOp) + self.cffi_types = tuple(self.cffi_types) # don't change any more + + def _do_collect_type(self, tp): + if not isinstance(tp, model.BaseTypeByIdentity): + if isinstance(tp, tuple): + for x in tp: + self._do_collect_type(x) + return + if tp not in self._typesdict: + self._typesdict[tp] = None + if isinstance(tp, model.FunctionPtrType): + self._do_collect_type(tp.as_raw_function()) + elif isinstance(tp, model.StructOrUnion): + if tp.fldtypes is not None and ( + tp not in self.ffi._parser._included_declarations): + for name1, tp1, _, _ in tp.enumfields(): + self._do_collect_type(self._field_type(tp, name1, tp1)) + else: + for _, x in tp._get_items(): + self._do_collect_type(x) + + def _generate(self, step_name): + lst = self.ffi._parser._declarations.items() + for name, (tp, quals) in sorted(lst): + kind, realname = name.split(' ', 1) + try: + method = getattr(self, '_generate_cpy_%s_%s' % (kind, + step_name)) + except AttributeError: + raise VerificationError( + "not implemented in recompile(): %r" % name) + try: + self._current_quals = quals + method(tp, realname) + except Exception as e: + model.attach_exception_info(e, name) + raise + + # ---------- + + ALL_STEPS = ["global", "field", "struct_union", "enum", "typename"] + + def collect_step_tables(self): + # collect the declarations for '_cffi_globals', '_cffi_typenames', etc. + self._lsts = {} + for step_name in self.ALL_STEPS: + self._lsts[step_name] = [] + self._seen_struct_unions = set() + self._generate("ctx") + self._add_missing_struct_unions() + # + for step_name in self.ALL_STEPS: + lst = self._lsts[step_name] + if step_name != "field": + lst.sort(key=lambda entry: entry.name) + self._lsts[step_name] = tuple(lst) # don't change any more + # + # check for a possible internal inconsistency: _cffi_struct_unions + # should have been generated with exactly self._struct_unions + lst = self._lsts["struct_union"] + for tp, i in self._struct_unions.items(): + assert i < len(lst) + assert lst[i].name == tp.name + assert len(lst) == len(self._struct_unions) + # same with enums + lst = self._lsts["enum"] + for tp, i in self._enums.items(): + assert i < len(lst) + assert lst[i].name == tp.name + assert len(lst) == len(self._enums) + + # ---------- + + def _prnt(self, what=''): + self._f.write(what + '\n') + + def write_source_to_f(self, f, preamble): + if self.target_is_python: + assert preamble is None + self.write_py_source_to_f(f) + else: + assert preamble is not None + self.write_c_source_to_f(f, preamble) + + def _rel_readlines(self, filename): + g = open(os.path.join(os.path.dirname(__file__), filename), 'r') + lines = g.readlines() + g.close() + return lines + + def write_c_source_to_f(self, f, preamble): + self._f = f + prnt = self._prnt + if self.ffi._embedding is not None: + prnt('#define _CFFI_USE_EMBEDDING') + if not USE_LIMITED_API: + prnt('#define _CFFI_NO_LIMITED_API') + # + # first the '#include' (actually done by inlining the file's content) + lines = self._rel_readlines('_cffi_include.h') + i = lines.index('#include "parse_c_type.h"\n') + lines[i:i+1] = self._rel_readlines('parse_c_type.h') + prnt(''.join(lines)) + # + # if we have ffi._embedding != None, we give it here as a macro + # and include an extra file + base_module_name = self.module_name.split('.')[-1] + if self.ffi._embedding is not None: + prnt('#define _CFFI_MODULE_NAME "%s"' % (self.module_name,)) + prnt('static const char _CFFI_PYTHON_STARTUP_CODE[] = {') + self._print_string_literal_in_array(self.ffi._embedding) + prnt('0 };') + prnt('#ifdef PYPY_VERSION') + prnt('# define _CFFI_PYTHON_STARTUP_FUNC _cffi_pypyinit_%s' % ( + base_module_name,)) + prnt('#elif PY_MAJOR_VERSION >= 3') + prnt('# define _CFFI_PYTHON_STARTUP_FUNC PyInit_%s' % ( + base_module_name,)) + prnt('#else') + prnt('# define _CFFI_PYTHON_STARTUP_FUNC init%s' % ( + base_module_name,)) + prnt('#endif') + lines = self._rel_readlines('_embedding.h') + i = lines.index('#include "_cffi_errors.h"\n') + lines[i:i+1] = self._rel_readlines('_cffi_errors.h') + prnt(''.join(lines)) + self.needs_version(VERSION_EMBEDDED) + # + # then paste the C source given by the user, verbatim. + prnt('/************************************************************/') + prnt() + prnt(preamble) + prnt() + prnt('/************************************************************/') + prnt() + # + # the declaration of '_cffi_types' + prnt('static void *_cffi_types[] = {') + typeindex2type = dict([(i, tp) for (tp, i) in self._typesdict.items()]) + for i, op in enumerate(self.cffi_types): + comment = '' + if i in typeindex2type: + comment = ' // ' + typeindex2type[i]._get_c_name() + prnt('/* %2d */ %s,%s' % (i, op.as_c_expr(), comment)) + if not self.cffi_types: + prnt(' 0') + prnt('};') + prnt() + # + # call generate_cpy_xxx_decl(), for every xxx found from + # ffi._parser._declarations. This generates all the functions. + self._seen_constants = set() + self._generate("decl") + # + # the declaration of '_cffi_globals' and '_cffi_typenames' + nums = {} + for step_name in self.ALL_STEPS: + lst = self._lsts[step_name] + nums[step_name] = len(lst) + if nums[step_name] > 0: + prnt('static const struct _cffi_%s_s _cffi_%ss[] = {' % ( + step_name, step_name)) + for entry in lst: + prnt(entry.as_c_expr()) + prnt('};') + prnt() + # + # the declaration of '_cffi_includes' + if self.ffi._included_ffis: + prnt('static const char * const _cffi_includes[] = {') + for ffi_to_include in self.ffi._included_ffis: + try: + included_module_name, included_source = ( + ffi_to_include._assigned_source[:2]) + except AttributeError: + raise VerificationError( + "ffi object %r includes %r, but the latter has not " + "been prepared with set_source()" % ( + self.ffi, ffi_to_include,)) + if included_source is None: + raise VerificationError( + "not implemented yet: ffi.include() of a Python-based " + "ffi inside a C-based ffi") + prnt(' "%s",' % (included_module_name,)) + prnt(' NULL') + prnt('};') + prnt() + # + # the declaration of '_cffi_type_context' + prnt('static const struct _cffi_type_context_s _cffi_type_context = {') + prnt(' _cffi_types,') + for step_name in self.ALL_STEPS: + if nums[step_name] > 0: + prnt(' _cffi_%ss,' % step_name) + else: + prnt(' NULL, /* no %ss */' % step_name) + for step_name in self.ALL_STEPS: + if step_name != "field": + prnt(' %d, /* num_%ss */' % (nums[step_name], step_name)) + if self.ffi._included_ffis: + prnt(' _cffi_includes,') + else: + prnt(' NULL, /* no includes */') + prnt(' %d, /* num_types */' % (len(self.cffi_types),)) + flags = 0 + if self._num_externpy: + flags |= 1 # set to mean that we use extern "Python" + prnt(' %d, /* flags */' % flags) + prnt('};') + prnt() + # + # the init function + prnt('#ifdef __GNUC__') + prnt('# pragma GCC visibility push(default) /* for -fvisibility= */') + prnt('#endif') + prnt() + prnt('#ifdef PYPY_VERSION') + prnt('PyMODINIT_FUNC') + prnt('_cffi_pypyinit_%s(const void *p[])' % (base_module_name,)) + prnt('{') + if self._num_externpy: + prnt(' if (((intptr_t)p[0]) >= 0x0A03) {') + prnt(' _cffi_call_python_org = ' + '(void(*)(struct _cffi_externpy_s *, char *))p[1];') + prnt(' }') + prnt(' p[0] = (const void *)0x%x;' % self._version) + prnt(' p[1] = &_cffi_type_context;') + prnt('#if PY_MAJOR_VERSION >= 3') + prnt(' return NULL;') + prnt('#endif') + prnt('}') + # on Windows, distutils insists on putting init_cffi_xyz in + # 'export_symbols', so instead of fighting it, just give up and + # give it one + prnt('# ifdef _MSC_VER') + prnt(' PyMODINIT_FUNC') + prnt('# if PY_MAJOR_VERSION >= 3') + prnt(' PyInit_%s(void) { return NULL; }' % (base_module_name,)) + prnt('# else') + prnt(' init%s(void) { }' % (base_module_name,)) + prnt('# endif') + prnt('# endif') + prnt('#elif PY_MAJOR_VERSION >= 3') + prnt('PyMODINIT_FUNC') + prnt('PyInit_%s(void)' % (base_module_name,)) + prnt('{') + prnt(' return _cffi_init("%s", 0x%x, &_cffi_type_context);' % ( + self.module_name, self._version)) + prnt('}') + prnt('#else') + prnt('PyMODINIT_FUNC') + prnt('init%s(void)' % (base_module_name,)) + prnt('{') + prnt(' _cffi_init("%s", 0x%x, &_cffi_type_context);' % ( + self.module_name, self._version)) + prnt('}') + prnt('#endif') + prnt() + prnt('#ifdef __GNUC__') + prnt('# pragma GCC visibility pop') + prnt('#endif') + self._version = None + + def _to_py(self, x): + if isinstance(x, str): + return "b'%s'" % (x,) + if isinstance(x, (list, tuple)): + rep = [self._to_py(item) for item in x] + if len(rep) == 1: + rep.append('') + return "(%s)" % (','.join(rep),) + return x.as_python_expr() # Py2: unicode unexpected; Py3: bytes unexp. + + def write_py_source_to_f(self, f): + self._f = f + prnt = self._prnt + # + # header + prnt("# auto-generated file") + prnt("import _cffi_backend") + # + # the 'import' of the included ffis + num_includes = len(self.ffi._included_ffis or ()) + for i in range(num_includes): + ffi_to_include = self.ffi._included_ffis[i] + try: + included_module_name, included_source = ( + ffi_to_include._assigned_source[:2]) + except AttributeError: + raise VerificationError( + "ffi object %r includes %r, but the latter has not " + "been prepared with set_source()" % ( + self.ffi, ffi_to_include,)) + if included_source is not None: + raise VerificationError( + "not implemented yet: ffi.include() of a C-based " + "ffi inside a Python-based ffi") + prnt('from %s import ffi as _ffi%d' % (included_module_name, i)) + prnt() + prnt("ffi = _cffi_backend.FFI('%s'," % (self.module_name,)) + prnt(" _version = 0x%x," % (self._version,)) + self._version = None + # + # the '_types' keyword argument + self.cffi_types = tuple(self.cffi_types) # don't change any more + types_lst = [op.as_python_bytes() for op in self.cffi_types] + prnt(' _types = %s,' % (self._to_py(''.join(types_lst)),)) + typeindex2type = dict([(i, tp) for (tp, i) in self._typesdict.items()]) + # + # the keyword arguments from ALL_STEPS + for step_name in self.ALL_STEPS: + lst = self._lsts[step_name] + if len(lst) > 0 and step_name != "field": + prnt(' _%ss = %s,' % (step_name, self._to_py(lst))) + # + # the '_includes' keyword argument + if num_includes > 0: + prnt(' _includes = (%s,),' % ( + ', '.join(['_ffi%d' % i for i in range(num_includes)]),)) + # + # the footer + prnt(')') + + # ---------- + + def _gettypenum(self, type): + # a KeyError here is a bug. please report it! :-) + return self._typesdict[type] + + def _convert_funcarg_to_c(self, tp, fromvar, tovar, errcode): + extraarg = '' + if isinstance(tp, model.BasePrimitiveType) and not tp.is_complex_type(): + if tp.is_integer_type() and tp.name != '_Bool': + converter = '_cffi_to_c_int' + extraarg = ', %s' % tp.name + elif isinstance(tp, model.UnknownFloatType): + # don't check with is_float_type(): it may be a 'long + # double' here, and _cffi_to_c_double would loose precision + converter = '(%s)_cffi_to_c_double' % (tp.get_c_name(''),) + else: + cname = tp.get_c_name('') + converter = '(%s)_cffi_to_c_%s' % (cname, + tp.name.replace(' ', '_')) + if cname in ('char16_t', 'char32_t'): + self.needs_version(VERSION_CHAR16CHAR32) + errvalue = '-1' + # + elif isinstance(tp, model.PointerType): + self._convert_funcarg_to_c_ptr_or_array(tp, fromvar, + tovar, errcode) + return + # + elif (isinstance(tp, model.StructOrUnionOrEnum) or + isinstance(tp, model.BasePrimitiveType)): + # a struct (not a struct pointer) as a function argument; + # or, a complex (the same code works) + self._prnt(' if (_cffi_to_c((char *)&%s, _cffi_type(%d), %s) < 0)' + % (tovar, self._gettypenum(tp), fromvar)) + self._prnt(' %s;' % errcode) + return + # + elif isinstance(tp, model.FunctionPtrType): + converter = '(%s)_cffi_to_c_pointer' % tp.get_c_name('') + extraarg = ', _cffi_type(%d)' % self._gettypenum(tp) + errvalue = 'NULL' + # + else: + raise NotImplementedError(tp) + # + self._prnt(' %s = %s(%s%s);' % (tovar, converter, fromvar, extraarg)) + self._prnt(' if (%s == (%s)%s && PyErr_Occurred())' % ( + tovar, tp.get_c_name(''), errvalue)) + self._prnt(' %s;' % errcode) + + def _extra_local_variables(self, tp, localvars, freelines): + if isinstance(tp, model.PointerType): + localvars.add('Py_ssize_t datasize') + localvars.add('struct _cffi_freeme_s *large_args_free = NULL') + freelines.add('if (large_args_free != NULL)' + ' _cffi_free_array_arguments(large_args_free);') + + def _convert_funcarg_to_c_ptr_or_array(self, tp, fromvar, tovar, errcode): + self._prnt(' datasize = _cffi_prepare_pointer_call_argument(') + self._prnt(' _cffi_type(%d), %s, (char **)&%s);' % ( + self._gettypenum(tp), fromvar, tovar)) + self._prnt(' if (datasize != 0) {') + self._prnt(' %s = ((size_t)datasize) <= 640 ? ' + '(%s)alloca((size_t)datasize) : NULL;' % ( + tovar, tp.get_c_name(''))) + self._prnt(' if (_cffi_convert_array_argument(_cffi_type(%d), %s, ' + '(char **)&%s,' % (self._gettypenum(tp), fromvar, tovar)) + self._prnt(' datasize, &large_args_free) < 0)') + self._prnt(' %s;' % errcode) + self._prnt(' }') + + def _convert_expr_from_c(self, tp, var, context): + if isinstance(tp, model.BasePrimitiveType): + if tp.is_integer_type() and tp.name != '_Bool': + return '_cffi_from_c_int(%s, %s)' % (var, tp.name) + elif isinstance(tp, model.UnknownFloatType): + return '_cffi_from_c_double(%s)' % (var,) + elif tp.name != 'long double' and not tp.is_complex_type(): + cname = tp.name.replace(' ', '_') + if cname in ('char16_t', 'char32_t'): + self.needs_version(VERSION_CHAR16CHAR32) + return '_cffi_from_c_%s(%s)' % (cname, var) + else: + return '_cffi_from_c_deref((char *)&%s, _cffi_type(%d))' % ( + var, self._gettypenum(tp)) + elif isinstance(tp, (model.PointerType, model.FunctionPtrType)): + return '_cffi_from_c_pointer((char *)%s, _cffi_type(%d))' % ( + var, self._gettypenum(tp)) + elif isinstance(tp, model.ArrayType): + return '_cffi_from_c_pointer((char *)%s, _cffi_type(%d))' % ( + var, self._gettypenum(model.PointerType(tp.item))) + elif isinstance(tp, model.StructOrUnion): + if tp.fldnames is None: + raise TypeError("'%s' is used as %s, but is opaque" % ( + tp._get_c_name(), context)) + return '_cffi_from_c_struct((char *)&%s, _cffi_type(%d))' % ( + var, self._gettypenum(tp)) + elif isinstance(tp, model.EnumType): + return '_cffi_from_c_deref((char *)&%s, _cffi_type(%d))' % ( + var, self._gettypenum(tp)) + else: + raise NotImplementedError(tp) + + # ---------- + # typedefs + + def _typedef_type(self, tp, name): + return self._global_type(tp, "(*(%s *)0)" % (name,)) + + def _generate_cpy_typedef_collecttype(self, tp, name): + self._do_collect_type(self._typedef_type(tp, name)) + + def _generate_cpy_typedef_decl(self, tp, name): + pass + + def _typedef_ctx(self, tp, name): + type_index = self._typesdict[tp] + self._lsts["typename"].append(TypenameExpr(name, type_index)) + + def _generate_cpy_typedef_ctx(self, tp, name): + tp = self._typedef_type(tp, name) + self._typedef_ctx(tp, name) + if getattr(tp, "origin", None) == "unknown_type": + self._struct_ctx(tp, tp.name, approxname=None) + elif isinstance(tp, model.NamedPointerType): + self._struct_ctx(tp.totype, tp.totype.name, approxname=tp.name, + named_ptr=tp) + + # ---------- + # function declarations + + def _generate_cpy_function_collecttype(self, tp, name): + self._do_collect_type(tp.as_raw_function()) + if tp.ellipsis and not self.target_is_python: + self._do_collect_type(tp) + + def _generate_cpy_function_decl(self, tp, name): + assert not self.target_is_python + assert isinstance(tp, model.FunctionPtrType) + if tp.ellipsis: + # cannot support vararg functions better than this: check for its + # exact type (including the fixed arguments), and build it as a + # constant function pointer (no CPython wrapper) + self._generate_cpy_constant_decl(tp, name) + return + prnt = self._prnt + numargs = len(tp.args) + if numargs == 0: + argname = 'noarg' + elif numargs == 1: + argname = 'arg0' + else: + argname = 'args' + # + # ------------------------------ + # the 'd' version of the function, only for addressof(lib, 'func') + arguments = [] + call_arguments = [] + context = 'argument of %s' % name + for i, type in enumerate(tp.args): + arguments.append(type.get_c_name(' x%d' % i, context)) + call_arguments.append('x%d' % i) + repr_arguments = ', '.join(arguments) + repr_arguments = repr_arguments or 'void' + if tp.abi: + abi = tp.abi + ' ' + else: + abi = '' + name_and_arguments = '%s_cffi_d_%s(%s)' % (abi, name, repr_arguments) + prnt('static %s' % (tp.result.get_c_name(name_and_arguments),)) + prnt('{') + call_arguments = ', '.join(call_arguments) + result_code = 'return ' + if isinstance(tp.result, model.VoidType): + result_code = '' + prnt(' %s%s(%s);' % (result_code, name, call_arguments)) + prnt('}') + # + prnt('#ifndef PYPY_VERSION') # ------------------------------ + # + prnt('static PyObject *') + prnt('_cffi_f_%s(PyObject *self, PyObject *%s)' % (name, argname)) + prnt('{') + # + context = 'argument of %s' % name + for i, type in enumerate(tp.args): + arg = type.get_c_name(' x%d' % i, context) + prnt(' %s;' % arg) + # + localvars = set() + freelines = set() + for type in tp.args: + self._extra_local_variables(type, localvars, freelines) + for decl in sorted(localvars): + prnt(' %s;' % (decl,)) + # + if not isinstance(tp.result, model.VoidType): + result_code = 'result = ' + context = 'result of %s' % name + result_decl = ' %s;' % tp.result.get_c_name(' result', context) + prnt(result_decl) + prnt(' PyObject *pyresult;') + else: + result_decl = None + result_code = '' + # + if len(tp.args) > 1: + rng = range(len(tp.args)) + for i in rng: + prnt(' PyObject *arg%d;' % i) + prnt() + prnt(' if (!PyArg_UnpackTuple(args, "%s", %d, %d, %s))' % ( + name, len(rng), len(rng), + ', '.join(['&arg%d' % i for i in rng]))) + prnt(' return NULL;') + prnt() + # + for i, type in enumerate(tp.args): + self._convert_funcarg_to_c(type, 'arg%d' % i, 'x%d' % i, + 'return NULL') + prnt() + # + prnt(' Py_BEGIN_ALLOW_THREADS') + prnt(' _cffi_restore_errno();') + call_arguments = ['x%d' % i for i in range(len(tp.args))] + call_arguments = ', '.join(call_arguments) + prnt(' { %s%s(%s); }' % (result_code, name, call_arguments)) + prnt(' _cffi_save_errno();') + prnt(' Py_END_ALLOW_THREADS') + prnt() + # + prnt(' (void)self; /* unused */') + if numargs == 0: + prnt(' (void)noarg; /* unused */') + if result_code: + prnt(' pyresult = %s;' % + self._convert_expr_from_c(tp.result, 'result', 'result type')) + for freeline in freelines: + prnt(' ' + freeline) + prnt(' return pyresult;') + else: + for freeline in freelines: + prnt(' ' + freeline) + prnt(' Py_INCREF(Py_None);') + prnt(' return Py_None;') + prnt('}') + # + prnt('#else') # ------------------------------ + # + # the PyPy version: need to replace struct/union arguments with + # pointers, and if the result is a struct/union, insert a first + # arg that is a pointer to the result. We also do that for + # complex args and return type. + def need_indirection(type): + return (isinstance(type, model.StructOrUnion) or + (isinstance(type, model.PrimitiveType) and + type.is_complex_type())) + difference = False + arguments = [] + call_arguments = [] + context = 'argument of %s' % name + for i, type in enumerate(tp.args): + indirection = '' + if need_indirection(type): + indirection = '*' + difference = True + arg = type.get_c_name(' %sx%d' % (indirection, i), context) + arguments.append(arg) + call_arguments.append('%sx%d' % (indirection, i)) + tp_result = tp.result + if need_indirection(tp_result): + context = 'result of %s' % name + arg = tp_result.get_c_name(' *result', context) + arguments.insert(0, arg) + tp_result = model.void_type + result_decl = None + result_code = '*result = ' + difference = True + if difference: + repr_arguments = ', '.join(arguments) + repr_arguments = repr_arguments or 'void' + name_and_arguments = '%s_cffi_f_%s(%s)' % (abi, name, + repr_arguments) + prnt('static %s' % (tp_result.get_c_name(name_and_arguments),)) + prnt('{') + if result_decl: + prnt(result_decl) + call_arguments = ', '.join(call_arguments) + prnt(' { %s%s(%s); }' % (result_code, name, call_arguments)) + if result_decl: + prnt(' return result;') + prnt('}') + else: + prnt('# define _cffi_f_%s _cffi_d_%s' % (name, name)) + # + prnt('#endif') # ------------------------------ + prnt() + + def _generate_cpy_function_ctx(self, tp, name): + if tp.ellipsis and not self.target_is_python: + self._generate_cpy_constant_ctx(tp, name) + return + type_index = self._typesdict[tp.as_raw_function()] + numargs = len(tp.args) + if self.target_is_python: + meth_kind = OP_DLOPEN_FUNC + elif numargs == 0: + meth_kind = OP_CPYTHON_BLTN_N # 'METH_NOARGS' + elif numargs == 1: + meth_kind = OP_CPYTHON_BLTN_O # 'METH_O' + else: + meth_kind = OP_CPYTHON_BLTN_V # 'METH_VARARGS' + self._lsts["global"].append( + GlobalExpr(name, '_cffi_f_%s' % name, + CffiOp(meth_kind, type_index), + size='_cffi_d_%s' % name)) + + # ---------- + # named structs or unions + + def _field_type(self, tp_struct, field_name, tp_field): + if isinstance(tp_field, model.ArrayType): + actual_length = tp_field.length + if actual_length == '...': + ptr_struct_name = tp_struct.get_c_name('*') + actual_length = '_cffi_array_len(((%s)0)->%s)' % ( + ptr_struct_name, field_name) + tp_item = self._field_type(tp_struct, '%s[0]' % field_name, + tp_field.item) + tp_field = model.ArrayType(tp_item, actual_length) + return tp_field + + def _struct_collecttype(self, tp): + self._do_collect_type(tp) + if self.target_is_python: + # also requires nested anon struct/unions in ABI mode, recursively + for fldtype in tp.anonymous_struct_fields(): + self._struct_collecttype(fldtype) + + def _struct_decl(self, tp, cname, approxname): + if tp.fldtypes is None: + return + prnt = self._prnt + checkfuncname = '_cffi_checkfld_%s' % (approxname,) + prnt('_CFFI_UNUSED_FN') + prnt('static void %s(%s *p)' % (checkfuncname, cname)) + prnt('{') + prnt(' /* only to generate compile-time warnings or errors */') + prnt(' (void)p;') + for fname, ftype, fbitsize, fqual in tp.enumfields(): + try: + if ftype.is_integer_type() or fbitsize >= 0: + # accept all integers, but complain on float or double + if fname != '': + prnt(" (void)((p->%s) | 0); /* check that '%s.%s' is " + "an integer */" % (fname, cname, fname)) + continue + # only accept exactly the type declared, except that '[]' + # is interpreted as a '*' and so will match any array length. + # (It would also match '*', but that's harder to detect...) + while (isinstance(ftype, model.ArrayType) + and (ftype.length is None or ftype.length == '...')): + ftype = ftype.item + fname = fname + '[0]' + prnt(' { %s = &p->%s; (void)tmp; }' % ( + ftype.get_c_name('*tmp', 'field %r'%fname, quals=fqual), + fname)) + except VerificationError as e: + prnt(' /* %s */' % str(e)) # cannot verify it, ignore + prnt('}') + prnt('struct _cffi_align_%s { char x; %s y; };' % (approxname, cname)) + prnt() + + def _struct_ctx(self, tp, cname, approxname, named_ptr=None): + type_index = self._typesdict[tp] + reason_for_not_expanding = None + flags = [] + if isinstance(tp, model.UnionType): + flags.append("_CFFI_F_UNION") + if tp.fldtypes is None: + flags.append("_CFFI_F_OPAQUE") + reason_for_not_expanding = "opaque" + if (tp not in self.ffi._parser._included_declarations and + (named_ptr is None or + named_ptr not in self.ffi._parser._included_declarations)): + if tp.fldtypes is None: + pass # opaque + elif tp.partial or any(tp.anonymous_struct_fields()): + pass # field layout obtained silently from the C compiler + else: + flags.append("_CFFI_F_CHECK_FIELDS") + if tp.packed: + if tp.packed > 1: + raise NotImplementedError( + "%r is declared with 'pack=%r'; only 0 or 1 are " + "supported in API mode (try to use \"...;\", which " + "does not require a 'pack' declaration)" % + (tp, tp.packed)) + flags.append("_CFFI_F_PACKED") + else: + flags.append("_CFFI_F_EXTERNAL") + reason_for_not_expanding = "external" + flags = '|'.join(flags) or '0' + c_fields = [] + if reason_for_not_expanding is None: + expand_anonymous_struct_union = not self.target_is_python + enumfields = list(tp.enumfields(expand_anonymous_struct_union)) + for fldname, fldtype, fbitsize, fqual in enumfields: + fldtype = self._field_type(tp, fldname, fldtype) + self._check_not_opaque(fldtype, + "field '%s.%s'" % (tp.name, fldname)) + # cname is None for _add_missing_struct_unions() only + op = OP_NOOP + if fbitsize >= 0: + op = OP_BITFIELD + size = '%d /* bits */' % fbitsize + elif cname is None or ( + isinstance(fldtype, model.ArrayType) and + fldtype.length is None): + size = '(size_t)-1' + else: + size = 'sizeof(((%s)0)->%s)' % ( + tp.get_c_name('*') if named_ptr is None + else named_ptr.name, + fldname) + if cname is None or fbitsize >= 0: + offset = '(size_t)-1' + elif named_ptr is not None: + offset = '((char *)&((%s)0)->%s) - (char *)0' % ( + named_ptr.name, fldname) + else: + offset = 'offsetof(%s, %s)' % (tp.get_c_name(''), fldname) + c_fields.append( + FieldExpr(fldname, offset, size, fbitsize, + CffiOp(op, self._typesdict[fldtype]))) + first_field_index = len(self._lsts["field"]) + self._lsts["field"].extend(c_fields) + # + if cname is None: # unknown name, for _add_missing_struct_unions + size = '(size_t)-2' + align = -2 + comment = "unnamed" + else: + if named_ptr is not None: + size = 'sizeof(*(%s)0)' % (named_ptr.name,) + align = '-1 /* unknown alignment */' + else: + size = 'sizeof(%s)' % (cname,) + align = 'offsetof(struct _cffi_align_%s, y)' % (approxname,) + comment = None + else: + size = '(size_t)-1' + align = -1 + first_field_index = -1 + comment = reason_for_not_expanding + self._lsts["struct_union"].append( + StructUnionExpr(tp.name, type_index, flags, size, align, comment, + first_field_index, c_fields)) + self._seen_struct_unions.add(tp) + + def _check_not_opaque(self, tp, location): + while isinstance(tp, model.ArrayType): + tp = tp.item + if isinstance(tp, model.StructOrUnion) and tp.fldtypes is None: + raise TypeError( + "%s is of an opaque type (not declared in cdef())" % location) + + def _add_missing_struct_unions(self): + # not very nice, but some struct declarations might be missing + # because they don't have any known C name. Check that they are + # not partial (we can't complete or verify them!) and emit them + # anonymously. + lst = list(self._struct_unions.items()) + lst.sort(key=lambda tp_order: tp_order[1]) + for tp, order in lst: + if tp not in self._seen_struct_unions: + if tp.partial: + raise NotImplementedError("internal inconsistency: %r is " + "partial but was not seen at " + "this point" % (tp,)) + if tp.name.startswith('$') and tp.name[1:].isdigit(): + approxname = tp.name[1:] + elif tp.name == '_IO_FILE' and tp.forcename == 'FILE': + approxname = 'FILE' + self._typedef_ctx(tp, 'FILE') + else: + raise NotImplementedError("internal inconsistency: %r" % + (tp,)) + self._struct_ctx(tp, None, approxname) + + def _generate_cpy_struct_collecttype(self, tp, name): + self._struct_collecttype(tp) + _generate_cpy_union_collecttype = _generate_cpy_struct_collecttype + + def _struct_names(self, tp): + cname = tp.get_c_name('') + if ' ' in cname: + return cname, cname.replace(' ', '_') + else: + return cname, '_' + cname + + def _generate_cpy_struct_decl(self, tp, name): + self._struct_decl(tp, *self._struct_names(tp)) + _generate_cpy_union_decl = _generate_cpy_struct_decl + + def _generate_cpy_struct_ctx(self, tp, name): + self._struct_ctx(tp, *self._struct_names(tp)) + _generate_cpy_union_ctx = _generate_cpy_struct_ctx + + # ---------- + # 'anonymous' declarations. These are produced for anonymous structs + # or unions; the 'name' is obtained by a typedef. + + def _generate_cpy_anonymous_collecttype(self, tp, name): + if isinstance(tp, model.EnumType): + self._generate_cpy_enum_collecttype(tp, name) + else: + self._struct_collecttype(tp) + + def _generate_cpy_anonymous_decl(self, tp, name): + if isinstance(tp, model.EnumType): + self._generate_cpy_enum_decl(tp) + else: + self._struct_decl(tp, name, 'typedef_' + name) + + def _generate_cpy_anonymous_ctx(self, tp, name): + if isinstance(tp, model.EnumType): + self._enum_ctx(tp, name) + else: + self._struct_ctx(tp, name, 'typedef_' + name) + + # ---------- + # constants, declared with "static const ..." + + def _generate_cpy_const(self, is_int, name, tp=None, category='const', + check_value=None): + if (category, name) in self._seen_constants: + raise VerificationError( + "duplicate declaration of %s '%s'" % (category, name)) + self._seen_constants.add((category, name)) + # + prnt = self._prnt + funcname = '_cffi_%s_%s' % (category, name) + if is_int: + prnt('static int %s(unsigned long long *o)' % funcname) + prnt('{') + prnt(' int n = (%s) <= 0;' % (name,)) + prnt(' *o = (unsigned long long)((%s) | 0);' + ' /* check that %s is an integer */' % (name, name)) + if check_value is not None: + if check_value > 0: + check_value = '%dU' % (check_value,) + prnt(' if (!_cffi_check_int(*o, n, %s))' % (check_value,)) + prnt(' n |= 2;') + prnt(' return n;') + prnt('}') + else: + assert check_value is None + prnt('static void %s(char *o)' % funcname) + prnt('{') + prnt(' *(%s)o = %s;' % (tp.get_c_name('*'), name)) + prnt('}') + prnt() + + def _generate_cpy_constant_collecttype(self, tp, name): + is_int = tp.is_integer_type() + if not is_int or self.target_is_python: + self._do_collect_type(tp) + + def _generate_cpy_constant_decl(self, tp, name): + is_int = tp.is_integer_type() + self._generate_cpy_const(is_int, name, tp) + + def _generate_cpy_constant_ctx(self, tp, name): + if not self.target_is_python and tp.is_integer_type(): + type_op = CffiOp(OP_CONSTANT_INT, -1) + else: + if self.target_is_python: + const_kind = OP_DLOPEN_CONST + else: + const_kind = OP_CONSTANT + type_index = self._typesdict[tp] + type_op = CffiOp(const_kind, type_index) + self._lsts["global"].append( + GlobalExpr(name, '_cffi_const_%s' % name, type_op)) + + # ---------- + # enums + + def _generate_cpy_enum_collecttype(self, tp, name): + self._do_collect_type(tp) + + def _generate_cpy_enum_decl(self, tp, name=None): + for enumerator in tp.enumerators: + self._generate_cpy_const(True, enumerator) + + def _enum_ctx(self, tp, cname): + type_index = self._typesdict[tp] + type_op = CffiOp(OP_ENUM, -1) + if self.target_is_python: + tp.check_not_partial() + for enumerator, enumvalue in zip(tp.enumerators, tp.enumvalues): + self._lsts["global"].append( + GlobalExpr(enumerator, '_cffi_const_%s' % enumerator, type_op, + check_value=enumvalue)) + # + if cname is not None and '$' not in cname and not self.target_is_python: + size = "sizeof(%s)" % cname + signed = "((%s)-1) <= 0" % cname + else: + basetp = tp.build_baseinttype(self.ffi, []) + size = self.ffi.sizeof(basetp) + signed = int(int(self.ffi.cast(basetp, -1)) < 0) + allenums = ",".join(tp.enumerators) + self._lsts["enum"].append( + EnumExpr(tp.name, type_index, size, signed, allenums)) + + def _generate_cpy_enum_ctx(self, tp, name): + self._enum_ctx(tp, tp._get_c_name()) + + # ---------- + # macros: for now only for integers + + def _generate_cpy_macro_collecttype(self, tp, name): + pass + + def _generate_cpy_macro_decl(self, tp, name): + if tp == '...': + check_value = None + else: + check_value = tp # an integer + self._generate_cpy_const(True, name, check_value=check_value) + + def _generate_cpy_macro_ctx(self, tp, name): + if tp == '...': + if self.target_is_python: + raise VerificationError( + "cannot use the syntax '...' in '#define %s ...' when " + "using the ABI mode" % (name,)) + check_value = None + else: + check_value = tp # an integer + type_op = CffiOp(OP_CONSTANT_INT, -1) + self._lsts["global"].append( + GlobalExpr(name, '_cffi_const_%s' % name, type_op, + check_value=check_value)) + + # ---------- + # global variables + + def _global_type(self, tp, global_name): + if isinstance(tp, model.ArrayType): + actual_length = tp.length + if actual_length == '...': + actual_length = '_cffi_array_len(%s)' % (global_name,) + tp_item = self._global_type(tp.item, '%s[0]' % global_name) + tp = model.ArrayType(tp_item, actual_length) + return tp + + def _generate_cpy_variable_collecttype(self, tp, name): + self._do_collect_type(self._global_type(tp, name)) + + def _generate_cpy_variable_decl(self, tp, name): + prnt = self._prnt + tp = self._global_type(tp, name) + if isinstance(tp, model.ArrayType) and tp.length is None: + tp = tp.item + ampersand = '' + else: + ampersand = '&' + # This code assumes that casts from "tp *" to "void *" is a + # no-op, i.e. a function that returns a "tp *" can be called + # as if it returned a "void *". This should be generally true + # on any modern machine. The only exception to that rule (on + # uncommon architectures, and as far as I can tell) might be + # if 'tp' were a function type, but that is not possible here. + # (If 'tp' is a function _pointer_ type, then casts from "fn_t + # **" to "void *" are again no-ops, as far as I can tell.) + decl = '*_cffi_var_%s(void)' % (name,) + prnt('static ' + tp.get_c_name(decl, quals=self._current_quals)) + prnt('{') + prnt(' return %s(%s);' % (ampersand, name)) + prnt('}') + prnt() + + def _generate_cpy_variable_ctx(self, tp, name): + tp = self._global_type(tp, name) + type_index = self._typesdict[tp] + if self.target_is_python: + op = OP_GLOBAL_VAR + else: + op = OP_GLOBAL_VAR_F + self._lsts["global"].append( + GlobalExpr(name, '_cffi_var_%s' % name, CffiOp(op, type_index))) + + # ---------- + # extern "Python" + + def _generate_cpy_extern_python_collecttype(self, tp, name): + assert isinstance(tp, model.FunctionPtrType) + self._do_collect_type(tp) + _generate_cpy_dllexport_python_collecttype = \ + _generate_cpy_extern_python_plus_c_collecttype = \ + _generate_cpy_extern_python_collecttype + + def _extern_python_decl(self, tp, name, tag_and_space): + prnt = self._prnt + if isinstance(tp.result, model.VoidType): + size_of_result = '0' + else: + context = 'result of %s' % name + size_of_result = '(int)sizeof(%s)' % ( + tp.result.get_c_name('', context),) + prnt('static struct _cffi_externpy_s _cffi_externpy__%s =' % name) + prnt(' { "%s.%s", %s, 0, 0 };' % ( + self.module_name, name, size_of_result)) + prnt() + # + arguments = [] + context = 'argument of %s' % name + for i, type in enumerate(tp.args): + arg = type.get_c_name(' a%d' % i, context) + arguments.append(arg) + # + repr_arguments = ', '.join(arguments) + repr_arguments = repr_arguments or 'void' + name_and_arguments = '%s(%s)' % (name, repr_arguments) + if tp.abi == "__stdcall": + name_and_arguments = '_cffi_stdcall ' + name_and_arguments + # + def may_need_128_bits(tp): + return (isinstance(tp, model.PrimitiveType) and + tp.name == 'long double') + # + size_of_a = max(len(tp.args)*8, 8) + if may_need_128_bits(tp.result): + size_of_a = max(size_of_a, 16) + if isinstance(tp.result, model.StructOrUnion): + size_of_a = 'sizeof(%s) > %d ? sizeof(%s) : %d' % ( + tp.result.get_c_name(''), size_of_a, + tp.result.get_c_name(''), size_of_a) + prnt('%s%s' % (tag_and_space, tp.result.get_c_name(name_and_arguments))) + prnt('{') + prnt(' char a[%s];' % size_of_a) + prnt(' char *p = a;') + for i, type in enumerate(tp.args): + arg = 'a%d' % i + if (isinstance(type, model.StructOrUnion) or + may_need_128_bits(type)): + arg = '&' + arg + type = model.PointerType(type) + prnt(' *(%s)(p + %d) = %s;' % (type.get_c_name('*'), i*8, arg)) + prnt(' _cffi_call_python(&_cffi_externpy__%s, p);' % name) + if not isinstance(tp.result, model.VoidType): + prnt(' return *(%s)p;' % (tp.result.get_c_name('*'),)) + prnt('}') + prnt() + self._num_externpy += 1 + + def _generate_cpy_extern_python_decl(self, tp, name): + self._extern_python_decl(tp, name, 'static ') + + def _generate_cpy_dllexport_python_decl(self, tp, name): + self._extern_python_decl(tp, name, 'CFFI_DLLEXPORT ') + + def _generate_cpy_extern_python_plus_c_decl(self, tp, name): + self._extern_python_decl(tp, name, '') + + def _generate_cpy_extern_python_ctx(self, tp, name): + if self.target_is_python: + raise VerificationError( + "cannot use 'extern \"Python\"' in the ABI mode") + if tp.ellipsis: + raise NotImplementedError("a vararg function is extern \"Python\"") + type_index = self._typesdict[tp] + type_op = CffiOp(OP_EXTERN_PYTHON, type_index) + self._lsts["global"].append( + GlobalExpr(name, '&_cffi_externpy__%s' % name, type_op, name)) + + _generate_cpy_dllexport_python_ctx = \ + _generate_cpy_extern_python_plus_c_ctx = \ + _generate_cpy_extern_python_ctx + + def _print_string_literal_in_array(self, s): + prnt = self._prnt + prnt('// # NB. this is not a string because of a size limit in MSVC') + if not isinstance(s, bytes): # unicode + s = s.encode('utf-8') # -> bytes + else: + s.decode('utf-8') # got bytes, check for valid utf-8 + try: + s.decode('ascii') + except UnicodeDecodeError: + s = b'# -*- encoding: utf8 -*-\n' + s + for line in s.splitlines(True): + comment = line + if type('//') is bytes: # python2 + line = map(ord, line) # make a list of integers + else: # python3 + # type(line) is bytes, which enumerates like a list of integers + comment = ascii(comment)[1:-1] + prnt(('// ' + comment).rstrip()) + printed_line = '' + for c in line: + if len(printed_line) >= 76: + prnt(printed_line) + printed_line = '' + printed_line += '%d,' % (c,) + prnt(printed_line) + + # ---------- + # emitting the opcodes for individual types + + def _emit_bytecode_VoidType(self, tp, index): + self.cffi_types[index] = CffiOp(OP_PRIMITIVE, PRIM_VOID) + + def _emit_bytecode_PrimitiveType(self, tp, index): + prim_index = PRIMITIVE_TO_INDEX[tp.name] + self.cffi_types[index] = CffiOp(OP_PRIMITIVE, prim_index) + + def _emit_bytecode_UnknownIntegerType(self, tp, index): + s = ('_cffi_prim_int(sizeof(%s), (\n' + ' ((%s)-1) | 0 /* check that %s is an integer type */\n' + ' ) <= 0)' % (tp.name, tp.name, tp.name)) + self.cffi_types[index] = CffiOp(OP_PRIMITIVE, s) + + def _emit_bytecode_UnknownFloatType(self, tp, index): + s = ('_cffi_prim_float(sizeof(%s) *\n' + ' (((%s)1) / 2) * 2 /* integer => 0, float => 1 */\n' + ' )' % (tp.name, tp.name)) + self.cffi_types[index] = CffiOp(OP_PRIMITIVE, s) + + def _emit_bytecode_RawFunctionType(self, tp, index): + self.cffi_types[index] = CffiOp(OP_FUNCTION, self._typesdict[tp.result]) + index += 1 + for tp1 in tp.args: + realindex = self._typesdict[tp1] + if index != realindex: + if isinstance(tp1, model.PrimitiveType): + self._emit_bytecode_PrimitiveType(tp1, index) + else: + self.cffi_types[index] = CffiOp(OP_NOOP, realindex) + index += 1 + flags = int(tp.ellipsis) + if tp.abi is not None: + if tp.abi == '__stdcall': + flags |= 2 + else: + raise NotImplementedError("abi=%r" % (tp.abi,)) + self.cffi_types[index] = CffiOp(OP_FUNCTION_END, flags) + + def _emit_bytecode_PointerType(self, tp, index): + self.cffi_types[index] = CffiOp(OP_POINTER, self._typesdict[tp.totype]) + + _emit_bytecode_ConstPointerType = _emit_bytecode_PointerType + _emit_bytecode_NamedPointerType = _emit_bytecode_PointerType + + def _emit_bytecode_FunctionPtrType(self, tp, index): + raw = tp.as_raw_function() + self.cffi_types[index] = CffiOp(OP_POINTER, self._typesdict[raw]) + + def _emit_bytecode_ArrayType(self, tp, index): + item_index = self._typesdict[tp.item] + if tp.length is None: + self.cffi_types[index] = CffiOp(OP_OPEN_ARRAY, item_index) + elif tp.length == '...': + raise VerificationError( + "type %s badly placed: the '...' array length can only be " + "used on global arrays or on fields of structures" % ( + str(tp).replace('/*...*/', '...'),)) + else: + assert self.cffi_types[index + 1] == 'LEN' + self.cffi_types[index] = CffiOp(OP_ARRAY, item_index) + self.cffi_types[index + 1] = CffiOp(None, str(tp.length)) + + def _emit_bytecode_StructType(self, tp, index): + struct_index = self._struct_unions[tp] + self.cffi_types[index] = CffiOp(OP_STRUCT_UNION, struct_index) + _emit_bytecode_UnionType = _emit_bytecode_StructType + + def _emit_bytecode_EnumType(self, tp, index): + enum_index = self._enums[tp] + self.cffi_types[index] = CffiOp(OP_ENUM, enum_index) + + +if sys.version_info >= (3,): + NativeIO = io.StringIO +else: + class NativeIO(io.BytesIO): + def write(self, s): + if isinstance(s, unicode): + s = s.encode('ascii') + super(NativeIO, self).write(s) + +def _make_c_or_py_source(ffi, module_name, preamble, target_file, verbose): + if verbose: + print("generating %s" % (target_file,)) + recompiler = Recompiler(ffi, module_name, + target_is_python=(preamble is None)) + recompiler.collect_type_table() + recompiler.collect_step_tables() + f = NativeIO() + recompiler.write_source_to_f(f, preamble) + output = f.getvalue() + try: + with open(target_file, 'r') as f1: + if f1.read(len(output) + 1) != output: + raise IOError + if verbose: + print("(already up-to-date)") + return False # already up-to-date + except IOError: + tmp_file = '%s.~%d' % (target_file, os.getpid()) + with open(tmp_file, 'w') as f1: + f1.write(output) + try: + os.rename(tmp_file, target_file) + except OSError: + os.unlink(target_file) + os.rename(tmp_file, target_file) + return True + +def make_c_source(ffi, module_name, preamble, target_c_file, verbose=False): + assert preamble is not None + return _make_c_or_py_source(ffi, module_name, preamble, target_c_file, + verbose) + +def make_py_source(ffi, module_name, target_py_file, verbose=False): + return _make_c_or_py_source(ffi, module_name, None, target_py_file, + verbose) + +def _modname_to_file(outputdir, modname, extension): + parts = modname.split('.') + try: + os.makedirs(os.path.join(outputdir, *parts[:-1])) + except OSError: + pass + parts[-1] += extension + return os.path.join(outputdir, *parts), parts + + +# Aaargh. Distutils is not tested at all for the purpose of compiling +# DLLs that are not extension modules. Here are some hacks to work +# around that, in the _patch_for_*() functions... + +def _patch_meth(patchlist, cls, name, new_meth): + old = getattr(cls, name) + patchlist.append((cls, name, old)) + setattr(cls, name, new_meth) + return old + +def _unpatch_meths(patchlist): + for cls, name, old_meth in reversed(patchlist): + setattr(cls, name, old_meth) + +def _patch_for_embedding(patchlist): + if sys.platform == 'win32': + # we must not remove the manifest when building for embedding! + from distutils.msvc9compiler import MSVCCompiler + _patch_meth(patchlist, MSVCCompiler, '_remove_visual_c_ref', + lambda self, manifest_file: manifest_file) + + if sys.platform == 'darwin': + # we must not make a '-bundle', but a '-dynamiclib' instead + from distutils.ccompiler import CCompiler + def my_link_shared_object(self, *args, **kwds): + if '-bundle' in self.linker_so: + self.linker_so = list(self.linker_so) + i = self.linker_so.index('-bundle') + self.linker_so[i] = '-dynamiclib' + return old_link_shared_object(self, *args, **kwds) + old_link_shared_object = _patch_meth(patchlist, CCompiler, + 'link_shared_object', + my_link_shared_object) + +def _patch_for_target(patchlist, target): + from distutils.command.build_ext import build_ext + # if 'target' is different from '*', we need to patch some internal + # method to just return this 'target' value, instead of having it + # built from module_name + if target.endswith('.*'): + target = target[:-2] + if sys.platform == 'win32': + target += '.dll' + elif sys.platform == 'darwin': + target += '.dylib' + else: + target += '.so' + _patch_meth(patchlist, build_ext, 'get_ext_filename', + lambda self, ext_name: target) + + +def recompile(ffi, module_name, preamble, tmpdir='.', call_c_compiler=True, + c_file=None, source_extension='.c', extradir=None, + compiler_verbose=1, target=None, debug=None, **kwds): + if not isinstance(module_name, str): + module_name = module_name.encode('ascii') + if ffi._windows_unicode: + ffi._apply_windows_unicode(kwds) + if preamble is not None: + embedding = (ffi._embedding is not None) + if embedding: + ffi._apply_embedding_fix(kwds) + if c_file is None: + c_file, parts = _modname_to_file(tmpdir, module_name, + source_extension) + if extradir: + parts = [extradir] + parts + ext_c_file = os.path.join(*parts) + else: + ext_c_file = c_file + # + if target is None: + if embedding: + target = '%s.*' % module_name + else: + target = '*' + # + ext = ffiplatform.get_extension(ext_c_file, module_name, **kwds) + updated = make_c_source(ffi, module_name, preamble, c_file, + verbose=compiler_verbose) + if call_c_compiler: + patchlist = [] + cwd = os.getcwd() + try: + if embedding: + _patch_for_embedding(patchlist) + if target != '*': + _patch_for_target(patchlist, target) + if compiler_verbose: + if tmpdir == '.': + msg = 'the current directory is' + else: + msg = 'setting the current directory to' + print('%s %r' % (msg, os.path.abspath(tmpdir))) + os.chdir(tmpdir) + outputfilename = ffiplatform.compile('.', ext, + compiler_verbose, debug) + finally: + os.chdir(cwd) + _unpatch_meths(patchlist) + return outputfilename + else: + return ext, updated + else: + if c_file is None: + c_file, _ = _modname_to_file(tmpdir, module_name, '.py') + updated = make_py_source(ffi, module_name, c_file, + verbose=compiler_verbose) + if call_c_compiler: + return c_file + else: + return None, updated + diff --git a/venv/Lib/site-packages/cffi/setuptools_ext.py b/venv/Lib/site-packages/cffi/setuptools_ext.py new file mode 100644 index 000000000..8fe361487 --- /dev/null +++ b/venv/Lib/site-packages/cffi/setuptools_ext.py @@ -0,0 +1,219 @@ +import os +import sys + +try: + basestring +except NameError: + # Python 3.x + basestring = str + +def error(msg): + from distutils.errors import DistutilsSetupError + raise DistutilsSetupError(msg) + + +def execfile(filename, glob): + # We use execfile() (here rewritten for Python 3) instead of + # __import__() to load the build script. The problem with + # a normal import is that in some packages, the intermediate + # __init__.py files may already try to import the file that + # we are generating. + with open(filename) as f: + src = f.read() + src += '\n' # Python 2.6 compatibility + code = compile(src, filename, 'exec') + exec(code, glob, glob) + + +def add_cffi_module(dist, mod_spec): + from cffi.api import FFI + + if not isinstance(mod_spec, basestring): + error("argument to 'cffi_modules=...' must be a str or a list of str," + " not %r" % (type(mod_spec).__name__,)) + mod_spec = str(mod_spec) + try: + build_file_name, ffi_var_name = mod_spec.split(':') + except ValueError: + error("%r must be of the form 'path/build.py:ffi_variable'" % + (mod_spec,)) + if not os.path.exists(build_file_name): + ext = '' + rewritten = build_file_name.replace('.', '/') + '.py' + if os.path.exists(rewritten): + ext = ' (rewrite cffi_modules to [%r])' % ( + rewritten + ':' + ffi_var_name,) + error("%r does not name an existing file%s" % (build_file_name, ext)) + + mod_vars = {'__name__': '__cffi__', '__file__': build_file_name} + execfile(build_file_name, mod_vars) + + try: + ffi = mod_vars[ffi_var_name] + except KeyError: + error("%r: object %r not found in module" % (mod_spec, + ffi_var_name)) + if not isinstance(ffi, FFI): + ffi = ffi() # maybe it's a function instead of directly an ffi + if not isinstance(ffi, FFI): + error("%r is not an FFI instance (got %r)" % (mod_spec, + type(ffi).__name__)) + if not hasattr(ffi, '_assigned_source'): + error("%r: the set_source() method was not called" % (mod_spec,)) + module_name, source, source_extension, kwds = ffi._assigned_source + if ffi._windows_unicode: + kwds = kwds.copy() + ffi._apply_windows_unicode(kwds) + + if source is None: + _add_py_module(dist, ffi, module_name) + else: + _add_c_module(dist, ffi, module_name, source, source_extension, kwds) + +def _set_py_limited_api(Extension, kwds): + """ + Add py_limited_api to kwds if setuptools >= 26 is in use. + Do not alter the setting if it already exists. + Setuptools takes care of ignoring the flag on Python 2 and PyPy. + + CPython itself should ignore the flag in a debugging version + (by not listing .abi3.so in the extensions it supports), but + it doesn't so far, creating troubles. That's why we check + for "not hasattr(sys, 'gettotalrefcount')" (the 2.7 compatible equivalent + of 'd' not in sys.abiflags). (http://bugs.python.org/issue28401) + + On Windows, with CPython <= 3.4, it's better not to use py_limited_api + because virtualenv *still* doesn't copy PYTHON3.DLL on these versions. + Recently (2020) we started shipping only >= 3.5 wheels, though. So + we'll give it another try and set py_limited_api on Windows >= 3.5. + """ + from cffi import recompiler + + if ('py_limited_api' not in kwds and not hasattr(sys, 'gettotalrefcount') + and recompiler.USE_LIMITED_API): + import setuptools + try: + setuptools_major_version = int(setuptools.__version__.partition('.')[0]) + if setuptools_major_version >= 26: + kwds['py_limited_api'] = True + except ValueError: # certain development versions of setuptools + # If we don't know the version number of setuptools, we + # try to set 'py_limited_api' anyway. At worst, we get a + # warning. + kwds['py_limited_api'] = True + return kwds + +def _add_c_module(dist, ffi, module_name, source, source_extension, kwds): + from distutils.core import Extension + # We are a setuptools extension. Need this build_ext for py_limited_api. + from setuptools.command.build_ext import build_ext + from distutils.dir_util import mkpath + from distutils import log + from cffi import recompiler + + allsources = ['$PLACEHOLDER'] + allsources.extend(kwds.pop('sources', [])) + kwds = _set_py_limited_api(Extension, kwds) + ext = Extension(name=module_name, sources=allsources, **kwds) + + def make_mod(tmpdir, pre_run=None): + c_file = os.path.join(tmpdir, module_name + source_extension) + log.info("generating cffi module %r" % c_file) + mkpath(tmpdir) + # a setuptools-only, API-only hook: called with the "ext" and "ffi" + # arguments just before we turn the ffi into C code. To use it, + # subclass the 'distutils.command.build_ext.build_ext' class and + # add a method 'def pre_run(self, ext, ffi)'. + if pre_run is not None: + pre_run(ext, ffi) + updated = recompiler.make_c_source(ffi, module_name, source, c_file) + if not updated: + log.info("already up-to-date") + return c_file + + if dist.ext_modules is None: + dist.ext_modules = [] + dist.ext_modules.append(ext) + + base_class = dist.cmdclass.get('build_ext', build_ext) + class build_ext_make_mod(base_class): + def run(self): + if ext.sources[0] == '$PLACEHOLDER': + pre_run = getattr(self, 'pre_run', None) + ext.sources[0] = make_mod(self.build_temp, pre_run) + base_class.run(self) + dist.cmdclass['build_ext'] = build_ext_make_mod + # NB. multiple runs here will create multiple 'build_ext_make_mod' + # classes. Even in this case the 'build_ext' command should be + # run once; but just in case, the logic above does nothing if + # called again. + + +def _add_py_module(dist, ffi, module_name): + from distutils.dir_util import mkpath + from setuptools.command.build_py import build_py + from setuptools.command.build_ext import build_ext + from distutils import log + from cffi import recompiler + + def generate_mod(py_file): + log.info("generating cffi module %r" % py_file) + mkpath(os.path.dirname(py_file)) + updated = recompiler.make_py_source(ffi, module_name, py_file) + if not updated: + log.info("already up-to-date") + + base_class = dist.cmdclass.get('build_py', build_py) + class build_py_make_mod(base_class): + def run(self): + base_class.run(self) + module_path = module_name.split('.') + module_path[-1] += '.py' + generate_mod(os.path.join(self.build_lib, *module_path)) + def get_source_files(self): + # This is called from 'setup.py sdist' only. Exclude + # the generate .py module in this case. + saved_py_modules = self.py_modules + try: + if saved_py_modules: + self.py_modules = [m for m in saved_py_modules + if m != module_name] + return base_class.get_source_files(self) + finally: + self.py_modules = saved_py_modules + dist.cmdclass['build_py'] = build_py_make_mod + + # distutils and setuptools have no notion I could find of a + # generated python module. If we don't add module_name to + # dist.py_modules, then things mostly work but there are some + # combination of options (--root and --record) that will miss + # the module. So we add it here, which gives a few apparently + # harmless warnings about not finding the file outside the + # build directory. + # Then we need to hack more in get_source_files(); see above. + if dist.py_modules is None: + dist.py_modules = [] + dist.py_modules.append(module_name) + + # the following is only for "build_ext -i" + base_class_2 = dist.cmdclass.get('build_ext', build_ext) + class build_ext_make_mod(base_class_2): + def run(self): + base_class_2.run(self) + if self.inplace: + # from get_ext_fullpath() in distutils/command/build_ext.py + module_path = module_name.split('.') + package = '.'.join(module_path[:-1]) + build_py = self.get_finalized_command('build_py') + package_dir = build_py.get_package_dir(package) + file_name = module_path[-1] + '.py' + generate_mod(os.path.join(package_dir, file_name)) + dist.cmdclass['build_ext'] = build_ext_make_mod + +def cffi_modules(dist, attr, value): + assert attr == 'cffi_modules' + if isinstance(value, basestring): + value = [value] + + for cffi_module in value: + add_cffi_module(dist, cffi_module) diff --git a/venv/Lib/site-packages/cffi/vengine_cpy.py b/venv/Lib/site-packages/cffi/vengine_cpy.py new file mode 100644 index 000000000..6de0df0ea --- /dev/null +++ b/venv/Lib/site-packages/cffi/vengine_cpy.py @@ -0,0 +1,1076 @@ +# +# DEPRECATED: implementation for ffi.verify() +# +import sys, imp +from . import model +from .error import VerificationError + + +class VCPythonEngine(object): + _class_key = 'x' + _gen_python_module = True + + def __init__(self, verifier): + self.verifier = verifier + self.ffi = verifier.ffi + self._struct_pending_verification = {} + self._types_of_builtin_functions = {} + + def patch_extension_kwds(self, kwds): + pass + + def find_module(self, module_name, path, so_suffixes): + try: + f, filename, descr = imp.find_module(module_name, path) + except ImportError: + return None + if f is not None: + f.close() + # Note that after a setuptools installation, there are both .py + # and .so files with the same basename. The code here relies on + # imp.find_module() locating the .so in priority. + if descr[0] not in so_suffixes: + return None + return filename + + def collect_types(self): + self._typesdict = {} + self._generate("collecttype") + + def _prnt(self, what=''): + self._f.write(what + '\n') + + def _gettypenum(self, type): + # a KeyError here is a bug. please report it! :-) + return self._typesdict[type] + + def _do_collect_type(self, tp): + if ((not isinstance(tp, model.PrimitiveType) + or tp.name == 'long double') + and tp not in self._typesdict): + num = len(self._typesdict) + self._typesdict[tp] = num + + def write_source_to_f(self): + self.collect_types() + # + # The new module will have a _cffi_setup() function that receives + # objects from the ffi world, and that calls some setup code in + # the module. This setup code is split in several independent + # functions, e.g. one per constant. The functions are "chained" + # by ending in a tail call to each other. + # + # This is further split in two chained lists, depending on if we + # can do it at import-time or if we must wait for _cffi_setup() to + # provide us with the objects. This is needed because we + # need the values of the enum constants in order to build the + # that we may have to pass to _cffi_setup(). + # + # The following two 'chained_list_constants' items contains + # the head of these two chained lists, as a string that gives the + # call to do, if any. + self._chained_list_constants = ['((void)lib,0)', '((void)lib,0)'] + # + prnt = self._prnt + # first paste some standard set of lines that are mostly '#define' + prnt(cffimod_header) + prnt() + # then paste the C source given by the user, verbatim. + prnt(self.verifier.preamble) + prnt() + # + # call generate_cpy_xxx_decl(), for every xxx found from + # ffi._parser._declarations. This generates all the functions. + self._generate("decl") + # + # implement the function _cffi_setup_custom() as calling the + # head of the chained list. + self._generate_setup_custom() + prnt() + # + # produce the method table, including the entries for the + # generated Python->C function wrappers, which are done + # by generate_cpy_function_method(). + prnt('static PyMethodDef _cffi_methods[] = {') + self._generate("method") + prnt(' {"_cffi_setup", _cffi_setup, METH_VARARGS, NULL},') + prnt(' {NULL, NULL, 0, NULL} /* Sentinel */') + prnt('};') + prnt() + # + # standard init. + modname = self.verifier.get_module_name() + constants = self._chained_list_constants[False] + prnt('#if PY_MAJOR_VERSION >= 3') + prnt() + prnt('static struct PyModuleDef _cffi_module_def = {') + prnt(' PyModuleDef_HEAD_INIT,') + prnt(' "%s",' % modname) + prnt(' NULL,') + prnt(' -1,') + prnt(' _cffi_methods,') + prnt(' NULL, NULL, NULL, NULL') + prnt('};') + prnt() + prnt('PyMODINIT_FUNC') + prnt('PyInit_%s(void)' % modname) + prnt('{') + prnt(' PyObject *lib;') + prnt(' lib = PyModule_Create(&_cffi_module_def);') + prnt(' if (lib == NULL)') + prnt(' return NULL;') + prnt(' if (%s < 0 || _cffi_init() < 0) {' % (constants,)) + prnt(' Py_DECREF(lib);') + prnt(' return NULL;') + prnt(' }') + prnt(' return lib;') + prnt('}') + prnt() + prnt('#else') + prnt() + prnt('PyMODINIT_FUNC') + prnt('init%s(void)' % modname) + prnt('{') + prnt(' PyObject *lib;') + prnt(' lib = Py_InitModule("%s", _cffi_methods);' % modname) + prnt(' if (lib == NULL)') + prnt(' return;') + prnt(' if (%s < 0 || _cffi_init() < 0)' % (constants,)) + prnt(' return;') + prnt(' return;') + prnt('}') + prnt() + prnt('#endif') + + def load_library(self, flags=None): + # XXX review all usages of 'self' here! + # import it as a new extension module + imp.acquire_lock() + try: + if hasattr(sys, "getdlopenflags"): + previous_flags = sys.getdlopenflags() + try: + if hasattr(sys, "setdlopenflags") and flags is not None: + sys.setdlopenflags(flags) + module = imp.load_dynamic(self.verifier.get_module_name(), + self.verifier.modulefilename) + except ImportError as e: + error = "importing %r: %s" % (self.verifier.modulefilename, e) + raise VerificationError(error) + finally: + if hasattr(sys, "setdlopenflags"): + sys.setdlopenflags(previous_flags) + finally: + imp.release_lock() + # + # call loading_cpy_struct() to get the struct layout inferred by + # the C compiler + self._load(module, 'loading') + # + # the C code will need the objects. Collect them in + # order in a list. + revmapping = dict([(value, key) + for (key, value) in self._typesdict.items()]) + lst = [revmapping[i] for i in range(len(revmapping))] + lst = list(map(self.ffi._get_cached_btype, lst)) + # + # build the FFILibrary class and instance and call _cffi_setup(). + # this will set up some fields like '_cffi_types', and only then + # it will invoke the chained list of functions that will really + # build (notably) the constant objects, as if they are + # pointers, and store them as attributes on the 'library' object. + class FFILibrary(object): + _cffi_python_module = module + _cffi_ffi = self.ffi + _cffi_dir = [] + def __dir__(self): + return FFILibrary._cffi_dir + list(self.__dict__) + library = FFILibrary() + if module._cffi_setup(lst, VerificationError, library): + import warnings + warnings.warn("reimporting %r might overwrite older definitions" + % (self.verifier.get_module_name())) + # + # finally, call the loaded_cpy_xxx() functions. This will perform + # the final adjustments, like copying the Python->C wrapper + # functions from the module to the 'library' object, and setting + # up the FFILibrary class with properties for the global C variables. + self._load(module, 'loaded', library=library) + module._cffi_original_ffi = self.ffi + module._cffi_types_of_builtin_funcs = self._types_of_builtin_functions + return library + + def _get_declarations(self): + lst = [(key, tp) for (key, (tp, qual)) in + self.ffi._parser._declarations.items()] + lst.sort() + return lst + + def _generate(self, step_name): + for name, tp in self._get_declarations(): + kind, realname = name.split(' ', 1) + try: + method = getattr(self, '_generate_cpy_%s_%s' % (kind, + step_name)) + except AttributeError: + raise VerificationError( + "not implemented in verify(): %r" % name) + try: + method(tp, realname) + except Exception as e: + model.attach_exception_info(e, name) + raise + + def _load(self, module, step_name, **kwds): + for name, tp in self._get_declarations(): + kind, realname = name.split(' ', 1) + method = getattr(self, '_%s_cpy_%s' % (step_name, kind)) + try: + method(tp, realname, module, **kwds) + except Exception as e: + model.attach_exception_info(e, name) + raise + + def _generate_nothing(self, tp, name): + pass + + def _loaded_noop(self, tp, name, module, **kwds): + pass + + # ---------- + + def _convert_funcarg_to_c(self, tp, fromvar, tovar, errcode): + extraarg = '' + if isinstance(tp, model.PrimitiveType): + if tp.is_integer_type() and tp.name != '_Bool': + converter = '_cffi_to_c_int' + extraarg = ', %s' % tp.name + else: + converter = '(%s)_cffi_to_c_%s' % (tp.get_c_name(''), + tp.name.replace(' ', '_')) + errvalue = '-1' + # + elif isinstance(tp, model.PointerType): + self._convert_funcarg_to_c_ptr_or_array(tp, fromvar, + tovar, errcode) + return + # + elif isinstance(tp, (model.StructOrUnion, model.EnumType)): + # a struct (not a struct pointer) as a function argument + self._prnt(' if (_cffi_to_c((char *)&%s, _cffi_type(%d), %s) < 0)' + % (tovar, self._gettypenum(tp), fromvar)) + self._prnt(' %s;' % errcode) + return + # + elif isinstance(tp, model.FunctionPtrType): + converter = '(%s)_cffi_to_c_pointer' % tp.get_c_name('') + extraarg = ', _cffi_type(%d)' % self._gettypenum(tp) + errvalue = 'NULL' + # + else: + raise NotImplementedError(tp) + # + self._prnt(' %s = %s(%s%s);' % (tovar, converter, fromvar, extraarg)) + self._prnt(' if (%s == (%s)%s && PyErr_Occurred())' % ( + tovar, tp.get_c_name(''), errvalue)) + self._prnt(' %s;' % errcode) + + def _extra_local_variables(self, tp, localvars, freelines): + if isinstance(tp, model.PointerType): + localvars.add('Py_ssize_t datasize') + localvars.add('struct _cffi_freeme_s *large_args_free = NULL') + freelines.add('if (large_args_free != NULL)' + ' _cffi_free_array_arguments(large_args_free);') + + def _convert_funcarg_to_c_ptr_or_array(self, tp, fromvar, tovar, errcode): + self._prnt(' datasize = _cffi_prepare_pointer_call_argument(') + self._prnt(' _cffi_type(%d), %s, (char **)&%s);' % ( + self._gettypenum(tp), fromvar, tovar)) + self._prnt(' if (datasize != 0) {') + self._prnt(' %s = ((size_t)datasize) <= 640 ? ' + 'alloca((size_t)datasize) : NULL;' % (tovar,)) + self._prnt(' if (_cffi_convert_array_argument(_cffi_type(%d), %s, ' + '(char **)&%s,' % (self._gettypenum(tp), fromvar, tovar)) + self._prnt(' datasize, &large_args_free) < 0)') + self._prnt(' %s;' % errcode) + self._prnt(' }') + + def _convert_expr_from_c(self, tp, var, context): + if isinstance(tp, model.PrimitiveType): + if tp.is_integer_type() and tp.name != '_Bool': + return '_cffi_from_c_int(%s, %s)' % (var, tp.name) + elif tp.name != 'long double': + return '_cffi_from_c_%s(%s)' % (tp.name.replace(' ', '_'), var) + else: + return '_cffi_from_c_deref((char *)&%s, _cffi_type(%d))' % ( + var, self._gettypenum(tp)) + elif isinstance(tp, (model.PointerType, model.FunctionPtrType)): + return '_cffi_from_c_pointer((char *)%s, _cffi_type(%d))' % ( + var, self._gettypenum(tp)) + elif isinstance(tp, model.ArrayType): + return '_cffi_from_c_pointer((char *)%s, _cffi_type(%d))' % ( + var, self._gettypenum(model.PointerType(tp.item))) + elif isinstance(tp, model.StructOrUnion): + if tp.fldnames is None: + raise TypeError("'%s' is used as %s, but is opaque" % ( + tp._get_c_name(), context)) + return '_cffi_from_c_struct((char *)&%s, _cffi_type(%d))' % ( + var, self._gettypenum(tp)) + elif isinstance(tp, model.EnumType): + return '_cffi_from_c_deref((char *)&%s, _cffi_type(%d))' % ( + var, self._gettypenum(tp)) + else: + raise NotImplementedError(tp) + + # ---------- + # typedefs: generates no code so far + + _generate_cpy_typedef_collecttype = _generate_nothing + _generate_cpy_typedef_decl = _generate_nothing + _generate_cpy_typedef_method = _generate_nothing + _loading_cpy_typedef = _loaded_noop + _loaded_cpy_typedef = _loaded_noop + + # ---------- + # function declarations + + def _generate_cpy_function_collecttype(self, tp, name): + assert isinstance(tp, model.FunctionPtrType) + if tp.ellipsis: + self._do_collect_type(tp) + else: + # don't call _do_collect_type(tp) in this common case, + # otherwise test_autofilled_struct_as_argument fails + for type in tp.args: + self._do_collect_type(type) + self._do_collect_type(tp.result) + + def _generate_cpy_function_decl(self, tp, name): + assert isinstance(tp, model.FunctionPtrType) + if tp.ellipsis: + # cannot support vararg functions better than this: check for its + # exact type (including the fixed arguments), and build it as a + # constant function pointer (no CPython wrapper) + self._generate_cpy_const(False, name, tp) + return + prnt = self._prnt + numargs = len(tp.args) + if numargs == 0: + argname = 'noarg' + elif numargs == 1: + argname = 'arg0' + else: + argname = 'args' + prnt('static PyObject *') + prnt('_cffi_f_%s(PyObject *self, PyObject *%s)' % (name, argname)) + prnt('{') + # + context = 'argument of %s' % name + for i, type in enumerate(tp.args): + prnt(' %s;' % type.get_c_name(' x%d' % i, context)) + # + localvars = set() + freelines = set() + for type in tp.args: + self._extra_local_variables(type, localvars, freelines) + for decl in sorted(localvars): + prnt(' %s;' % (decl,)) + # + if not isinstance(tp.result, model.VoidType): + result_code = 'result = ' + context = 'result of %s' % name + prnt(' %s;' % tp.result.get_c_name(' result', context)) + prnt(' PyObject *pyresult;') + else: + result_code = '' + # + if len(tp.args) > 1: + rng = range(len(tp.args)) + for i in rng: + prnt(' PyObject *arg%d;' % i) + prnt() + prnt(' if (!PyArg_ParseTuple(args, "%s:%s", %s))' % ( + 'O' * numargs, name, ', '.join(['&arg%d' % i for i in rng]))) + prnt(' return NULL;') + prnt() + # + for i, type in enumerate(tp.args): + self._convert_funcarg_to_c(type, 'arg%d' % i, 'x%d' % i, + 'return NULL') + prnt() + # + prnt(' Py_BEGIN_ALLOW_THREADS') + prnt(' _cffi_restore_errno();') + prnt(' { %s%s(%s); }' % ( + result_code, name, + ', '.join(['x%d' % i for i in range(len(tp.args))]))) + prnt(' _cffi_save_errno();') + prnt(' Py_END_ALLOW_THREADS') + prnt() + # + prnt(' (void)self; /* unused */') + if numargs == 0: + prnt(' (void)noarg; /* unused */') + if result_code: + prnt(' pyresult = %s;' % + self._convert_expr_from_c(tp.result, 'result', 'result type')) + for freeline in freelines: + prnt(' ' + freeline) + prnt(' return pyresult;') + else: + for freeline in freelines: + prnt(' ' + freeline) + prnt(' Py_INCREF(Py_None);') + prnt(' return Py_None;') + prnt('}') + prnt() + + def _generate_cpy_function_method(self, tp, name): + if tp.ellipsis: + return + numargs = len(tp.args) + if numargs == 0: + meth = 'METH_NOARGS' + elif numargs == 1: + meth = 'METH_O' + else: + meth = 'METH_VARARGS' + self._prnt(' {"%s", _cffi_f_%s, %s, NULL},' % (name, name, meth)) + + _loading_cpy_function = _loaded_noop + + def _loaded_cpy_function(self, tp, name, module, library): + if tp.ellipsis: + return + func = getattr(module, name) + setattr(library, name, func) + self._types_of_builtin_functions[func] = tp + + # ---------- + # named structs + + _generate_cpy_struct_collecttype = _generate_nothing + def _generate_cpy_struct_decl(self, tp, name): + assert name == tp.name + self._generate_struct_or_union_decl(tp, 'struct', name) + def _generate_cpy_struct_method(self, tp, name): + self._generate_struct_or_union_method(tp, 'struct', name) + def _loading_cpy_struct(self, tp, name, module): + self._loading_struct_or_union(tp, 'struct', name, module) + def _loaded_cpy_struct(self, tp, name, module, **kwds): + self._loaded_struct_or_union(tp) + + _generate_cpy_union_collecttype = _generate_nothing + def _generate_cpy_union_decl(self, tp, name): + assert name == tp.name + self._generate_struct_or_union_decl(tp, 'union', name) + def _generate_cpy_union_method(self, tp, name): + self._generate_struct_or_union_method(tp, 'union', name) + def _loading_cpy_union(self, tp, name, module): + self._loading_struct_or_union(tp, 'union', name, module) + def _loaded_cpy_union(self, tp, name, module, **kwds): + self._loaded_struct_or_union(tp) + + def _generate_struct_or_union_decl(self, tp, prefix, name): + if tp.fldnames is None: + return # nothing to do with opaque structs + checkfuncname = '_cffi_check_%s_%s' % (prefix, name) + layoutfuncname = '_cffi_layout_%s_%s' % (prefix, name) + cname = ('%s %s' % (prefix, name)).strip() + # + prnt = self._prnt + prnt('static void %s(%s *p)' % (checkfuncname, cname)) + prnt('{') + prnt(' /* only to generate compile-time warnings or errors */') + prnt(' (void)p;') + for fname, ftype, fbitsize, fqual in tp.enumfields(): + if (isinstance(ftype, model.PrimitiveType) + and ftype.is_integer_type()) or fbitsize >= 0: + # accept all integers, but complain on float or double + prnt(' (void)((p->%s) << 1);' % fname) + else: + # only accept exactly the type declared. + try: + prnt(' { %s = &p->%s; (void)tmp; }' % ( + ftype.get_c_name('*tmp', 'field %r'%fname, quals=fqual), + fname)) + except VerificationError as e: + prnt(' /* %s */' % str(e)) # cannot verify it, ignore + prnt('}') + prnt('static PyObject *') + prnt('%s(PyObject *self, PyObject *noarg)' % (layoutfuncname,)) + prnt('{') + prnt(' struct _cffi_aligncheck { char x; %s y; };' % cname) + prnt(' static Py_ssize_t nums[] = {') + prnt(' sizeof(%s),' % cname) + prnt(' offsetof(struct _cffi_aligncheck, y),') + for fname, ftype, fbitsize, fqual in tp.enumfields(): + if fbitsize >= 0: + continue # xxx ignore fbitsize for now + prnt(' offsetof(%s, %s),' % (cname, fname)) + if isinstance(ftype, model.ArrayType) and ftype.length is None: + prnt(' 0, /* %s */' % ftype._get_c_name()) + else: + prnt(' sizeof(((%s *)0)->%s),' % (cname, fname)) + prnt(' -1') + prnt(' };') + prnt(' (void)self; /* unused */') + prnt(' (void)noarg; /* unused */') + prnt(' return _cffi_get_struct_layout(nums);') + prnt(' /* the next line is not executed, but compiled */') + prnt(' %s(0);' % (checkfuncname,)) + prnt('}') + prnt() + + def _generate_struct_or_union_method(self, tp, prefix, name): + if tp.fldnames is None: + return # nothing to do with opaque structs + layoutfuncname = '_cffi_layout_%s_%s' % (prefix, name) + self._prnt(' {"%s", %s, METH_NOARGS, NULL},' % (layoutfuncname, + layoutfuncname)) + + def _loading_struct_or_union(self, tp, prefix, name, module): + if tp.fldnames is None: + return # nothing to do with opaque structs + layoutfuncname = '_cffi_layout_%s_%s' % (prefix, name) + # + function = getattr(module, layoutfuncname) + layout = function() + if isinstance(tp, model.StructOrUnion) and tp.partial: + # use the function()'s sizes and offsets to guide the + # layout of the struct + totalsize = layout[0] + totalalignment = layout[1] + fieldofs = layout[2::2] + fieldsize = layout[3::2] + tp.force_flatten() + assert len(fieldofs) == len(fieldsize) == len(tp.fldnames) + tp.fixedlayout = fieldofs, fieldsize, totalsize, totalalignment + else: + cname = ('%s %s' % (prefix, name)).strip() + self._struct_pending_verification[tp] = layout, cname + + def _loaded_struct_or_union(self, tp): + if tp.fldnames is None: + return # nothing to do with opaque structs + self.ffi._get_cached_btype(tp) # force 'fixedlayout' to be considered + + if tp in self._struct_pending_verification: + # check that the layout sizes and offsets match the real ones + def check(realvalue, expectedvalue, msg): + if realvalue != expectedvalue: + raise VerificationError( + "%s (we have %d, but C compiler says %d)" + % (msg, expectedvalue, realvalue)) + ffi = self.ffi + BStruct = ffi._get_cached_btype(tp) + layout, cname = self._struct_pending_verification.pop(tp) + check(layout[0], ffi.sizeof(BStruct), "wrong total size") + check(layout[1], ffi.alignof(BStruct), "wrong total alignment") + i = 2 + for fname, ftype, fbitsize, fqual in tp.enumfields(): + if fbitsize >= 0: + continue # xxx ignore fbitsize for now + check(layout[i], ffi.offsetof(BStruct, fname), + "wrong offset for field %r" % (fname,)) + if layout[i+1] != 0: + BField = ffi._get_cached_btype(ftype) + check(layout[i+1], ffi.sizeof(BField), + "wrong size for field %r" % (fname,)) + i += 2 + assert i == len(layout) + + # ---------- + # 'anonymous' declarations. These are produced for anonymous structs + # or unions; the 'name' is obtained by a typedef. + + _generate_cpy_anonymous_collecttype = _generate_nothing + + def _generate_cpy_anonymous_decl(self, tp, name): + if isinstance(tp, model.EnumType): + self._generate_cpy_enum_decl(tp, name, '') + else: + self._generate_struct_or_union_decl(tp, '', name) + + def _generate_cpy_anonymous_method(self, tp, name): + if not isinstance(tp, model.EnumType): + self._generate_struct_or_union_method(tp, '', name) + + def _loading_cpy_anonymous(self, tp, name, module): + if isinstance(tp, model.EnumType): + self._loading_cpy_enum(tp, name, module) + else: + self._loading_struct_or_union(tp, '', name, module) + + def _loaded_cpy_anonymous(self, tp, name, module, **kwds): + if isinstance(tp, model.EnumType): + self._loaded_cpy_enum(tp, name, module, **kwds) + else: + self._loaded_struct_or_union(tp) + + # ---------- + # constants, likely declared with '#define' + + def _generate_cpy_const(self, is_int, name, tp=None, category='const', + vartp=None, delayed=True, size_too=False, + check_value=None): + prnt = self._prnt + funcname = '_cffi_%s_%s' % (category, name) + prnt('static int %s(PyObject *lib)' % funcname) + prnt('{') + prnt(' PyObject *o;') + prnt(' int res;') + if not is_int: + prnt(' %s;' % (vartp or tp).get_c_name(' i', name)) + else: + assert category == 'const' + # + if check_value is not None: + self._check_int_constant_value(name, check_value) + # + if not is_int: + if category == 'var': + realexpr = '&' + name + else: + realexpr = name + prnt(' i = (%s);' % (realexpr,)) + prnt(' o = %s;' % (self._convert_expr_from_c(tp, 'i', + 'variable type'),)) + assert delayed + else: + prnt(' o = _cffi_from_c_int_const(%s);' % name) + prnt(' if (o == NULL)') + prnt(' return -1;') + if size_too: + prnt(' {') + prnt(' PyObject *o1 = o;') + prnt(' o = Py_BuildValue("On", o1, (Py_ssize_t)sizeof(%s));' + % (name,)) + prnt(' Py_DECREF(o1);') + prnt(' if (o == NULL)') + prnt(' return -1;') + prnt(' }') + prnt(' res = PyObject_SetAttrString(lib, "%s", o);' % name) + prnt(' Py_DECREF(o);') + prnt(' if (res < 0)') + prnt(' return -1;') + prnt(' return %s;' % self._chained_list_constants[delayed]) + self._chained_list_constants[delayed] = funcname + '(lib)' + prnt('}') + prnt() + + def _generate_cpy_constant_collecttype(self, tp, name): + is_int = isinstance(tp, model.PrimitiveType) and tp.is_integer_type() + if not is_int: + self._do_collect_type(tp) + + def _generate_cpy_constant_decl(self, tp, name): + is_int = isinstance(tp, model.PrimitiveType) and tp.is_integer_type() + self._generate_cpy_const(is_int, name, tp) + + _generate_cpy_constant_method = _generate_nothing + _loading_cpy_constant = _loaded_noop + _loaded_cpy_constant = _loaded_noop + + # ---------- + # enums + + def _check_int_constant_value(self, name, value, err_prefix=''): + prnt = self._prnt + if value <= 0: + prnt(' if ((%s) > 0 || (long)(%s) != %dL) {' % ( + name, name, value)) + else: + prnt(' if ((%s) <= 0 || (unsigned long)(%s) != %dUL) {' % ( + name, name, value)) + prnt(' char buf[64];') + prnt(' if ((%s) <= 0)' % name) + prnt(' snprintf(buf, 63, "%%ld", (long)(%s));' % name) + prnt(' else') + prnt(' snprintf(buf, 63, "%%lu", (unsigned long)(%s));' % + name) + prnt(' PyErr_Format(_cffi_VerificationError,') + prnt(' "%s%s has the real value %s, not %s",') + prnt(' "%s", "%s", buf, "%d");' % ( + err_prefix, name, value)) + prnt(' return -1;') + prnt(' }') + + def _enum_funcname(self, prefix, name): + # "$enum_$1" => "___D_enum____D_1" + name = name.replace('$', '___D_') + return '_cffi_e_%s_%s' % (prefix, name) + + def _generate_cpy_enum_decl(self, tp, name, prefix='enum'): + if tp.partial: + for enumerator in tp.enumerators: + self._generate_cpy_const(True, enumerator, delayed=False) + return + # + funcname = self._enum_funcname(prefix, name) + prnt = self._prnt + prnt('static int %s(PyObject *lib)' % funcname) + prnt('{') + for enumerator, enumvalue in zip(tp.enumerators, tp.enumvalues): + self._check_int_constant_value(enumerator, enumvalue, + "enum %s: " % name) + prnt(' return %s;' % self._chained_list_constants[True]) + self._chained_list_constants[True] = funcname + '(lib)' + prnt('}') + prnt() + + _generate_cpy_enum_collecttype = _generate_nothing + _generate_cpy_enum_method = _generate_nothing + + def _loading_cpy_enum(self, tp, name, module): + if tp.partial: + enumvalues = [getattr(module, enumerator) + for enumerator in tp.enumerators] + tp.enumvalues = tuple(enumvalues) + tp.partial_resolved = True + + def _loaded_cpy_enum(self, tp, name, module, library): + for enumerator, enumvalue in zip(tp.enumerators, tp.enumvalues): + setattr(library, enumerator, enumvalue) + + # ---------- + # macros: for now only for integers + + def _generate_cpy_macro_decl(self, tp, name): + if tp == '...': + check_value = None + else: + check_value = tp # an integer + self._generate_cpy_const(True, name, check_value=check_value) + + _generate_cpy_macro_collecttype = _generate_nothing + _generate_cpy_macro_method = _generate_nothing + _loading_cpy_macro = _loaded_noop + _loaded_cpy_macro = _loaded_noop + + # ---------- + # global variables + + def _generate_cpy_variable_collecttype(self, tp, name): + if isinstance(tp, model.ArrayType): + tp_ptr = model.PointerType(tp.item) + else: + tp_ptr = model.PointerType(tp) + self._do_collect_type(tp_ptr) + + def _generate_cpy_variable_decl(self, tp, name): + if isinstance(tp, model.ArrayType): + tp_ptr = model.PointerType(tp.item) + self._generate_cpy_const(False, name, tp, vartp=tp_ptr, + size_too = tp.length_is_unknown()) + else: + tp_ptr = model.PointerType(tp) + self._generate_cpy_const(False, name, tp_ptr, category='var') + + _generate_cpy_variable_method = _generate_nothing + _loading_cpy_variable = _loaded_noop + + def _loaded_cpy_variable(self, tp, name, module, library): + value = getattr(library, name) + if isinstance(tp, model.ArrayType): # int a[5] is "constant" in the + # sense that "a=..." is forbidden + if tp.length_is_unknown(): + assert isinstance(value, tuple) + (value, size) = value + BItemType = self.ffi._get_cached_btype(tp.item) + length, rest = divmod(size, self.ffi.sizeof(BItemType)) + if rest != 0: + raise VerificationError( + "bad size: %r does not seem to be an array of %s" % + (name, tp.item)) + tp = tp.resolve_length(length) + # 'value' is a which we have to replace with + # a if the N is actually known + if tp.length is not None: + BArray = self.ffi._get_cached_btype(tp) + value = self.ffi.cast(BArray, value) + setattr(library, name, value) + return + # remove ptr= from the library instance, and replace + # it by a property on the class, which reads/writes into ptr[0]. + ptr = value + delattr(library, name) + def getter(library): + return ptr[0] + def setter(library, value): + ptr[0] = value + setattr(type(library), name, property(getter, setter)) + type(library)._cffi_dir.append(name) + + # ---------- + + def _generate_setup_custom(self): + prnt = self._prnt + prnt('static int _cffi_setup_custom(PyObject *lib)') + prnt('{') + prnt(' return %s;' % self._chained_list_constants[True]) + prnt('}') + +cffimod_header = r''' +#include +#include + +/* this block of #ifs should be kept exactly identical between + c/_cffi_backend.c, cffi/vengine_cpy.py, cffi/vengine_gen.py + and cffi/_cffi_include.h */ +#if defined(_MSC_VER) +# include /* for alloca() */ +# if _MSC_VER < 1600 /* MSVC < 2010 */ + typedef __int8 int8_t; + typedef __int16 int16_t; + typedef __int32 int32_t; + typedef __int64 int64_t; + typedef unsigned __int8 uint8_t; + typedef unsigned __int16 uint16_t; + typedef unsigned __int32 uint32_t; + typedef unsigned __int64 uint64_t; + typedef __int8 int_least8_t; + typedef __int16 int_least16_t; + typedef __int32 int_least32_t; + typedef __int64 int_least64_t; + typedef unsigned __int8 uint_least8_t; + typedef unsigned __int16 uint_least16_t; + typedef unsigned __int32 uint_least32_t; + typedef unsigned __int64 uint_least64_t; + typedef __int8 int_fast8_t; + typedef __int16 int_fast16_t; + typedef __int32 int_fast32_t; + typedef __int64 int_fast64_t; + typedef unsigned __int8 uint_fast8_t; + typedef unsigned __int16 uint_fast16_t; + typedef unsigned __int32 uint_fast32_t; + typedef unsigned __int64 uint_fast64_t; + typedef __int64 intmax_t; + typedef unsigned __int64 uintmax_t; +# else +# include +# endif +# if _MSC_VER < 1800 /* MSVC < 2013 */ +# ifndef __cplusplus + typedef unsigned char _Bool; +# endif +# endif +#else +# include +# if (defined (__SVR4) && defined (__sun)) || defined(_AIX) || defined(__hpux) +# include +# endif +#endif + +#if PY_MAJOR_VERSION < 3 +# undef PyCapsule_CheckExact +# undef PyCapsule_GetPointer +# define PyCapsule_CheckExact(capsule) (PyCObject_Check(capsule)) +# define PyCapsule_GetPointer(capsule, name) \ + (PyCObject_AsVoidPtr(capsule)) +#endif + +#if PY_MAJOR_VERSION >= 3 +# define PyInt_FromLong PyLong_FromLong +#endif + +#define _cffi_from_c_double PyFloat_FromDouble +#define _cffi_from_c_float PyFloat_FromDouble +#define _cffi_from_c_long PyInt_FromLong +#define _cffi_from_c_ulong PyLong_FromUnsignedLong +#define _cffi_from_c_longlong PyLong_FromLongLong +#define _cffi_from_c_ulonglong PyLong_FromUnsignedLongLong +#define _cffi_from_c__Bool PyBool_FromLong + +#define _cffi_to_c_double PyFloat_AsDouble +#define _cffi_to_c_float PyFloat_AsDouble + +#define _cffi_from_c_int_const(x) \ + (((x) > 0) ? \ + ((unsigned long long)(x) <= (unsigned long long)LONG_MAX) ? \ + PyInt_FromLong((long)(x)) : \ + PyLong_FromUnsignedLongLong((unsigned long long)(x)) : \ + ((long long)(x) >= (long long)LONG_MIN) ? \ + PyInt_FromLong((long)(x)) : \ + PyLong_FromLongLong((long long)(x))) + +#define _cffi_from_c_int(x, type) \ + (((type)-1) > 0 ? /* unsigned */ \ + (sizeof(type) < sizeof(long) ? \ + PyInt_FromLong((long)x) : \ + sizeof(type) == sizeof(long) ? \ + PyLong_FromUnsignedLong((unsigned long)x) : \ + PyLong_FromUnsignedLongLong((unsigned long long)x)) : \ + (sizeof(type) <= sizeof(long) ? \ + PyInt_FromLong((long)x) : \ + PyLong_FromLongLong((long long)x))) + +#define _cffi_to_c_int(o, type) \ + ((type)( \ + sizeof(type) == 1 ? (((type)-1) > 0 ? (type)_cffi_to_c_u8(o) \ + : (type)_cffi_to_c_i8(o)) : \ + sizeof(type) == 2 ? (((type)-1) > 0 ? (type)_cffi_to_c_u16(o) \ + : (type)_cffi_to_c_i16(o)) : \ + sizeof(type) == 4 ? (((type)-1) > 0 ? (type)_cffi_to_c_u32(o) \ + : (type)_cffi_to_c_i32(o)) : \ + sizeof(type) == 8 ? (((type)-1) > 0 ? (type)_cffi_to_c_u64(o) \ + : (type)_cffi_to_c_i64(o)) : \ + (Py_FatalError("unsupported size for type " #type), (type)0))) + +#define _cffi_to_c_i8 \ + ((int(*)(PyObject *))_cffi_exports[1]) +#define _cffi_to_c_u8 \ + ((int(*)(PyObject *))_cffi_exports[2]) +#define _cffi_to_c_i16 \ + ((int(*)(PyObject *))_cffi_exports[3]) +#define _cffi_to_c_u16 \ + ((int(*)(PyObject *))_cffi_exports[4]) +#define _cffi_to_c_i32 \ + ((int(*)(PyObject *))_cffi_exports[5]) +#define _cffi_to_c_u32 \ + ((unsigned int(*)(PyObject *))_cffi_exports[6]) +#define _cffi_to_c_i64 \ + ((long long(*)(PyObject *))_cffi_exports[7]) +#define _cffi_to_c_u64 \ + ((unsigned long long(*)(PyObject *))_cffi_exports[8]) +#define _cffi_to_c_char \ + ((int(*)(PyObject *))_cffi_exports[9]) +#define _cffi_from_c_pointer \ + ((PyObject *(*)(char *, CTypeDescrObject *))_cffi_exports[10]) +#define _cffi_to_c_pointer \ + ((char *(*)(PyObject *, CTypeDescrObject *))_cffi_exports[11]) +#define _cffi_get_struct_layout \ + ((PyObject *(*)(Py_ssize_t[]))_cffi_exports[12]) +#define _cffi_restore_errno \ + ((void(*)(void))_cffi_exports[13]) +#define _cffi_save_errno \ + ((void(*)(void))_cffi_exports[14]) +#define _cffi_from_c_char \ + ((PyObject *(*)(char))_cffi_exports[15]) +#define _cffi_from_c_deref \ + ((PyObject *(*)(char *, CTypeDescrObject *))_cffi_exports[16]) +#define _cffi_to_c \ + ((int(*)(char *, CTypeDescrObject *, PyObject *))_cffi_exports[17]) +#define _cffi_from_c_struct \ + ((PyObject *(*)(char *, CTypeDescrObject *))_cffi_exports[18]) +#define _cffi_to_c_wchar_t \ + ((wchar_t(*)(PyObject *))_cffi_exports[19]) +#define _cffi_from_c_wchar_t \ + ((PyObject *(*)(wchar_t))_cffi_exports[20]) +#define _cffi_to_c_long_double \ + ((long double(*)(PyObject *))_cffi_exports[21]) +#define _cffi_to_c__Bool \ + ((_Bool(*)(PyObject *))_cffi_exports[22]) +#define _cffi_prepare_pointer_call_argument \ + ((Py_ssize_t(*)(CTypeDescrObject *, PyObject *, char **))_cffi_exports[23]) +#define _cffi_convert_array_from_object \ + ((int(*)(char *, CTypeDescrObject *, PyObject *))_cffi_exports[24]) +#define _CFFI_NUM_EXPORTS 25 + +typedef struct _ctypedescr CTypeDescrObject; + +static void *_cffi_exports[_CFFI_NUM_EXPORTS]; +static PyObject *_cffi_types, *_cffi_VerificationError; + +static int _cffi_setup_custom(PyObject *lib); /* forward */ + +static PyObject *_cffi_setup(PyObject *self, PyObject *args) +{ + PyObject *library; + int was_alive = (_cffi_types != NULL); + (void)self; /* unused */ + if (!PyArg_ParseTuple(args, "OOO", &_cffi_types, &_cffi_VerificationError, + &library)) + return NULL; + Py_INCREF(_cffi_types); + Py_INCREF(_cffi_VerificationError); + if (_cffi_setup_custom(library) < 0) + return NULL; + return PyBool_FromLong(was_alive); +} + +union _cffi_union_alignment_u { + unsigned char m_char; + unsigned short m_short; + unsigned int m_int; + unsigned long m_long; + unsigned long long m_longlong; + float m_float; + double m_double; + long double m_longdouble; +}; + +struct _cffi_freeme_s { + struct _cffi_freeme_s *next; + union _cffi_union_alignment_u alignment; +}; + +#ifdef __GNUC__ + __attribute__((unused)) +#endif +static int _cffi_convert_array_argument(CTypeDescrObject *ctptr, PyObject *arg, + char **output_data, Py_ssize_t datasize, + struct _cffi_freeme_s **freeme) +{ + char *p; + if (datasize < 0) + return -1; + + p = *output_data; + if (p == NULL) { + struct _cffi_freeme_s *fp = (struct _cffi_freeme_s *)PyObject_Malloc( + offsetof(struct _cffi_freeme_s, alignment) + (size_t)datasize); + if (fp == NULL) + return -1; + fp->next = *freeme; + *freeme = fp; + p = *output_data = (char *)&fp->alignment; + } + memset((void *)p, 0, (size_t)datasize); + return _cffi_convert_array_from_object(p, ctptr, arg); +} + +#ifdef __GNUC__ + __attribute__((unused)) +#endif +static void _cffi_free_array_arguments(struct _cffi_freeme_s *freeme) +{ + do { + void *p = (void *)freeme; + freeme = freeme->next; + PyObject_Free(p); + } while (freeme != NULL); +} + +static int _cffi_init(void) +{ + PyObject *module, *c_api_object = NULL; + + module = PyImport_ImportModule("_cffi_backend"); + if (module == NULL) + goto failure; + + c_api_object = PyObject_GetAttrString(module, "_C_API"); + if (c_api_object == NULL) + goto failure; + if (!PyCapsule_CheckExact(c_api_object)) { + PyErr_SetNone(PyExc_ImportError); + goto failure; + } + memcpy(_cffi_exports, PyCapsule_GetPointer(c_api_object, "cffi"), + _CFFI_NUM_EXPORTS * sizeof(void *)); + + Py_DECREF(module); + Py_DECREF(c_api_object); + return 0; + + failure: + Py_XDECREF(module); + Py_XDECREF(c_api_object); + return -1; +} + +#define _cffi_type(num) ((CTypeDescrObject *)PyList_GET_ITEM(_cffi_types, num)) + +/**********/ +''' diff --git a/venv/Lib/site-packages/cffi/vengine_gen.py b/venv/Lib/site-packages/cffi/vengine_gen.py new file mode 100644 index 000000000..26421526f --- /dev/null +++ b/venv/Lib/site-packages/cffi/vengine_gen.py @@ -0,0 +1,675 @@ +# +# DEPRECATED: implementation for ffi.verify() +# +import sys, os +import types + +from . import model +from .error import VerificationError + + +class VGenericEngine(object): + _class_key = 'g' + _gen_python_module = False + + def __init__(self, verifier): + self.verifier = verifier + self.ffi = verifier.ffi + self.export_symbols = [] + self._struct_pending_verification = {} + + def patch_extension_kwds(self, kwds): + # add 'export_symbols' to the dictionary. Note that we add the + # list before filling it. When we fill it, it will thus also show + # up in kwds['export_symbols']. + kwds.setdefault('export_symbols', self.export_symbols) + + def find_module(self, module_name, path, so_suffixes): + for so_suffix in so_suffixes: + basename = module_name + so_suffix + if path is None: + path = sys.path + for dirname in path: + filename = os.path.join(dirname, basename) + if os.path.isfile(filename): + return filename + + def collect_types(self): + pass # not needed in the generic engine + + def _prnt(self, what=''): + self._f.write(what + '\n') + + def write_source_to_f(self): + prnt = self._prnt + # first paste some standard set of lines that are mostly '#include' + prnt(cffimod_header) + # then paste the C source given by the user, verbatim. + prnt(self.verifier.preamble) + # + # call generate_gen_xxx_decl(), for every xxx found from + # ffi._parser._declarations. This generates all the functions. + self._generate('decl') + # + # on Windows, distutils insists on putting init_cffi_xyz in + # 'export_symbols', so instead of fighting it, just give up and + # give it one + if sys.platform == 'win32': + if sys.version_info >= (3,): + prefix = 'PyInit_' + else: + prefix = 'init' + modname = self.verifier.get_module_name() + prnt("void %s%s(void) { }\n" % (prefix, modname)) + + def load_library(self, flags=0): + # import it with the CFFI backend + backend = self.ffi._backend + # needs to make a path that contains '/', on Posix + filename = os.path.join(os.curdir, self.verifier.modulefilename) + module = backend.load_library(filename, flags) + # + # call loading_gen_struct() to get the struct layout inferred by + # the C compiler + self._load(module, 'loading') + + # build the FFILibrary class and instance, this is a module subclass + # because modules are expected to have usually-constant-attributes and + # in PyPy this means the JIT is able to treat attributes as constant, + # which we want. + class FFILibrary(types.ModuleType): + _cffi_generic_module = module + _cffi_ffi = self.ffi + _cffi_dir = [] + def __dir__(self): + return FFILibrary._cffi_dir + library = FFILibrary("") + # + # finally, call the loaded_gen_xxx() functions. This will set + # up the 'library' object. + self._load(module, 'loaded', library=library) + return library + + def _get_declarations(self): + lst = [(key, tp) for (key, (tp, qual)) in + self.ffi._parser._declarations.items()] + lst.sort() + return lst + + def _generate(self, step_name): + for name, tp in self._get_declarations(): + kind, realname = name.split(' ', 1) + try: + method = getattr(self, '_generate_gen_%s_%s' % (kind, + step_name)) + except AttributeError: + raise VerificationError( + "not implemented in verify(): %r" % name) + try: + method(tp, realname) + except Exception as e: + model.attach_exception_info(e, name) + raise + + def _load(self, module, step_name, **kwds): + for name, tp in self._get_declarations(): + kind, realname = name.split(' ', 1) + method = getattr(self, '_%s_gen_%s' % (step_name, kind)) + try: + method(tp, realname, module, **kwds) + except Exception as e: + model.attach_exception_info(e, name) + raise + + def _generate_nothing(self, tp, name): + pass + + def _loaded_noop(self, tp, name, module, **kwds): + pass + + # ---------- + # typedefs: generates no code so far + + _generate_gen_typedef_decl = _generate_nothing + _loading_gen_typedef = _loaded_noop + _loaded_gen_typedef = _loaded_noop + + # ---------- + # function declarations + + def _generate_gen_function_decl(self, tp, name): + assert isinstance(tp, model.FunctionPtrType) + if tp.ellipsis: + # cannot support vararg functions better than this: check for its + # exact type (including the fixed arguments), and build it as a + # constant function pointer (no _cffi_f_%s wrapper) + self._generate_gen_const(False, name, tp) + return + prnt = self._prnt + numargs = len(tp.args) + argnames = [] + for i, type in enumerate(tp.args): + indirection = '' + if isinstance(type, model.StructOrUnion): + indirection = '*' + argnames.append('%sx%d' % (indirection, i)) + context = 'argument of %s' % name + arglist = [type.get_c_name(' %s' % arg, context) + for type, arg in zip(tp.args, argnames)] + tpresult = tp.result + if isinstance(tpresult, model.StructOrUnion): + arglist.insert(0, tpresult.get_c_name(' *r', context)) + tpresult = model.void_type + arglist = ', '.join(arglist) or 'void' + wrappername = '_cffi_f_%s' % name + self.export_symbols.append(wrappername) + if tp.abi: + abi = tp.abi + ' ' + else: + abi = '' + funcdecl = ' %s%s(%s)' % (abi, wrappername, arglist) + context = 'result of %s' % name + prnt(tpresult.get_c_name(funcdecl, context)) + prnt('{') + # + if isinstance(tp.result, model.StructOrUnion): + result_code = '*r = ' + elif not isinstance(tp.result, model.VoidType): + result_code = 'return ' + else: + result_code = '' + prnt(' %s%s(%s);' % (result_code, name, ', '.join(argnames))) + prnt('}') + prnt() + + _loading_gen_function = _loaded_noop + + def _loaded_gen_function(self, tp, name, module, library): + assert isinstance(tp, model.FunctionPtrType) + if tp.ellipsis: + newfunction = self._load_constant(False, tp, name, module) + else: + indirections = [] + base_tp = tp + if (any(isinstance(typ, model.StructOrUnion) for typ in tp.args) + or isinstance(tp.result, model.StructOrUnion)): + indirect_args = [] + for i, typ in enumerate(tp.args): + if isinstance(typ, model.StructOrUnion): + typ = model.PointerType(typ) + indirections.append((i, typ)) + indirect_args.append(typ) + indirect_result = tp.result + if isinstance(indirect_result, model.StructOrUnion): + if indirect_result.fldtypes is None: + raise TypeError("'%s' is used as result type, " + "but is opaque" % ( + indirect_result._get_c_name(),)) + indirect_result = model.PointerType(indirect_result) + indirect_args.insert(0, indirect_result) + indirections.insert(0, ("result", indirect_result)) + indirect_result = model.void_type + tp = model.FunctionPtrType(tuple(indirect_args), + indirect_result, tp.ellipsis) + BFunc = self.ffi._get_cached_btype(tp) + wrappername = '_cffi_f_%s' % name + newfunction = module.load_function(BFunc, wrappername) + for i, typ in indirections: + newfunction = self._make_struct_wrapper(newfunction, i, typ, + base_tp) + setattr(library, name, newfunction) + type(library)._cffi_dir.append(name) + + def _make_struct_wrapper(self, oldfunc, i, tp, base_tp): + backend = self.ffi._backend + BType = self.ffi._get_cached_btype(tp) + if i == "result": + ffi = self.ffi + def newfunc(*args): + res = ffi.new(BType) + oldfunc(res, *args) + return res[0] + else: + def newfunc(*args): + args = args[:i] + (backend.newp(BType, args[i]),) + args[i+1:] + return oldfunc(*args) + newfunc._cffi_base_type = base_tp + return newfunc + + # ---------- + # named structs + + def _generate_gen_struct_decl(self, tp, name): + assert name == tp.name + self._generate_struct_or_union_decl(tp, 'struct', name) + + def _loading_gen_struct(self, tp, name, module): + self._loading_struct_or_union(tp, 'struct', name, module) + + def _loaded_gen_struct(self, tp, name, module, **kwds): + self._loaded_struct_or_union(tp) + + def _generate_gen_union_decl(self, tp, name): + assert name == tp.name + self._generate_struct_or_union_decl(tp, 'union', name) + + def _loading_gen_union(self, tp, name, module): + self._loading_struct_or_union(tp, 'union', name, module) + + def _loaded_gen_union(self, tp, name, module, **kwds): + self._loaded_struct_or_union(tp) + + def _generate_struct_or_union_decl(self, tp, prefix, name): + if tp.fldnames is None: + return # nothing to do with opaque structs + checkfuncname = '_cffi_check_%s_%s' % (prefix, name) + layoutfuncname = '_cffi_layout_%s_%s' % (prefix, name) + cname = ('%s %s' % (prefix, name)).strip() + # + prnt = self._prnt + prnt('static void %s(%s *p)' % (checkfuncname, cname)) + prnt('{') + prnt(' /* only to generate compile-time warnings or errors */') + prnt(' (void)p;') + for fname, ftype, fbitsize, fqual in tp.enumfields(): + if (isinstance(ftype, model.PrimitiveType) + and ftype.is_integer_type()) or fbitsize >= 0: + # accept all integers, but complain on float or double + prnt(' (void)((p->%s) << 1);' % fname) + else: + # only accept exactly the type declared. + try: + prnt(' { %s = &p->%s; (void)tmp; }' % ( + ftype.get_c_name('*tmp', 'field %r'%fname, quals=fqual), + fname)) + except VerificationError as e: + prnt(' /* %s */' % str(e)) # cannot verify it, ignore + prnt('}') + self.export_symbols.append(layoutfuncname) + prnt('intptr_t %s(intptr_t i)' % (layoutfuncname,)) + prnt('{') + prnt(' struct _cffi_aligncheck { char x; %s y; };' % cname) + prnt(' static intptr_t nums[] = {') + prnt(' sizeof(%s),' % cname) + prnt(' offsetof(struct _cffi_aligncheck, y),') + for fname, ftype, fbitsize, fqual in tp.enumfields(): + if fbitsize >= 0: + continue # xxx ignore fbitsize for now + prnt(' offsetof(%s, %s),' % (cname, fname)) + if isinstance(ftype, model.ArrayType) and ftype.length is None: + prnt(' 0, /* %s */' % ftype._get_c_name()) + else: + prnt(' sizeof(((%s *)0)->%s),' % (cname, fname)) + prnt(' -1') + prnt(' };') + prnt(' return nums[i];') + prnt(' /* the next line is not executed, but compiled */') + prnt(' %s(0);' % (checkfuncname,)) + prnt('}') + prnt() + + def _loading_struct_or_union(self, tp, prefix, name, module): + if tp.fldnames is None: + return # nothing to do with opaque structs + layoutfuncname = '_cffi_layout_%s_%s' % (prefix, name) + # + BFunc = self.ffi._typeof_locked("intptr_t(*)(intptr_t)")[0] + function = module.load_function(BFunc, layoutfuncname) + layout = [] + num = 0 + while True: + x = function(num) + if x < 0: break + layout.append(x) + num += 1 + if isinstance(tp, model.StructOrUnion) and tp.partial: + # use the function()'s sizes and offsets to guide the + # layout of the struct + totalsize = layout[0] + totalalignment = layout[1] + fieldofs = layout[2::2] + fieldsize = layout[3::2] + tp.force_flatten() + assert len(fieldofs) == len(fieldsize) == len(tp.fldnames) + tp.fixedlayout = fieldofs, fieldsize, totalsize, totalalignment + else: + cname = ('%s %s' % (prefix, name)).strip() + self._struct_pending_verification[tp] = layout, cname + + def _loaded_struct_or_union(self, tp): + if tp.fldnames is None: + return # nothing to do with opaque structs + self.ffi._get_cached_btype(tp) # force 'fixedlayout' to be considered + + if tp in self._struct_pending_verification: + # check that the layout sizes and offsets match the real ones + def check(realvalue, expectedvalue, msg): + if realvalue != expectedvalue: + raise VerificationError( + "%s (we have %d, but C compiler says %d)" + % (msg, expectedvalue, realvalue)) + ffi = self.ffi + BStruct = ffi._get_cached_btype(tp) + layout, cname = self._struct_pending_verification.pop(tp) + check(layout[0], ffi.sizeof(BStruct), "wrong total size") + check(layout[1], ffi.alignof(BStruct), "wrong total alignment") + i = 2 + for fname, ftype, fbitsize, fqual in tp.enumfields(): + if fbitsize >= 0: + continue # xxx ignore fbitsize for now + check(layout[i], ffi.offsetof(BStruct, fname), + "wrong offset for field %r" % (fname,)) + if layout[i+1] != 0: + BField = ffi._get_cached_btype(ftype) + check(layout[i+1], ffi.sizeof(BField), + "wrong size for field %r" % (fname,)) + i += 2 + assert i == len(layout) + + # ---------- + # 'anonymous' declarations. These are produced for anonymous structs + # or unions; the 'name' is obtained by a typedef. + + def _generate_gen_anonymous_decl(self, tp, name): + if isinstance(tp, model.EnumType): + self._generate_gen_enum_decl(tp, name, '') + else: + self._generate_struct_or_union_decl(tp, '', name) + + def _loading_gen_anonymous(self, tp, name, module): + if isinstance(tp, model.EnumType): + self._loading_gen_enum(tp, name, module, '') + else: + self._loading_struct_or_union(tp, '', name, module) + + def _loaded_gen_anonymous(self, tp, name, module, **kwds): + if isinstance(tp, model.EnumType): + self._loaded_gen_enum(tp, name, module, **kwds) + else: + self._loaded_struct_or_union(tp) + + # ---------- + # constants, likely declared with '#define' + + def _generate_gen_const(self, is_int, name, tp=None, category='const', + check_value=None): + prnt = self._prnt + funcname = '_cffi_%s_%s' % (category, name) + self.export_symbols.append(funcname) + if check_value is not None: + assert is_int + assert category == 'const' + prnt('int %s(char *out_error)' % funcname) + prnt('{') + self._check_int_constant_value(name, check_value) + prnt(' return 0;') + prnt('}') + elif is_int: + assert category == 'const' + prnt('int %s(long long *out_value)' % funcname) + prnt('{') + prnt(' *out_value = (long long)(%s);' % (name,)) + prnt(' return (%s) <= 0;' % (name,)) + prnt('}') + else: + assert tp is not None + assert check_value is None + if category == 'var': + ampersand = '&' + else: + ampersand = '' + extra = '' + if category == 'const' and isinstance(tp, model.StructOrUnion): + extra = 'const *' + ampersand = '&' + prnt(tp.get_c_name(' %s%s(void)' % (extra, funcname), name)) + prnt('{') + prnt(' return (%s%s);' % (ampersand, name)) + prnt('}') + prnt() + + def _generate_gen_constant_decl(self, tp, name): + is_int = isinstance(tp, model.PrimitiveType) and tp.is_integer_type() + self._generate_gen_const(is_int, name, tp) + + _loading_gen_constant = _loaded_noop + + def _load_constant(self, is_int, tp, name, module, check_value=None): + funcname = '_cffi_const_%s' % name + if check_value is not None: + assert is_int + self._load_known_int_constant(module, funcname) + value = check_value + elif is_int: + BType = self.ffi._typeof_locked("long long*")[0] + BFunc = self.ffi._typeof_locked("int(*)(long long*)")[0] + function = module.load_function(BFunc, funcname) + p = self.ffi.new(BType) + negative = function(p) + value = int(p[0]) + if value < 0 and not negative: + BLongLong = self.ffi._typeof_locked("long long")[0] + value += (1 << (8*self.ffi.sizeof(BLongLong))) + else: + assert check_value is None + fntypeextra = '(*)(void)' + if isinstance(tp, model.StructOrUnion): + fntypeextra = '*' + fntypeextra + BFunc = self.ffi._typeof_locked(tp.get_c_name(fntypeextra, name))[0] + function = module.load_function(BFunc, funcname) + value = function() + if isinstance(tp, model.StructOrUnion): + value = value[0] + return value + + def _loaded_gen_constant(self, tp, name, module, library): + is_int = isinstance(tp, model.PrimitiveType) and tp.is_integer_type() + value = self._load_constant(is_int, tp, name, module) + setattr(library, name, value) + type(library)._cffi_dir.append(name) + + # ---------- + # enums + + def _check_int_constant_value(self, name, value): + prnt = self._prnt + if value <= 0: + prnt(' if ((%s) > 0 || (long)(%s) != %dL) {' % ( + name, name, value)) + else: + prnt(' if ((%s) <= 0 || (unsigned long)(%s) != %dUL) {' % ( + name, name, value)) + prnt(' char buf[64];') + prnt(' if ((%s) <= 0)' % name) + prnt(' sprintf(buf, "%%ld", (long)(%s));' % name) + prnt(' else') + prnt(' sprintf(buf, "%%lu", (unsigned long)(%s));' % + name) + prnt(' sprintf(out_error, "%s has the real value %s, not %s",') + prnt(' "%s", buf, "%d");' % (name[:100], value)) + prnt(' return -1;') + prnt(' }') + + def _load_known_int_constant(self, module, funcname): + BType = self.ffi._typeof_locked("char[]")[0] + BFunc = self.ffi._typeof_locked("int(*)(char*)")[0] + function = module.load_function(BFunc, funcname) + p = self.ffi.new(BType, 256) + if function(p) < 0: + error = self.ffi.string(p) + if sys.version_info >= (3,): + error = str(error, 'utf-8') + raise VerificationError(error) + + def _enum_funcname(self, prefix, name): + # "$enum_$1" => "___D_enum____D_1" + name = name.replace('$', '___D_') + return '_cffi_e_%s_%s' % (prefix, name) + + def _generate_gen_enum_decl(self, tp, name, prefix='enum'): + if tp.partial: + for enumerator in tp.enumerators: + self._generate_gen_const(True, enumerator) + return + # + funcname = self._enum_funcname(prefix, name) + self.export_symbols.append(funcname) + prnt = self._prnt + prnt('int %s(char *out_error)' % funcname) + prnt('{') + for enumerator, enumvalue in zip(tp.enumerators, tp.enumvalues): + self._check_int_constant_value(enumerator, enumvalue) + prnt(' return 0;') + prnt('}') + prnt() + + def _loading_gen_enum(self, tp, name, module, prefix='enum'): + if tp.partial: + enumvalues = [self._load_constant(True, tp, enumerator, module) + for enumerator in tp.enumerators] + tp.enumvalues = tuple(enumvalues) + tp.partial_resolved = True + else: + funcname = self._enum_funcname(prefix, name) + self._load_known_int_constant(module, funcname) + + def _loaded_gen_enum(self, tp, name, module, library): + for enumerator, enumvalue in zip(tp.enumerators, tp.enumvalues): + setattr(library, enumerator, enumvalue) + type(library)._cffi_dir.append(enumerator) + + # ---------- + # macros: for now only for integers + + def _generate_gen_macro_decl(self, tp, name): + if tp == '...': + check_value = None + else: + check_value = tp # an integer + self._generate_gen_const(True, name, check_value=check_value) + + _loading_gen_macro = _loaded_noop + + def _loaded_gen_macro(self, tp, name, module, library): + if tp == '...': + check_value = None + else: + check_value = tp # an integer + value = self._load_constant(True, tp, name, module, + check_value=check_value) + setattr(library, name, value) + type(library)._cffi_dir.append(name) + + # ---------- + # global variables + + def _generate_gen_variable_decl(self, tp, name): + if isinstance(tp, model.ArrayType): + if tp.length_is_unknown(): + prnt = self._prnt + funcname = '_cffi_sizeof_%s' % (name,) + self.export_symbols.append(funcname) + prnt("size_t %s(void)" % funcname) + prnt("{") + prnt(" return sizeof(%s);" % (name,)) + prnt("}") + tp_ptr = model.PointerType(tp.item) + self._generate_gen_const(False, name, tp_ptr) + else: + tp_ptr = model.PointerType(tp) + self._generate_gen_const(False, name, tp_ptr, category='var') + + _loading_gen_variable = _loaded_noop + + def _loaded_gen_variable(self, tp, name, module, library): + if isinstance(tp, model.ArrayType): # int a[5] is "constant" in the + # sense that "a=..." is forbidden + if tp.length_is_unknown(): + funcname = '_cffi_sizeof_%s' % (name,) + BFunc = self.ffi._typeof_locked('size_t(*)(void)')[0] + function = module.load_function(BFunc, funcname) + size = function() + BItemType = self.ffi._get_cached_btype(tp.item) + length, rest = divmod(size, self.ffi.sizeof(BItemType)) + if rest != 0: + raise VerificationError( + "bad size: %r does not seem to be an array of %s" % + (name, tp.item)) + tp = tp.resolve_length(length) + tp_ptr = model.PointerType(tp.item) + value = self._load_constant(False, tp_ptr, name, module) + # 'value' is a which we have to replace with + # a if the N is actually known + if tp.length is not None: + BArray = self.ffi._get_cached_btype(tp) + value = self.ffi.cast(BArray, value) + setattr(library, name, value) + type(library)._cffi_dir.append(name) + return + # remove ptr= from the library instance, and replace + # it by a property on the class, which reads/writes into ptr[0]. + funcname = '_cffi_var_%s' % name + BFunc = self.ffi._typeof_locked(tp.get_c_name('*(*)(void)', name))[0] + function = module.load_function(BFunc, funcname) + ptr = function() + def getter(library): + return ptr[0] + def setter(library, value): + ptr[0] = value + setattr(type(library), name, property(getter, setter)) + type(library)._cffi_dir.append(name) + +cffimod_header = r''' +#include +#include +#include +#include +#include /* XXX for ssize_t on some platforms */ + +/* this block of #ifs should be kept exactly identical between + c/_cffi_backend.c, cffi/vengine_cpy.py, cffi/vengine_gen.py + and cffi/_cffi_include.h */ +#if defined(_MSC_VER) +# include /* for alloca() */ +# if _MSC_VER < 1600 /* MSVC < 2010 */ + typedef __int8 int8_t; + typedef __int16 int16_t; + typedef __int32 int32_t; + typedef __int64 int64_t; + typedef unsigned __int8 uint8_t; + typedef unsigned __int16 uint16_t; + typedef unsigned __int32 uint32_t; + typedef unsigned __int64 uint64_t; + typedef __int8 int_least8_t; + typedef __int16 int_least16_t; + typedef __int32 int_least32_t; + typedef __int64 int_least64_t; + typedef unsigned __int8 uint_least8_t; + typedef unsigned __int16 uint_least16_t; + typedef unsigned __int32 uint_least32_t; + typedef unsigned __int64 uint_least64_t; + typedef __int8 int_fast8_t; + typedef __int16 int_fast16_t; + typedef __int32 int_fast32_t; + typedef __int64 int_fast64_t; + typedef unsigned __int8 uint_fast8_t; + typedef unsigned __int16 uint_fast16_t; + typedef unsigned __int32 uint_fast32_t; + typedef unsigned __int64 uint_fast64_t; + typedef __int64 intmax_t; + typedef unsigned __int64 uintmax_t; +# else +# include +# endif +# if _MSC_VER < 1800 /* MSVC < 2013 */ +# ifndef __cplusplus + typedef unsigned char _Bool; +# endif +# endif +#else +# include +# if (defined (__SVR4) && defined (__sun)) || defined(_AIX) || defined(__hpux) +# include +# endif +#endif +''' diff --git a/venv/Lib/site-packages/cffi/verifier.py b/venv/Lib/site-packages/cffi/verifier.py new file mode 100644 index 000000000..59b78c216 --- /dev/null +++ b/venv/Lib/site-packages/cffi/verifier.py @@ -0,0 +1,306 @@ +# +# DEPRECATED: implementation for ffi.verify() +# +import sys, os, binascii, shutil, io +from . import __version_verifier_modules__ +from . import ffiplatform +from .error import VerificationError + +if sys.version_info >= (3, 3): + import importlib.machinery + def _extension_suffixes(): + return importlib.machinery.EXTENSION_SUFFIXES[:] +else: + import imp + def _extension_suffixes(): + return [suffix for suffix, _, type in imp.get_suffixes() + if type == imp.C_EXTENSION] + + +if sys.version_info >= (3,): + NativeIO = io.StringIO +else: + class NativeIO(io.BytesIO): + def write(self, s): + if isinstance(s, unicode): + s = s.encode('ascii') + super(NativeIO, self).write(s) + + +class Verifier(object): + + def __init__(self, ffi, preamble, tmpdir=None, modulename=None, + ext_package=None, tag='', force_generic_engine=False, + source_extension='.c', flags=None, relative_to=None, **kwds): + if ffi._parser._uses_new_feature: + raise VerificationError( + "feature not supported with ffi.verify(), but only " + "with ffi.set_source(): %s" % (ffi._parser._uses_new_feature,)) + self.ffi = ffi + self.preamble = preamble + if not modulename: + flattened_kwds = ffiplatform.flatten(kwds) + vengine_class = _locate_engine_class(ffi, force_generic_engine) + self._vengine = vengine_class(self) + self._vengine.patch_extension_kwds(kwds) + self.flags = flags + self.kwds = self.make_relative_to(kwds, relative_to) + # + if modulename: + if tag: + raise TypeError("can't specify both 'modulename' and 'tag'") + else: + key = '\x00'.join([sys.version[:3], __version_verifier_modules__, + preamble, flattened_kwds] + + ffi._cdefsources) + if sys.version_info >= (3,): + key = key.encode('utf-8') + k1 = hex(binascii.crc32(key[0::2]) & 0xffffffff) + k1 = k1.lstrip('0x').rstrip('L') + k2 = hex(binascii.crc32(key[1::2]) & 0xffffffff) + k2 = k2.lstrip('0').rstrip('L') + modulename = '_cffi_%s_%s%s%s' % (tag, self._vengine._class_key, + k1, k2) + suffix = _get_so_suffixes()[0] + self.tmpdir = tmpdir or _caller_dir_pycache() + self.sourcefilename = os.path.join(self.tmpdir, modulename + source_extension) + self.modulefilename = os.path.join(self.tmpdir, modulename + suffix) + self.ext_package = ext_package + self._has_source = False + self._has_module = False + + def write_source(self, file=None): + """Write the C source code. It is produced in 'self.sourcefilename', + which can be tweaked beforehand.""" + with self.ffi._lock: + if self._has_source and file is None: + raise VerificationError( + "source code already written") + self._write_source(file) + + def compile_module(self): + """Write the C source code (if not done already) and compile it. + This produces a dynamic link library in 'self.modulefilename'.""" + with self.ffi._lock: + if self._has_module: + raise VerificationError("module already compiled") + if not self._has_source: + self._write_source() + self._compile_module() + + def load_library(self): + """Get a C module from this Verifier instance. + Returns an instance of a FFILibrary class that behaves like the + objects returned by ffi.dlopen(), but that delegates all + operations to the C module. If necessary, the C code is written + and compiled first. + """ + with self.ffi._lock: + if not self._has_module: + self._locate_module() + if not self._has_module: + if not self._has_source: + self._write_source() + self._compile_module() + return self._load_library() + + def get_module_name(self): + basename = os.path.basename(self.modulefilename) + # kill both the .so extension and the other .'s, as introduced + # by Python 3: 'basename.cpython-33m.so' + basename = basename.split('.', 1)[0] + # and the _d added in Python 2 debug builds --- but try to be + # conservative and not kill a legitimate _d + if basename.endswith('_d') and hasattr(sys, 'gettotalrefcount'): + basename = basename[:-2] + return basename + + def get_extension(self): + ffiplatform._hack_at_distutils() # backward compatibility hack + if not self._has_source: + with self.ffi._lock: + if not self._has_source: + self._write_source() + sourcename = ffiplatform.maybe_relative_path(self.sourcefilename) + modname = self.get_module_name() + return ffiplatform.get_extension(sourcename, modname, **self.kwds) + + def generates_python_module(self): + return self._vengine._gen_python_module + + def make_relative_to(self, kwds, relative_to): + if relative_to and os.path.dirname(relative_to): + dirname = os.path.dirname(relative_to) + kwds = kwds.copy() + for key in ffiplatform.LIST_OF_FILE_NAMES: + if key in kwds: + lst = kwds[key] + if not isinstance(lst, (list, tuple)): + raise TypeError("keyword '%s' should be a list or tuple" + % (key,)) + lst = [os.path.join(dirname, fn) for fn in lst] + kwds[key] = lst + return kwds + + # ---------- + + def _locate_module(self): + if not os.path.isfile(self.modulefilename): + if self.ext_package: + try: + pkg = __import__(self.ext_package, None, None, ['__doc__']) + except ImportError: + return # cannot import the package itself, give up + # (e.g. it might be called differently before installation) + path = pkg.__path__ + else: + path = None + filename = self._vengine.find_module(self.get_module_name(), path, + _get_so_suffixes()) + if filename is None: + return + self.modulefilename = filename + self._vengine.collect_types() + self._has_module = True + + def _write_source_to(self, file): + self._vengine._f = file + try: + self._vengine.write_source_to_f() + finally: + del self._vengine._f + + def _write_source(self, file=None): + if file is not None: + self._write_source_to(file) + else: + # Write our source file to an in memory file. + f = NativeIO() + self._write_source_to(f) + source_data = f.getvalue() + + # Determine if this matches the current file + if os.path.exists(self.sourcefilename): + with open(self.sourcefilename, "r") as fp: + needs_written = not (fp.read() == source_data) + else: + needs_written = True + + # Actually write the file out if it doesn't match + if needs_written: + _ensure_dir(self.sourcefilename) + with open(self.sourcefilename, "w") as fp: + fp.write(source_data) + + # Set this flag + self._has_source = True + + def _compile_module(self): + # compile this C source + tmpdir = os.path.dirname(self.sourcefilename) + outputfilename = ffiplatform.compile(tmpdir, self.get_extension()) + try: + same = ffiplatform.samefile(outputfilename, self.modulefilename) + except OSError: + same = False + if not same: + _ensure_dir(self.modulefilename) + shutil.move(outputfilename, self.modulefilename) + self._has_module = True + + def _load_library(self): + assert self._has_module + if self.flags is not None: + return self._vengine.load_library(self.flags) + else: + return self._vengine.load_library() + +# ____________________________________________________________ + +_FORCE_GENERIC_ENGINE = False # for tests + +def _locate_engine_class(ffi, force_generic_engine): + if _FORCE_GENERIC_ENGINE: + force_generic_engine = True + if not force_generic_engine: + if '__pypy__' in sys.builtin_module_names: + force_generic_engine = True + else: + try: + import _cffi_backend + except ImportError: + _cffi_backend = '?' + if ffi._backend is not _cffi_backend: + force_generic_engine = True + if force_generic_engine: + from . import vengine_gen + return vengine_gen.VGenericEngine + else: + from . import vengine_cpy + return vengine_cpy.VCPythonEngine + +# ____________________________________________________________ + +_TMPDIR = None + +def _caller_dir_pycache(): + if _TMPDIR: + return _TMPDIR + result = os.environ.get('CFFI_TMPDIR') + if result: + return result + filename = sys._getframe(2).f_code.co_filename + return os.path.abspath(os.path.join(os.path.dirname(filename), + '__pycache__')) + +def set_tmpdir(dirname): + """Set the temporary directory to use instead of __pycache__.""" + global _TMPDIR + _TMPDIR = dirname + +def cleanup_tmpdir(tmpdir=None, keep_so=False): + """Clean up the temporary directory by removing all files in it + called `_cffi_*.{c,so}` as well as the `build` subdirectory.""" + tmpdir = tmpdir or _caller_dir_pycache() + try: + filelist = os.listdir(tmpdir) + except OSError: + return + if keep_so: + suffix = '.c' # only remove .c files + else: + suffix = _get_so_suffixes()[0].lower() + for fn in filelist: + if fn.lower().startswith('_cffi_') and ( + fn.lower().endswith(suffix) or fn.lower().endswith('.c')): + try: + os.unlink(os.path.join(tmpdir, fn)) + except OSError: + pass + clean_dir = [os.path.join(tmpdir, 'build')] + for dir in clean_dir: + try: + for fn in os.listdir(dir): + fn = os.path.join(dir, fn) + if os.path.isdir(fn): + clean_dir.append(fn) + else: + os.unlink(fn) + except OSError: + pass + +def _get_so_suffixes(): + suffixes = _extension_suffixes() + if not suffixes: + # bah, no C_EXTENSION available. Occurs on pypy without cpyext + if sys.platform == 'win32': + suffixes = [".pyd"] + else: + suffixes = [".so"] + + return suffixes + +def _ensure_dir(filename): + dirname = os.path.dirname(filename) + if dirname and not os.path.isdir(dirname): + os.makedirs(dirname) diff --git a/venv/Lib/site-packages/chardet-3.0.4.dist-info/DESCRIPTION.rst b/venv/Lib/site-packages/chardet-3.0.4.dist-info/DESCRIPTION.rst new file mode 100644 index 000000000..c0f044d84 --- /dev/null +++ b/venv/Lib/site-packages/chardet-3.0.4.dist-info/DESCRIPTION.rst @@ -0,0 +1,70 @@ +Chardet: The Universal Character Encoding Detector +-------------------------------------------------- + +.. image:: https://img.shields.io/travis/chardet/chardet/stable.svg + :alt: Build status + :target: https://travis-ci.org/chardet/chardet + +.. image:: https://img.shields.io/coveralls/chardet/chardet/stable.svg + :target: https://coveralls.io/r/chardet/chardet + +.. image:: https://img.shields.io/pypi/v/chardet.svg + :target: https://warehouse.python.org/project/chardet/ + :alt: Latest version on PyPI + +.. image:: https://img.shields.io/pypi/l/chardet.svg + :alt: License + + +Detects + - ASCII, UTF-8, UTF-16 (2 variants), UTF-32 (4 variants) + - Big5, GB2312, EUC-TW, HZ-GB-2312, ISO-2022-CN (Traditional and Simplified Chinese) + - EUC-JP, SHIFT_JIS, CP932, ISO-2022-JP (Japanese) + - EUC-KR, ISO-2022-KR (Korean) + - KOI8-R, MacCyrillic, IBM855, IBM866, ISO-8859-5, windows-1251 (Cyrillic) + - ISO-8859-5, windows-1251 (Bulgarian) + - ISO-8859-1, windows-1252 (Western European languages) + - ISO-8859-7, windows-1253 (Greek) + - ISO-8859-8, windows-1255 (Visual and Logical Hebrew) + - TIS-620 (Thai) + +.. note:: + Our ISO-8859-2 and windows-1250 (Hungarian) probers have been temporarily + disabled until we can retrain the models. + +Requires Python 2.6, 2.7, or 3.3+. + +Installation +------------ + +Install from `PyPI `_:: + + pip install chardet + +Documentation +------------- + +For users, docs are now available at https://chardet.readthedocs.io/. + +Command-line Tool +----------------- + +chardet comes with a command-line script which reports on the encodings of one +or more files:: + + % chardetect somefile someotherfile + somefile: windows-1252 with confidence 0.5 + someotherfile: ascii with confidence 1.0 + +About +----- + +This is a continuation of Mark Pilgrim's excellent chardet. Previously, two +versions needed to be maintained: one that supported python 2.x and one that +supported python 3.x. We've recently merged with `Ian Cordasco `_'s +`charade `_ fork, so now we have one +coherent version that works for Python 2.6+. + +:maintainer: Dan Blanchard + + diff --git a/venv/Lib/site-packages/chardet-3.0.4.dist-info/INSTALLER b/venv/Lib/site-packages/chardet-3.0.4.dist-info/INSTALLER new file mode 100644 index 000000000..a1b589e38 --- /dev/null +++ b/venv/Lib/site-packages/chardet-3.0.4.dist-info/INSTALLER @@ -0,0 +1 @@ +pip diff --git a/venv/Lib/site-packages/chardet-3.0.4.dist-info/METADATA b/venv/Lib/site-packages/chardet-3.0.4.dist-info/METADATA new file mode 100644 index 000000000..1427867ab --- /dev/null +++ b/venv/Lib/site-packages/chardet-3.0.4.dist-info/METADATA @@ -0,0 +1,96 @@ +Metadata-Version: 2.0 +Name: chardet +Version: 3.0.4 +Summary: Universal encoding detector for Python 2 and 3 +Home-page: https://github.com/chardet/chardet +Author: Daniel Blanchard +Author-email: dan.blanchard@gmail.com +License: LGPL +Keywords: encoding,i18n,xml +Platform: UNKNOWN +Classifier: Development Status :: 4 - Beta +Classifier: Intended Audience :: Developers +Classifier: License :: OSI Approved :: GNU Library or Lesser General Public License (LGPL) +Classifier: Operating System :: OS Independent +Classifier: Programming Language :: Python +Classifier: Programming Language :: Python :: 2 +Classifier: Programming Language :: Python :: 2.6 +Classifier: Programming Language :: Python :: 2.7 +Classifier: Programming Language :: Python :: 3 +Classifier: Programming Language :: Python :: 3.3 +Classifier: Programming Language :: Python :: 3.4 +Classifier: Programming Language :: Python :: 3.5 +Classifier: Programming Language :: Python :: 3.6 +Classifier: Topic :: Software Development :: Libraries :: Python Modules +Classifier: Topic :: Text Processing :: Linguistic + +Chardet: The Universal Character Encoding Detector +-------------------------------------------------- + +.. image:: https://img.shields.io/travis/chardet/chardet/stable.svg + :alt: Build status + :target: https://travis-ci.org/chardet/chardet + +.. image:: https://img.shields.io/coveralls/chardet/chardet/stable.svg + :target: https://coveralls.io/r/chardet/chardet + +.. image:: https://img.shields.io/pypi/v/chardet.svg + :target: https://warehouse.python.org/project/chardet/ + :alt: Latest version on PyPI + +.. image:: https://img.shields.io/pypi/l/chardet.svg + :alt: License + + +Detects + - ASCII, UTF-8, UTF-16 (2 variants), UTF-32 (4 variants) + - Big5, GB2312, EUC-TW, HZ-GB-2312, ISO-2022-CN (Traditional and Simplified Chinese) + - EUC-JP, SHIFT_JIS, CP932, ISO-2022-JP (Japanese) + - EUC-KR, ISO-2022-KR (Korean) + - KOI8-R, MacCyrillic, IBM855, IBM866, ISO-8859-5, windows-1251 (Cyrillic) + - ISO-8859-5, windows-1251 (Bulgarian) + - ISO-8859-1, windows-1252 (Western European languages) + - ISO-8859-7, windows-1253 (Greek) + - ISO-8859-8, windows-1255 (Visual and Logical Hebrew) + - TIS-620 (Thai) + +.. note:: + Our ISO-8859-2 and windows-1250 (Hungarian) probers have been temporarily + disabled until we can retrain the models. + +Requires Python 2.6, 2.7, or 3.3+. + +Installation +------------ + +Install from `PyPI `_:: + + pip install chardet + +Documentation +------------- + +For users, docs are now available at https://chardet.readthedocs.io/. + +Command-line Tool +----------------- + +chardet comes with a command-line script which reports on the encodings of one +or more files:: + + % chardetect somefile someotherfile + somefile: windows-1252 with confidence 0.5 + someotherfile: ascii with confidence 1.0 + +About +----- + +This is a continuation of Mark Pilgrim's excellent chardet. Previously, two +versions needed to be maintained: one that supported python 2.x and one that +supported python 3.x. We've recently merged with `Ian Cordasco `_'s +`charade `_ fork, so now we have one +coherent version that works for Python 2.6+. + +:maintainer: Dan Blanchard + + diff --git a/venv/Lib/site-packages/chardet-3.0.4.dist-info/RECORD b/venv/Lib/site-packages/chardet-3.0.4.dist-info/RECORD new file mode 100644 index 000000000..94aed0c2c --- /dev/null +++ b/venv/Lib/site-packages/chardet-3.0.4.dist-info/RECORD @@ -0,0 +1,91 @@ +../../Scripts/chardetect.exe,sha256=ppzfbkr-fZFrimgadK1tlo-rInIap9DTd1NT2LxyYSw,97237 +chardet-3.0.4.dist-info/DESCRIPTION.rst,sha256=PQ4sBsMyKFZkjC6QpmbpLn0UtCNyeb-ZqvCGEgyZMGk,2174 +chardet-3.0.4.dist-info/INSTALLER,sha256=zuuue4knoyJ-UwPPXg8fezS7VCrXJQrAP7zeNuwvFQg,4 +chardet-3.0.4.dist-info/METADATA,sha256=RV_2I4B1Z586DL8oVO5Kp7X5bUdQ5EuKAvNoAEF8wSw,3239 +chardet-3.0.4.dist-info/RECORD,, +chardet-3.0.4.dist-info/WHEEL,sha256=o2k-Qa-RMNIJmUdIc7KU6VWR_ErNRbWNlxDIpl7lm34,110 +chardet-3.0.4.dist-info/entry_points.txt,sha256=fAMmhu5eJ-zAJ-smfqQwRClQ3-nozOCmvJ6-E8lgGJo,60 +chardet-3.0.4.dist-info/metadata.json,sha256=0htbRM18ujyGZDdfowgAqj6Hq2eQtwzwyhaEveKntgo,1375 +chardet-3.0.4.dist-info/top_level.txt,sha256=AowzBbZy4x8EirABDdJSLJZMkJ_53iIag8xfKR6D7kI,8 +chardet/__init__.py,sha256=YsP5wQlsHJ2auF1RZJfypiSrCA7_bQiRm3ES_NI76-Y,1559 +chardet/__pycache__/__init__.cpython-36.pyc,, +chardet/__pycache__/big5freq.cpython-36.pyc,, +chardet/__pycache__/big5prober.cpython-36.pyc,, +chardet/__pycache__/chardistribution.cpython-36.pyc,, +chardet/__pycache__/charsetgroupprober.cpython-36.pyc,, +chardet/__pycache__/charsetprober.cpython-36.pyc,, +chardet/__pycache__/codingstatemachine.cpython-36.pyc,, +chardet/__pycache__/compat.cpython-36.pyc,, +chardet/__pycache__/cp949prober.cpython-36.pyc,, +chardet/__pycache__/enums.cpython-36.pyc,, +chardet/__pycache__/escprober.cpython-36.pyc,, +chardet/__pycache__/escsm.cpython-36.pyc,, +chardet/__pycache__/eucjpprober.cpython-36.pyc,, +chardet/__pycache__/euckrfreq.cpython-36.pyc,, +chardet/__pycache__/euckrprober.cpython-36.pyc,, +chardet/__pycache__/euctwfreq.cpython-36.pyc,, +chardet/__pycache__/euctwprober.cpython-36.pyc,, +chardet/__pycache__/gb2312freq.cpython-36.pyc,, +chardet/__pycache__/gb2312prober.cpython-36.pyc,, +chardet/__pycache__/hebrewprober.cpython-36.pyc,, +chardet/__pycache__/jisfreq.cpython-36.pyc,, +chardet/__pycache__/jpcntx.cpython-36.pyc,, +chardet/__pycache__/langbulgarianmodel.cpython-36.pyc,, +chardet/__pycache__/langcyrillicmodel.cpython-36.pyc,, +chardet/__pycache__/langgreekmodel.cpython-36.pyc,, +chardet/__pycache__/langhebrewmodel.cpython-36.pyc,, +chardet/__pycache__/langhungarianmodel.cpython-36.pyc,, +chardet/__pycache__/langthaimodel.cpython-36.pyc,, +chardet/__pycache__/langturkishmodel.cpython-36.pyc,, +chardet/__pycache__/latin1prober.cpython-36.pyc,, +chardet/__pycache__/mbcharsetprober.cpython-36.pyc,, +chardet/__pycache__/mbcsgroupprober.cpython-36.pyc,, +chardet/__pycache__/mbcssm.cpython-36.pyc,, +chardet/__pycache__/sbcharsetprober.cpython-36.pyc,, +chardet/__pycache__/sbcsgroupprober.cpython-36.pyc,, +chardet/__pycache__/sjisprober.cpython-36.pyc,, +chardet/__pycache__/universaldetector.cpython-36.pyc,, +chardet/__pycache__/utf8prober.cpython-36.pyc,, +chardet/__pycache__/version.cpython-36.pyc,, +chardet/big5freq.py,sha256=D_zK5GyzoVsRes0HkLJziltFQX0bKCLOrFe9_xDvO_8,31254 +chardet/big5prober.py,sha256=kBxHbdetBpPe7xrlb-e990iot64g_eGSLd32lB7_h3M,1757 +chardet/chardistribution.py,sha256=3woWS62KrGooKyqz4zQSnjFbJpa6V7g02daAibTwcl8,9411 +chardet/charsetgroupprober.py,sha256=6bDu8YIiRuScX4ca9Igb0U69TA2PGXXDej6Cc4_9kO4,3787 +chardet/charsetprober.py,sha256=KSmwJErjypyj0bRZmC5F5eM7c8YQgLYIjZXintZNstg,5110 +chardet/cli/__init__.py,sha256=AbpHGcgLb-kRsJGnwFEktk7uzpZOCcBY74-YBdrKVGs,1 +chardet/cli/__pycache__/__init__.cpython-36.pyc,, +chardet/cli/__pycache__/chardetect.cpython-36.pyc,, +chardet/cli/chardetect.py,sha256=YBO8L4mXo0WR6_-Fjh_8QxPBoEBNqB9oNxNrdc54AQs,2738 +chardet/codingstatemachine.py,sha256=VYp_6cyyki5sHgXDSZnXW4q1oelHc3cu9AyQTX7uug8,3590 +chardet/compat.py,sha256=PKTzHkSbtbHDqS9PyujMbX74q1a8mMpeQTDVsQhZMRw,1134 +chardet/cp949prober.py,sha256=TZ434QX8zzBsnUvL_8wm4AQVTZ2ZkqEEQL_lNw9f9ow,1855 +chardet/enums.py,sha256=Aimwdb9as1dJKZaFNUH2OhWIVBVd6ZkJJ_WK5sNY8cU,1661 +chardet/escprober.py,sha256=kkyqVg1Yw3DIOAMJ2bdlyQgUFQhuHAW8dUGskToNWSc,3950 +chardet/escsm.py,sha256=RuXlgNvTIDarndvllNCk5WZBIpdCxQ0kcd9EAuxUh84,10510 +chardet/eucjpprober.py,sha256=iD8Jdp0ISRjgjiVN7f0e8xGeQJ5GM2oeZ1dA8nbSeUw,3749 +chardet/euckrfreq.py,sha256=-7GdmvgWez4-eO4SuXpa7tBiDi5vRXQ8WvdFAzVaSfo,13546 +chardet/euckrprober.py,sha256=MqFMTQXxW4HbzIpZ9lKDHB3GN8SP4yiHenTmf8g_PxY,1748 +chardet/euctwfreq.py,sha256=No1WyduFOgB5VITUA7PLyC5oJRNzRyMbBxaKI1l16MA,31621 +chardet/euctwprober.py,sha256=13p6EP4yRaxqnP4iHtxHOJ6R2zxHq1_m8hTRjzVZ95c,1747 +chardet/gb2312freq.py,sha256=JX8lsweKLmnCwmk8UHEQsLgkr_rP_kEbvivC4qPOrlc,20715 +chardet/gb2312prober.py,sha256=gGvIWi9WhDjE-xQXHvNIyrnLvEbMAYgyUSZ65HUfylw,1754 +chardet/hebrewprober.py,sha256=c3SZ-K7hvyzGY6JRAZxJgwJ_sUS9k0WYkvMY00YBYFo,13838 +chardet/jisfreq.py,sha256=vpmJv2Bu0J8gnMVRPHMFefTRvo_ha1mryLig8CBwgOg,25777 +chardet/jpcntx.py,sha256=PYlNqRUQT8LM3cT5FmHGP0iiscFlTWED92MALvBungo,19643 +chardet/langbulgarianmodel.py,sha256=1HqQS9Pbtnj1xQgxitJMvw8X6kKr5OockNCZWfEQrPE,12839 +chardet/langcyrillicmodel.py,sha256=LODajvsetH87yYDDQKA2CULXUH87tI223dhfjh9Zx9c,17948 +chardet/langgreekmodel.py,sha256=8YAW7bU8YwSJap0kIJSbPMw1BEqzGjWzqcqf0WgUKAA,12688 +chardet/langhebrewmodel.py,sha256=JSnqmE5E62tDLTPTvLpQsg5gOMO4PbdWRvV7Avkc0HA,11345 +chardet/langhungarianmodel.py,sha256=RhapYSG5l0ZaO-VV4Fan5sW0WRGQqhwBM61yx3yxyOA,12592 +chardet/langthaimodel.py,sha256=8l0173Gu_W6G8mxmQOTEF4ls2YdE7FxWf3QkSxEGXJQ,11290 +chardet/langturkishmodel.py,sha256=W22eRNJsqI6uWAfwXSKVWWnCerYqrI8dZQTm_M0lRFk,11102 +chardet/latin1prober.py,sha256=S2IoORhFk39FEFOlSFWtgVybRiP6h7BlLldHVclNkU8,5370 +chardet/mbcharsetprober.py,sha256=AR95eFH9vuqSfvLQZN-L5ijea25NOBCoXqw8s5O9xLQ,3413 +chardet/mbcsgroupprober.py,sha256=h6TRnnYq2OxG1WdD5JOyxcdVpn7dG0q-vB8nWr5mbh4,2012 +chardet/mbcssm.py,sha256=SY32wVIF3HzcjY3BaEspy9metbNSKxIIB0RKPn7tjpI,25481 +chardet/sbcharsetprober.py,sha256=LDSpCldDCFlYwUkGkwD2oFxLlPWIWXT09akH_2PiY74,5657 +chardet/sbcsgroupprober.py,sha256=1IprcCB_k1qfmnxGC6MBbxELlKqD3scW6S8YIwdeyXA,3546 +chardet/sjisprober.py,sha256=IIt-lZj0WJqK4rmUZzKZP4GJlE8KUEtFYVuY96ek5MQ,3774 +chardet/universaldetector.py,sha256=qL0174lSZE442eB21nnktT9_VcAye07laFWUeUrjttY,12485 +chardet/utf8prober.py,sha256=IdD8v3zWOsB8OLiyPi-y_fqwipRFxV9Nc1eKBLSuIEw,2766 +chardet/version.py,sha256=sp3B08mrDXB-pf3K9fqJ_zeDHOCLC8RrngQyDFap_7g,242 diff --git a/venv/Lib/site-packages/chardet-3.0.4.dist-info/WHEEL b/venv/Lib/site-packages/chardet-3.0.4.dist-info/WHEEL new file mode 100644 index 000000000..8b6dd1b5a --- /dev/null +++ b/venv/Lib/site-packages/chardet-3.0.4.dist-info/WHEEL @@ -0,0 +1,6 @@ +Wheel-Version: 1.0 +Generator: bdist_wheel (0.29.0) +Root-Is-Purelib: true +Tag: py2-none-any +Tag: py3-none-any + diff --git a/venv/Lib/site-packages/chardet-3.0.4.dist-info/entry_points.txt b/venv/Lib/site-packages/chardet-3.0.4.dist-info/entry_points.txt new file mode 100644 index 000000000..a884269e7 --- /dev/null +++ b/venv/Lib/site-packages/chardet-3.0.4.dist-info/entry_points.txt @@ -0,0 +1,3 @@ +[console_scripts] +chardetect = chardet.cli.chardetect:main + diff --git a/venv/Lib/site-packages/chardet-3.0.4.dist-info/metadata.json b/venv/Lib/site-packages/chardet-3.0.4.dist-info/metadata.json new file mode 100644 index 000000000..8cdf02560 --- /dev/null +++ b/venv/Lib/site-packages/chardet-3.0.4.dist-info/metadata.json @@ -0,0 +1 @@ +{"classifiers": ["Development Status :: 4 - Beta", "Intended Audience :: Developers", "License :: OSI Approved :: GNU Library or Lesser General Public License (LGPL)", "Operating System :: OS Independent", "Programming Language :: Python", "Programming Language :: Python :: 2", "Programming Language :: Python :: 2.6", "Programming Language :: Python :: 2.7", "Programming Language :: Python :: 3", "Programming Language :: Python :: 3.3", "Programming Language :: Python :: 3.4", "Programming Language :: Python :: 3.5", "Programming Language :: Python :: 3.6", "Topic :: Software Development :: Libraries :: Python Modules", "Topic :: Text Processing :: Linguistic"], "extensions": {"python.commands": {"wrap_console": {"chardetect": "chardet.cli.chardetect:main"}}, "python.details": {"contacts": [{"email": "dan.blanchard@gmail.com", "name": "Daniel Blanchard", "role": "author"}], "document_names": {"description": "DESCRIPTION.rst"}, "project_urls": {"Home": "https://github.com/chardet/chardet"}}, "python.exports": {"console_scripts": {"chardetect": "chardet.cli.chardetect:main"}}}, "generator": "bdist_wheel (0.29.0)", "keywords": ["encoding", "i18n", "xml"], "license": "LGPL", "metadata_version": "2.0", "name": "chardet", "summary": "Universal encoding detector for Python 2 and 3", "test_requires": [{"requires": ["hypothesis", "pytest"]}], "version": "3.0.4"} \ No newline at end of file diff --git a/venv/Lib/site-packages/chardet-3.0.4.dist-info/top_level.txt b/venv/Lib/site-packages/chardet-3.0.4.dist-info/top_level.txt new file mode 100644 index 000000000..79236f25c --- /dev/null +++ b/venv/Lib/site-packages/chardet-3.0.4.dist-info/top_level.txt @@ -0,0 +1 @@ +chardet diff --git a/venv/Lib/site-packages/requests/packages/chardet/__init__.py b/venv/Lib/site-packages/chardet/__init__.py similarity index 55% rename from venv/Lib/site-packages/requests/packages/chardet/__init__.py rename to venv/Lib/site-packages/chardet/__init__.py index 82c2a48d2..0f9f820ef 100644 --- a/venv/Lib/site-packages/requests/packages/chardet/__init__.py +++ b/venv/Lib/site-packages/chardet/__init__.py @@ -15,18 +15,25 @@ # 02110-1301 USA ######################### END LICENSE BLOCK ######################### -__version__ = "2.3.0" -from sys import version_info + +from .compat import PY2, PY3 +from .universaldetector import UniversalDetector +from .version import __version__, VERSION -def detect(aBuf): - if ((version_info < (3, 0) and isinstance(aBuf, unicode)) or - (version_info >= (3, 0) and not isinstance(aBuf, bytes))): - raise ValueError('Expected a bytes object, not a unicode object') +def detect(byte_str): + """ + Detect the encoding of the given byte string. - from . import universaldetector - u = universaldetector.UniversalDetector() - u.reset() - u.feed(aBuf) - u.close() - return u.result + :param byte_str: The byte sequence to examine. + :type byte_str: ``bytes`` or ``bytearray`` + """ + if not isinstance(byte_str, bytearray): + if not isinstance(byte_str, bytes): + raise TypeError('Expected object of type bytes or bytearray, got: ' + '{0}'.format(type(byte_str))) + else: + byte_str = bytearray(byte_str) + detector = UniversalDetector() + detector.feed(byte_str) + return detector.close() diff --git a/venv/Lib/site-packages/chardet/__pycache__/__init__.cpython-36.pyc b/venv/Lib/site-packages/chardet/__pycache__/__init__.cpython-36.pyc new file mode 100644 index 0000000000000000000000000000000000000000..8fa125032152458db27a255f3a01f78e53633be6 GIT binary patch literal 894 zcmYjQO>fjN5Vf<}Bn=d8;Q&V;S&5c@9m)zJBv=U~R1hsltSn`{i8q@zv4ia`-O^sz z{tphE_)ETW;xBMwoU~9!9?jVAji1Mpoz>NNm|rIM1B8B|8^Z(tIZV9=CPNu6QH4ji z@4YlRd^V#ANa_Xn@v?x&9JhEwCid;wFx0%OoQGI;6f&BpVCQghb{FGIN;2SN?Eb12XpGC%F zN7Calk?Ja7O0mUw+;Glzho?1^if2Slj=*WOUFXq`tiEpIv2$ksgCIaB$8dKdBwHiifqx8=etj~wrQ=T zyB9s-vmz}yVZs#a@ETJ?rVOg6cq(&I7-$fp7eKB6Do*H|VnTIc_$W=KRlBOLgTn8Fnj}p@ZkW3+NA$Fk*}UY>+%ei=d-yi)b^ZcZGy~ND literal 0 HcmV?d00001 diff --git a/venv/Lib/site-packages/chardet/__pycache__/big5freq.cpython-36.pyc b/venv/Lib/site-packages/chardet/__pycache__/big5freq.cpython-36.pyc new file mode 100644 index 0000000000000000000000000000000000000000..53ba5b2e9c7ea36f07d197ea96781f10649ba8bd GIT binary patch literal 54781 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 literal 0 HcmV?d00001 diff --git a/venv/Lib/site-packages/chardet/__pycache__/big5prober.cpython-36.pyc b/venv/Lib/site-packages/chardet/__pycache__/big5prober.cpython-36.pyc new file mode 100644 index 0000000000000000000000000000000000000000..2f39adf3a265f2f6afa1663a564c4f31ae52b95c GIT binary patch literal 1170 zcmah|%Wl&^6rJ%SaigR_D;^6L5v(H7qC&d>Ap}jU3aKeb*;$rGj^`$E>qnRw7p3Yh zk@_7h`6WxNSn&(2xYurJ*uYpbb3E5`ALkyw>~va(lco6HVC)B584luiIQ0Q8l1ZMh zl>3|$wh}9~eY?VT;-s$cR@g}zY140VcEqGB8%rh|z!$df$>xytyq_Fh^?3PUP$VYa zpBv~;Lp22RN#!F@XxZrJGR`JL6B-zV(KOBgPao~alf8pj8x@ZV6X)6cEKKG))@bYO ze>mC`!+{ulJUBd#FuG?J|(w5GWEx7L@t};g4xMB|T zDdT3@qR@4E5oJ$0lI^VjAQbNEM$$AVHs*d=?a0{3Tas!5l)>-3>IPpbe<*P7uLl z_tnmeV5ag@h)i$}(>O|?8)hcnGE*3v?l_E~t02lJm^}8RtLJz*#ZR;I;5Z%yIySI1 z3!}4e0y>DW(-O?{5%P&%vEAFVx$>~Mr#LkM#@Bg^d;DVamh|l#a{gkUI?$(UM2_Uh zs&!I2bW5${Nsp^GZWXSVJNR0*DF@_BWMK+DJkb^|%({5E5^wdJ|Ho|hNutQ{Kf-!R zm`w^KVQVGiYKb@Yo<~}s?2ynYp@$UezWpW#_v2 z5hMw!iBh`Bt3#Mbs3i9UfhO&FyxnL!)fuVsPCB|SzwVGCe#(tni<6kiYM#ZYyj$Ms8 zv1;6jE16kIRFh7!nsQRrE~iV$tV(ya$LXo|I=$6Cr%%c3O1j$b^j8O*f$E?$sB3pL z5fkxEO~k#S=caQEd_p9_C%t3fhry>r7x*s4kAUwMJ>Yv3KMKBA^nveF{22JO=m+1g z_~YOQ#31-V#h(yEbK3Z^EgjPvH^b5CM^p3Pcc<=7%YIn{@=IUc`DbJ3t8Z?UemKPH z=8Y{AHWUdKK77-1$uTo9uB%iSm6eB zcTsvz+`1H=47=Q*uu$<_zufS`{5 z#+IJ%1><^X`Ceu5H<~;FQ~&+z;`RKh?@2$uPzY9+@=zjV`Kgx|p1&N_SMsa1^0T^J z&aZg|nRzSkdsWX5Jej$iFM6f7-o1P!zas08y<(7m>MfOv6)#h$1?3CDlD8OS77Il$ zBfVn1R4dc38Gj9ftLR#Ln!jIO$ou8MyRcFyE*DCkpQoY13*J=kwmDv0Sql@cTZR(X zy+}9rf@o$;kJ%{d*EloPVG%EGk34wAhM`I5YQ+ptU62~W#JX6G)5>X>67k^4H!_$Y z{7|T^W&EHJc(=D`NOs(mR3k@7MnT4Pd7O3nI3g!m8w2?O#gBn#7A!X!r#jlLzFj2N z_%H^uu3+{tD(is%vLS~6C2d`Qu5Xw%OT;$JbyJwjwwzzbkjI$LJ3yzaubb#+ENgOJ zSg4`bn6_*+ds)q1masAHc;oD%=ZQ=q!-Xgmx!ljn!BS?qR)1E@RJ>X#SlS}wC9yA0 zft0xgvRnVbGj4~;k{3h>j$AUtZi6JsIhJxxXi$SzQ@M^&SLcxbK0e~*3%gPvuS$P&A8wzDPMSkI34Fih17RnK+9l){6A3;gOcMeR8TdG zQXOakcE@w$vB4AlP~o-*?@}H_9W*hv@4kKs3OdnW1sE;{&f@wW;7N7qYO&{fs2u<<|tdZ}MC@9#hsjS0v8(}HV z8UtwyOVOlv_7#Wz1Z6*p4mSKKQS^ISdyPaVd7C6dvKK}2oo#8`e&A|s zz(;;}*O%bN9njGAoBUu4G?W|~G{>V0%#otzJVMC{JPfbzHhage#0X4>u);0_r?Qkwd7(X0zI3E8qm}FkkL5zf>|CGQe2mx@{27Mt)pH9>4 z0pvbrzhR?swxbUY3pTFVZ~4s@*eE$X*yiv*$B}|<5@tqV9@;8adhzQ(^(RRW+#0r;;A?T^N5{_LW=(DHWd>n!;Fp zfqx*X`)YI*RA>12&?Z$HCAy`8&dw%OHC|Q1#QV`b`$KX*|A!kgnm;Q&lO9yR;q=&l E0q`9olmGw# literal 0 HcmV?d00001 diff --git a/venv/Lib/site-packages/chardet/__pycache__/charsetgroupprober.cpython-36.pyc b/venv/Lib/site-packages/chardet/__pycache__/charsetgroupprober.cpython-36.pyc new file mode 100644 index 0000000000000000000000000000000000000000..1de2f280e17bb521858143bd2115eb8be6b6ded9 GIT binary patch literal 2277 zcmb_dOOG2x5bmC7kH=nn6PC>bh=hZJz!3=wtOP-j1mz_pa8MpZvIe!h)9qP%?eT8+ zIP98P3CSzv#Ek=gA(#9S{=wW3r<}NR;;SBKcL~dlv8$%Kr>DEBzOQONZZ_+;lYRNy zGGl+RBbR`E17bgbQcUp?8}lybWP2lT?00?6?lR>ovCovy{@m{hRe8YL!3&O8+Pr9d zYbNW1G2l@6JycAMW@ka??Y+U<%)GZwfvOzx$>01U+enL#tHjj zSLligRCS-tc{hL^s+zN_s;-vySvOP-)x^E_lnK_Y!>1F)%Hr_5W-{F>J?O-qJCrfH z`wOw}!^l|1b2j&eUd|Q&nZovRCjEp#3q`u37&i7h2yAK8OB2~2j52Lr(3b6>sMzV2 zHiiN#LMaF7Ad|9KlD#+^Jkc_pj*IG+ON1>}u94DqGn;Hh({%8|#B4^px@THzk=0}DuTASp z6zgQ|>XnZooHEpL7Cq4$gLtG{y)+wK$~JUAYxR4vZW$d<68Jorq%FIPm&aI|K8d~_ ztVec`=}TL^c(a#i8^r)s>Fh(gTb(78-!g{FTe~KN`{yB+48~V@fZyz`e}i%PWsYKE z4_yQbrH_EI9jHT4<_v%UAnEU1&e>4hV&7lb<2g6yaz6CjQvfF`IW`#j%KrqLNq_s? zW3U%*1r9pVF#&dcXdGRuriwv{SH);VVrn!|hbn>+HM4|4+cOO}w*ZQpCapvLFmr;` zNvQWAmJG(15paVG9^$^jXJ?NI-5qxjH@QP{6JlFXh>+Q{(3~PGM-%~BLk}e6owo0M zE0z4-Zda(N)N+9v(-dms=gwHc^PgrSm5kJ3Ev(P$u2;a?h@8hq*W8_Dy#O zZRUK>&wYClV?XnUV$(A>a;kpNX&4~wG+V`N2nu=Gul91v0Zl*D1%nCLzXGuAf51~Gdxi2C10u*z!^gv6G*FjLyRGp-kp+m^* z%rPV&ClA1<{zPTu()%k61j(otGgKmyw5m8#Mk61icNF-l{5{Xrq1cJAx&kQfyOdws zUd#PqV86p`6=@V0)#e^&ZoWQedt&jVLQfz|xtI&ogqMp=X4Y~6NPQ$-Y_GX=3;T=m zaXwW^&`F-({e8Cj{LkyjkE>+vUr*q$yJpRIZ7ZE*t+LW*r!d6-u#{R~VBBt$X(fcr z8B%YMqPB1Z#b7i^5^ai#((BX2P<=U`8{%=hQWhb>Q`B7Fr$ZcOg>dF8pizlDg4l~t z%mE|-jli$$ECk_6z!&n<5PB9s&(0qM-9Os{HI60vI#GAP*QqY$c%r5wvKvxvPkW>C ziEHDou@xcO9zJZ@ZW$MaWQbN}B{vtJsaTIjQXbL|h3&eeYmiipEr_K)8uI0!QE!Be xFkE%rx6`f^6^-wsEeoN!=s9J(HS{%b>kcO^gBrZy{|%rq{wM$d literal 0 HcmV?d00001 diff --git a/venv/Lib/site-packages/chardet/__pycache__/charsetprober.cpython-36.pyc b/venv/Lib/site-packages/chardet/__pycache__/charsetprober.cpython-36.pyc new file mode 100644 index 0000000000000000000000000000000000000000..07ee4db2ebfdd64f07764fa1fdc8b55eab89c1a5 GIT binary patch literal 3503 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 byq5Q=Zn^n&phfs&>GDtHiXjuB-wgf*j?N*` literal 0 HcmV?d00001 diff --git a/venv/Lib/site-packages/chardet/__pycache__/compat.cpython-36.pyc b/venv/Lib/site-packages/chardet/__pycache__/compat.cpython-36.pyc new file mode 100644 index 0000000000000000000000000000000000000000..983fa18646bc61a83ac42fce1cd593eef0d777e4 GIT binary patch literal 410 zcmYk1yH3L}6o#Ek+q7yIgqSnZp`czC5JD_4A%p}Ak)_JDPZGC{9oZ*=?7RjKz$;~C z>MJnez=AD*KKhUK>3BJrjBc~{wF(LOBL7z4>Kk`#2SJ3lCkX+v^+az+%&75Uq4IW<>9hR<%rX5sDaxI{ZHq64hi-rhqxW=Z0wzp{z>?bkfPTJx7gJ06hIwRdM zta7Rq2qSBt0_+ZTNuBUjn;mU{nRrDl6kridJf|G8)x~^4OQW~Ik=Bq)zK578lrzjB z#W-agVgp=fN}`)Nb{{|}+*4K4d%2-jBFsw0cPs--dCrUgJmQ)-Rmi0X@k%QWZ3-gdvRcV<){|u0eFWQEl&ZHx z>i^)zU)n1t{sJe)yDg*_@XGe*u{|^X=G*73*6RLv!Cp5A`9YSNgZK@0wTFWsf+i%T z0i_08iIv)cU12+MQa5lb>?B^=2pW{UC&Crpf(Q@XxgGeTF(4iPCq-8sT0YqS+&lQR z7b`8}VWHzZdzbKKOncILQduJ+~x=f*iX_RWqU=#(CH zR!UbDQ;^cb%caj)oW+_kX&g$|*jA#72c}YKne|<<#24d+urrXQD?x!q9vlV92Uxvv4Z&V~BKk3X?cWpv^NKZ|Vt*bbG`jXiJFlF(!{yY^xbwPVs1V8Xm^OP{kTH zr#w30V^Cp)l@p-1qbU{)-D3T=rZef|>mFlQ1`xVNS8bo3-C3f2>x!Oh{F@r|%sr!2 zL6KMMsC27qat%!#Dw{Y}xE|JVSvE}?NEyp`3Qy3Y486oUyT2T9`OyEPdIz}#p8YGV zpYUv4AP?J1A+J61>OjXgdNA2BR<1IZ=AuXpZZh_z;7Pqx(N_9MBdSQxh?mOzR)Bl54r1 q4ln7diz-b)N)N3H#cRY|x&E6;jjC$+FYD*MdT5d{3TV>mvws8pVJGbX literal 0 HcmV?d00001 diff --git a/venv/Lib/site-packages/chardet/__pycache__/enums.cpython-36.pyc b/venv/Lib/site-packages/chardet/__pycache__/enums.cpython-36.pyc new file mode 100644 index 0000000000000000000000000000000000000000..10f3c1f81d920b88165d86bd964e4e8453247a5e GIT binary patch literal 2668 zcmbVO+iu%N5T$Mu#n`#Hk1fyzdO-y=Dw5`kHh9nn_Ab?tNR}y22RCY-R z640mQGx`JlgMJHN`=np!eP$*3(l|yE3NzZ-9q!J~oSEUb+uNo!e(nCOYufMHr6&*L zJs>#&#8KFdmZ` z^-k%SS4?x4Ch;T^yQD!wQVVFPRLED1hLzz)+#64+A5^?(S~fkn;rWw+(H@Ze1Q^$P z8Mu3vWqLW5?d4gnS77;`&I(|wo|<+zOX5yUW4`E^1fK51mxP1WMDUs5l7}(c&k6HK zBQ8KB64fQ4Bnka9E+h>I*w4K<62t?Ghn)CfMeVi(6SO5-w9Eo?%Ei=h-H=YX>!zmb zP9v5CINoyI7YPm4D@E63k%ubBCvD5EcIvjBmaI;FGkjtnJaKE!y4J6n*n*7}`{NgH zw+|i`vOlD8GU-PlX97&@GcHf#Xx0aVUq<4zKj&1CM}5hsT*h3G2Yru^AAR@WVSgr~ z=Wvt$8K3xGzzGdw|2|xQ6q6D4I5@?N#-ShkQAp$*UY>$#c-C+F!@l%met#WB*0$roC@ljr60< zT(@0q*j>BjRGX>sw0c}c%~U^ZwXLd?7M+&k)}J1xxoWeS7S}JOIheYD$ZE8W=iLT& z4@m9+GxDo&Y`Bq8>sJEvK6$luETW+wj#rs=@UCt@&n$r95ODdwY!Zl#3&%n>UF*bB z!|Gb~uI(J8#(wL>X}ESb)ty$?J+iKK#mBHM0lJDzoc(YI98quLhkWG#=e-@EJVB=g$fr1wzmYhX8}CO4SQim$a-nOOc~6lVzY-WEZ=;g2#yn6i#MH9dGigYY+j3Z!?6yk zUHeBXHBOwSeP}hGrTY5cIBs>IX29AlFQ8IRIdoPgzJy~h*{E8GstTXM!b2d5Q=1|U zRUs>I#REEj(1&|K@^fG}p$07bxS^O)mFlE+wxxEKrw^!W<}Vff+*J~goASHpP>xjH5Rm+D(3B=wflZMT{P zz6HD}ls<#b&j0QLRDO!eQkI!@v1oU*ZMBYHH%F0PuZD&zu-nZSfr daa7vZ9grH2SDz$5V0TidK{8 literal 0 HcmV?d00001 diff --git a/venv/Lib/site-packages/chardet/__pycache__/escprober.cpython-36.pyc b/venv/Lib/site-packages/chardet/__pycache__/escprober.cpython-36.pyc new file mode 100644 index 0000000000000000000000000000000000000000..0eff5b93ac129b769e52e77d78ab5f02e0ff6dd2 GIT binary patch literal 2659 zcma)7UvC>l5Z}E!pU?K$NkbY^pyCJ;k`XO5^Z_aatrDkA+c;GmC^{J}m)o^{j(tvc z&utR95|SfTLPA13@z_^h`U&_X_l9`t6Yo4RvuC>vsStPCxw)O$KQr^2nNQ2*Vy%73 z;yFV8B(FRc@Hb(oZ-H>aX^-@&Pbu<7&*+=Jsd=+!^>co%Z~JyX@8|WL)pPm*Mu7Ud?lP7A)Jc{JGZbHe6% z?wpb__4B|Ncv15XFLC#j_yu0(75EmP5{vjHaLar;UsK^3mz?}w^x)a;M9MoO@Pu-6lwP+@Q&JXo$eQ7iG3I2^)qJWC2t?L~rngV;+3daHN%fc!+3n6!uNYaIu zQ+Qp>lhkGkQz*?z2uo5mQcHEHQtbsD7*D-J$qkXVO_mq^6eAFUu-*2#CvPw0p$ z?{JC3msum)HBf%I^pGSu)ENVQnXQqN*VLKdX17|9W!PBbL@px-WflUP#WFQ}B9@Cd zeG$nLkg6dsA&+`hD&Io>Z6s*1-r@!@Y5@qL6|mW&hW3IB^knIr)jH}klhJe>YcP}z z1g?(|rvPz%2l(jY^^vo4Q+I+e76*M%!^JwCjg!mg4t!Pf|DCJNe*L-56vmscoOwR9 zQ?1vZhrU8PWs%bcG%pxvvsrIHzx~I_;`6`0YJ-M;{@V+cwn!lP;uhArP;9{x?L-2u zw~Ui_&-vo4{;UM%U?C12g=fGV{W_umw4a|CM?d0Cf&bx&IWk=c^vLW|m&gwekuyfd zm_D&aR$_LoeM5Etk|qQAS)`le#%F+OhLFs0bDzpz61$rRXgV-cXb{)|*A-#i0!T_) zVs_mz7Qr&?UV-o2RQDk{v>&41U}e>+Z%D+=3mDLyG&<#F;L~C(j*_gzNCZ@xtL^M; z?_{V(BU8J+z00<0@=Yzxijlp!+km;$+1UQNzRosx)8))p*qgH5SU+p}S!#H&ILnWm z259Q+9Vbu>6PeO5ODcC-e6ieRIr9?0R!a!pfKAj25JHQPITgs9BD^+mMe4wd6i3B4 zxp*#^xC17Niv=I^01AGQvHpM$d&s+t9S(!uM3QHW4?@Ot$oE8C{|JZNdhoP_#IyuXz%)2GmaxKT!HKtyzq~%ElW>r&S zqNWRzu8*#n`W1UmniKJ`uXLl57_CVRg$kjE%^H(#N4gDVm27som!&CnzQ{cBC0MH-utVwQsKD2x!{lI zxL1reKgT(aaD*RlLtf;0j@%Vvz`u{PJ3$1uhm<{nqY-zKjYZv_tgTNROnZ!^5QX67 zjJhp}hiMnr)@S|Dv-?aG$UQLyF@`2Uilj+~WIqaGn*1PUP}=q%?S=FLwCCS>U& z$ENy@_sqg{g!NH6NMqD?{IlZ`^cT7jGKlTT#k;S>EV(b{AVYGHg&fJdS;>Z~g~)t4+3_Oso*}(}cb>H%{~{ff^lV3n+qqCJ<^$WLOCNk?ZbXfxRNe42euWuoJ@GcuJ4#ORG7UT7|NABiQhA+AG_ z&8QNrlM-3C{k}u)w7AO86SmB`3QzL~veH*IXj!ra6RZQ11U5-*V%V@Uz)b|!{F&Vq zt8ZRcYtOf8G_`|TCR7BPQwFkWb}adL05tCqU0JbogXTWMbe+H3tgU9 zQzY?|aemO(&Gn1HLeu&E7`Nx&vT?r~%S7C8A}X1=D#BIPO#fYf<7%C&W)>q#cZk^h z^HKR#8k=C4(y?rf`;x8!G1OC#2$(09K9a_o`aw5Nq%)9>@(am?A($2zDJ#%vW>7zC!spJE*?Il}K#zWqy;t$F5)E giCB#HuJn~4BX*hJVE4moK}T$~a6R~&3_I-izm^N9Jpcdz literal 0 HcmV?d00001 diff --git a/venv/Lib/site-packages/chardet/__pycache__/eucjpprober.cpython-36.pyc b/venv/Lib/site-packages/chardet/__pycache__/eucjpprober.cpython-36.pyc new file mode 100644 index 0000000000000000000000000000000000000000..3b4aa70ec64760611f7474e646e58027a7ae5596 GIT binary patch literal 2463 zcmai0TW=dh6rS0e*N*MD=`E=cG7?2HqNRlj0jdziF}hxU=Ju zSniX9`pR!W;(<4Q&phzLQ(yQ2yudlLPUIji-ptIIGnaGbT)vYJYqd&ec*=gN6Y?8b z`Z+*<4lVx{I!-u^NkaQHvHBLpxfR=q({~JQ$8O^FJwrQjDe?Qhq20KgRQeS|d+|zA z?N=#zNO+0+r-b{$ncMvuFYl37lI!pd4Z<7dYfhk(1$dDecivl-<|M*9;LW$A-7h)?n;hs7&qv7Mz# z9IGXM-SFAo7Ten1>^u!YvGbq3pz<9c1nE;w`qnFQKsn{sso%E^ZF2``N4VVO-YJ>W zz6Z2@_xTF1!dQMq9MZ3V6>56L$Sz(LqDkeNmf;fZGZv+hVobU)l|J&yp)n)N z6Y1gnDqpf43($B|IA6lGMp&5coUL6ca-qPqPA=jD7|V=>aggVX{Y?J&G5mBe$%V`Z z`+=Gq4zg5m8NCn#F7hLljR%u7`Yw}4gA)QWf1&hvGmr4}wrMr3kYjya^oL%unEO0$bA;gQwB{Adi%|H4eg~U?}oI z2=T*(dS6V!(HO3UD7rm9kt^`9o6zzKbcEJvh5GPKi&!cAa{J6~|LmYQ;NV3Efg9|? zRcDTHB;Ie_AXkxs>;n(UMloDM)*5z~vBMqjLCY~GQK{*rr7*c|jDA5E44C%W0ZzgB zR(I;bnOjeG%)JXyg^Y7Sx{6i-53)2!#2viAf{s|z^<{a>oBmg<_MZgfAceU2FTs8s zq{9g~2BZ5-=mndfZ3vA>JE8cH+yTamjkzcfx8M^;K1FDIeF>K zEN%hkml+_y2BhEU61VT;xHh_svzapo#02Wf@*E@-J3u>buM_OAlkf3{<^BJ%`n>)X z0eQ|so@L}+1x>FVSwB#D$J~8=P8Re!!og_c$iey9dw_ElBE#)Y-@2JM;jhSo=3%6o zkm8wa2CBIaPz!6X!O%ovSiSxeeytmj>fkY_gZj?`XvyT`UV+AB_K?{RMr=l+-5&$^rJaZkH@y$8EJeR&9B z8BU}WDU1-NAXrxzfJ-qo8Kj*90hm%V;*Bc0yxHk>+P%l!hkA9GDJIfvGCX8FP=T(S zJG1m4;vx-&UfX-Lz1wR)>#^RW-40BiZnj*LliEi^fR0kr2-0K$lBP!as0~9qm_$0y zCixDi@i8<5*@UiH4TC0iz!S$%*dxBwX#-Z*sYlmo#j0C%S_O`8O&iN;hfh0CH?%M| z6a8-j0p27d3h{_BZ5hf^Cidr60sf9Lk$e|67Z$RU;J9TM?}I0qGRR;&(A5R%o7vx= zg%^AcEywI5<_Xgq%ZgsKDij?kGzch+fx}pm@kxwym9giOATCx6@EV}gKExr^D0Q+F zD`-lixvniLN+{wOD%ZKm0nrR<8o28eD+^z1ztx0 literal 0 HcmV?d00001 diff --git a/venv/Lib/site-packages/chardet/__pycache__/euckrfreq.cpython-36.pyc b/venv/Lib/site-packages/chardet/__pycache__/euckrfreq.cpython-36.pyc new file mode 100644 index 0000000000000000000000000000000000000000..6c702a14bb1ef84b982b322bbb4576aa87b50890 GIT binary patch literal 24167 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 r&lN-QbOh{?}O zO)1JOON~iMEzT~xD delta 6752 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 literal 0 HcmV?d00001 diff --git a/venv/Lib/site-packages/requests/packages/chardet/__pycache__/gb2312freq.cpython-36.pyc b/venv/Lib/site-packages/chardet/__pycache__/gb2312freq.cpython-36.pyc similarity index 54% rename from venv/Lib/site-packages/requests/packages/chardet/__pycache__/gb2312freq.cpython-36.pyc rename to venv/Lib/site-packages/chardet/__pycache__/gb2312freq.cpython-36.pyc index eef1c1baf4a4e1636bd679d9203c884d3ab84003..8727d8a6c61fa8a17cefc68aa61ff133b9b426ef 100644 GIT binary patch delta 277 zcmZ2Di)FzYCQoBtUM|=4miX5J3=EGMkiZ5$1_lQpzgPrFq%cG=q%cM?PT)(~9K{4A zHw80jYyqlBKYIoQ-q>eu^epk@^wR)oD`I5WT+@>4Iei@mqecBKNp~kBV?(2OXAj4q z_z?eiw;f?5*PxXQMIb}K#IJ?PRxzc;sYS&xNr@$;88P{JsVPO7WvMYKsm0kP z`2{hhd70(;McFZxsfk4jCNagSxv9k^sYMEgG0CavCYFXqF$G2WS*gh-F=eS4naMe+ z3W<3onUcCC8L4R{3TcVSsR~7@$@%GdnI)O|c?!kTt2h~Dr?2E>RAIWoxcxjQ<1I!2 D&)1g-xr6<-zXYRxP}QLNp{j-&6}x_* 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 U|Koq%Um()|x>xl7#DD4k0bv{n_5c6? diff --git a/venv/Lib/site-packages/chardet/__pycache__/gb2312prober.cpython-36.pyc b/venv/Lib/site-packages/chardet/__pycache__/gb2312prober.cpython-36.pyc new file mode 100644 index 0000000000000000000000000000000000000000..71361390f335bf714fea58b3a5cd4014214dad81 GIT binary patch literal 1186 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 JU*N*X4gdi=P_qC4 literal 84113 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 *)MVFRV>2y|`MC z)oA18;c7J;pPy`BT)nil@ult2`PIwAwb9X!td55lhU3X_bo7I(>%+4j`S=Gvw0d#0 zeQvluS$%o<;>P;s@aWpsWaE947l&siN6)OS508$9>)U6yHYOX}TSv#2OY?;S-FkWT z>5Ugw#~YL3`!24npI$HX1GA%u+(K23VNkA3v5OqU;_@iYk%NBh#($TuV|zyX zOJ;iS^7GFOPChm`{>bSQkDq+*^P_tL7cxf&!yGE+Sa)<^__5tHb2z+vi@9FD$3avU z)jPCM7PfHZp?OQ<_}1gH#aG& zZiyDE?wdPb?H%b{@2>W)^{*|K+~UVN*Gi=z`=igq&$q-*blHQ2mkwX;SBvKtMt@N_ z7OFinuirV>uX-OV_j(W)mP=c@zs8Pro{jl?CVQjfNat$*NRfG@6ZnPBr%D_<{L{vZcg`|9Zm*Z=h?=x`}aTd$ma&nop^e1`ibXGoOWHjAZ9+W{u<7szex;T4GmUx6Vhg<2S zru{SJLHkBw7#}Sr?q7f3p6>qcTf0l;&;IUG?{N1}_dv<_x^M4ZdHcKr44U@)7#F7O z7bkbVKYR3hvm5rniRF{eKmNq6%WS_=(|gZuPX@!S?Mr8098_zQweJ+#aqMrWd*waz zRHdF<1jc3Kg8f`^6gYa)TsrHmc#)`tUD{m~q_yPVYeX!QPd3&t2Lr zZR_krblv=BW%0JIit1ziWo{w&?^thk4P*V>hLYeJK2j%kJjf50Ts(mFPQP_L2uKTu5l z+4@@NOt-0M-d&{owoxbVRQ%{~spPRQ` zvKTUcOEHtqq`ZT#_s;eB7@WP2hIv86X}Qu(yoHyEs!PsH(Hu;a{P@BTJs#_@N`(|hIZEi&6bMdG92c=W~+moiP53`YInR;9V)N;at=p2*Lvmk z+v^v|`R?|+s{Z-zR=-z%lNdi-EjIa2lvnu8{Ajb`=? z>$~B>Eni=0MA0Pelepoou zEANGSXFreKck@Y$jlA)dFnR$6dVECO z@`&C{!~skf${YOHqL1rz|Cx=^&0mN{4+Y|$aruR0tKz=wcusgk;>q}j@;!cQF`alo zdQ068l%Ge-Yrem5puF&pb`SKfJk)k>&1Y2k==$l>KKhw3?+z0eZn{){Q!1Bsa(NW* zQ=ZduZD-eWeYm+w`QMapuG~`hK>t9Wo4;Oi%~#y0hs*akcB6h! zc}P3u7hzs;(+5sGfBdOu^V7&(EKRpuv2T_HSFHRpUXGh9R*rk2T$c}&h&F0=jCdD!}a5K?&zbXxbvorJ{IV>BBS`5OWW1>=aRqW zY8)+}`b*`Pw;fmGC)@V;{mtE2E}x0%a?E{Uf3l4Grx+P0wA39%y!`D`v)@MJ@tJv1 z%{i-grx&lXyG3)GmbTm->}0f+1L8#b%@XzEYR;COa)cTQ=)h3LqnZjSCyq9jBLP)% z@gc@vS$S$&Js@7F0~ng6Rb3;1XHDurXeF4!FbMqFLJj$LDm^?*O|Lr z-w%4j;)Lr1@+diDM(J6_qkxCuw8`nQm*&K!HVe(2nLQqJXGn^takvoZ69j31(-jBI z%JHlkrey(fuDy5?pa2$(Azo@T3~+rwWPfb#noqLkDCz^^8hCbi=Je7HppXm@a^95P zb5`+^fdxJbhEyG7$YrO)Ds8Tf&H`9Fw;QD2 z?IM4``sxGXP~qlelb5Q57{I)1G3=loRWF2hMo*T6OV<=Zf(g@;0jW8`co^@wN})=j zE3%5`Tp{#APZb%dO$AA$V0VpPI-*)15ZNDD!yf&}s^3+3eLx1?5qgEp z>A|dNuEy+_H4BNw0-jYzlCxk3!&!EcVL>oBXTX=XEP+t~6^1G~+Vm)xqrmRk(FUfY zSynlq#?OB#wObGFx$luwB~(qSLaGs$c9jAmol8!f1w2FOQ^*EL;3kuEL!B$wy&{Kk zhRk>{%a^37N(dgNsn$;r2}`L5A?A>zIJKHf;IH~tzJxT-Asu~B_=IX@l?#W^=d}%q(up>bj zM9zZ4ZG$RJBgDA!6w*c&dYCoRn@huiVAPjp&_S-@s}Cq4J;mg;=_e z8iYa#5)0sF5wnjoAStI@*G?`Odd;~Qb9&6M1F-aj3QsGiSCI|^Cu!4G9}qog&;vwH z&jC(p$nxjD5IoeRoV{&TubR8>{k7VbQ#e&2P^GyHca?Z3Z3DXmS;)=ZKdQ<#bR@ZS zK#{8tC>^D%!_$D%$fzgS@ok=Kw-=lR!nrvH3D#q=Nd{F61xQ`A;6!RDL{$=y6Ouft zs7jt~di25^xpF{_Kl?3Cq~p`VfH=>caTiifupTT;Gw9H`zb@Jia;`{ywj~90gsBh6I^A${&`QFC5s32|vKsI3Ei_Ih&ZHUc3>hccYTAZHK?Rz})9I+6@o@MM97m3^=t4hS33O#o&P8B^KH!v{lKa;f8J*9?UK#F%#NrhzCK+36@lmt}=;mOF-%;h(=3zDoh?=xG_{E&~v;#VvZN3d(t~N+WO`w=>d=$} zjG=&$UK#MAMTj{%nnle1{T^^aq<2%Ka!^{9TJ#dw859gX3`gP#X$u(ymHHZj+Ybmb zdH~t2hY*bOXw#(Kl1i<5fE!6W{yi|;9MqPB%H1MFE}ly11?PS+97B#aLfQyvvsd93 z97)c-Qig5rA5~}A)-cxxByHO$1k2+n+Nd^+v;VwDuvKzxy@}plRoSaP+E{ENZQEKQ zP^H6wN*Q<#C-g{NDmg=i#k zo%8T8N~Z$?bBrf9S7xH3S7ztB5<4I@1OfpgDR?XimjuyB&0aik3Tg{srXVRfsT?U7QagaC1rOmuoY5?%J|Jn6hXzMAjXVC!ALMKU zj8P3$mtzMx4C2Ju3l#-&80pO=2w}oWkJlEuTdINuL#|C4RBX4^luHE%xpD_J%c>8E z5=eCsCPP)NXh;ylL~5ImxziG}I6Mpx3yIW%9YT_)(o|>*<)h7B1hKWL%?=CdGpE;d z)CbfCZ_7cU20U=)+}bP1uBS~N80AO z^0c-DcKJbn`x8VrJ#7ZTLh#JVorVG-r`JXgfxUn=7E&(|dK109dh{k-TaMjNg9s_8 z6wk1YnW}AgbLjy$EcF3#1IX@v7pQszQd^n~j+`DHDMyGdae7qU8A6l-5oefkjC8KM z1q%jJne|dtk@5j1L?pwNYfe?ESFpVe_?80#=_n?XL)Y9U6AC8hrlbQhbd_jfq;siaoThMhjjC;U3i80Aa*%TEja+>|(mG1dDjo$5+-e|X zJP-<2$pO)$npTq9+I9v=nn8$ho#yCpk5r0>vFhg0W;IDuhD*RhvpEP-FF7H2m`3yM z2Ly#6JhUpkZ4_-nBuF{esRx7(1><29geQbhBiIgdES6l`Am*}{GUFw13h5x{jI@Nd z4!{_Ns~{a|K*|A;bxmGBb1=d~t~uTve_JJ|);5np;-CVDF?0q6w}M`A6zomRY>y*t za~tV31nh2Er8jN2eBc-^6`mb{foLQEOsIl}w0?pd0MZ^j8^Oul=E03gRd=fyKl`V9 z;8;%TAjBZUHuVX?LmxQ!lwpC~T;qCOv|w@!GKVKURfnglqzuwXdTVceKxBc#m^`bu zcF*>gp-FHePzX3#EZ{+O_8}xnk#Z{$~j!k%8))SCh4<776m016*Q3g zfTX2FBRP850CNy5IbQN80Y*KJj$L2Bqal2WB9LoEp`A07%Y z_Tp*UL`pACuj!}{h)0yVi!kSSsuX;vk?Dr29|#2uEQWTZDg@3D*ET5O4A}rXC@4)* zaa7p@yt!a{=u4rR*&Y;N(q4jNhI8dhJ59ly9eU6Uai5z#s1Jx9k$4V}M}<%b(Mt;x2ZTXw z%Wfpi-d}(<3UW}&QAh_Q0Uk4G)4PMvo`M2WACM&)4cj~g z>#1h<4srIjb+8g3t{6`O+oWoPv~}3~f94_0-Ms@<0jUoNc-jvs^q7*2ZF&h}h(h=r zsi%HC+S*9z5aLV6L32G$L{dWdJSwVlLziGL(+HiLLfe2agB&^|d%S5>pu%cHu}xxrE&kUVg+M5pLEg6g$kChH3?r~C&ZjHTnFA<<6H)bgUaD}g7xem=h@(q zQy zn8VWmA$0Rno4VTC$f?UPkpgiVq+Ucl+wj2oJ03V!NflB>rmB!O1H`w#&UjPIF~u8@+NdgoHXs(vQLu{VAPcCrn&_$WEcrmW&bBtH4wBxsWMz%z?vD07nQ!uwIO;4@gPY?bd@9BaUA63&sPNa&(xJ%G}&uAudcoP|1f!)dkvS z&JJ^Py|f33K83PSKz%Yo^bpj3KyHAZjd&EGaAAVYsnuMfN})LUWO0eMk+T4S9pEIj zZFldDckIq*)n$=OO2suRDo+r;4*+ipka|`bK!~T=Jx3J-sU9Jwku>|?bg}@LEwh)o zZ8-$t7KMcuj#M7M7FVc+%S|&MMR3b8hm|ZUMG~rf*>siq+pS0K+@^}3K(-t!I(<~LMS9%=JXUKSQZDd zQG|97CMrTqTh(4X!4}$vTgB4=ZWF0eX4pY^^MJ^<-2iho!bkz*>IfC0r>~{<4 zm6=#5xD{=W0uZ(6G0ovJvlvL-6mc#U2q9I$P&r5sFd?2DP}!C|XQYuaw|>O|O0?J#Fs%B6z$L>zn$q63`0Z6hVPQ_mS~9ZqYjnoC-CCyi=-KsI_TdX5L@ z4PXE{z~Ic`X^`pWITDCfJgOK-G0YGQjsm2BsU~I>Sin;YELI)K3<$_M(j0As3dhsX z3xp*wR|8H0!lt7>AmEfd7IVpS3bYs?hABrC<0c#8xn-`H0#pbl#5DRxYN0?lH%CGG z#B7L%ar3OIN>OTvr4Oh60|0@B{@Wa|ZMY0u=>uKn!g&2fgb6Vh91u7~0f~2UwA5hE+-Npt4Pms%>dT z;K~7!MVv@H^(W62yKl*p%0-|{LkA&XjJdR?L=UMlU@=U+so;9u4?ShLXy^^$b6I#m zWR?X_eaT~4Leh)?*H2JF(u0sR${l1BVbV&j&A1Y)9rJ zf+e*|8*|C2z>pbfuOvvl;GB!6G{Q!6eL(j7*t@I#-)`#z;*2>PJrC6!w<5hlsA8yc z`1BHb{hC{`5qg++#-4B1_vKw0K@= zZT2QF+TQ2^xjlLRH8er&GZVz)J*#sX#8_+~h=m2O(5*^+}LMCRO6* zdeKoIP&!_E%()zL7;<<_Hb*Ey>hK+;2bC;(&cI{E@IenwNE$?8ZWXXQO$ZoL3VKo{ zJ_{_yMdML5Cm2uq1U3xZ?FS_7Tn{yAe*t4$tX`^8XsafIG{X&Lbr7gUPv!)Ho?eWq z^isj2vR8WB$axreP??i}g3O)>o*e->c53uX<;UoFm`B5$2=iE&$HP1k=E*Qmh52-t zr^7rGW;x8sFwchhok)l`yMeel^S&!VJQEG0a++ z7s9NEslp7yoC$L_%!^?*!ki0pKFnsA3t_gxY=^lR=A|&BFykNggvp zou=9dFto$cVlp+rL4e}mxij*xn0EbCa+c6kTj^vMs9{d(VyX?0QczJMZA=qz4op!Q zoV4JmVjU<(5~iYzMQ~Ks!ClUV40^$vnM;Se>K>kX0`eE{5%F2s^2 z5HRIr&Bd_qf_=sz@JV%~d?c*`+xN?z89%GKWK*_?j|#Pv@wRtw$!Sg(@XqBY-N54| KJW?*ukkIc^aZS~+^B`;zz<(>zVp9_Rx7l&rh9sl!{?{vPY0n7^ndygT8LOrM!`dj z_zSjp3&#LKjNkEl{=gqE6SxDcKYse*IDamp)ax|~J47mhdznjBNvK(S{QKz1!{!E{Z)V<>sM+*yDMM}DBRU{X)vqQgOl#M@VTt( zac64Qxw(p8;IlAls@m~&o1Q1@8k8ox)Ev5G&4-MN)FcDCYGgpxeX%K3m23l5_6#Y4 z2ReFTJ0zW5o|$u|NM6Z(V1{gfD_9NeMc;_=k_&srUZM=_0x((eqr%d+i;d{mYqrWm o0}2ifBbA;AD67&6=!xcAc`RPA5NhUkMs7xTMy+ILJZAmwH|Uas$N&HU diff --git a/venv/Lib/site-packages/requests/packages/chardet/__pycache__/langcyrillicmodel.cpython-36.pyc b/venv/Lib/site-packages/chardet/__pycache__/langcyrillicmodel.cpython-36.pyc similarity index 94% rename from venv/Lib/site-packages/requests/packages/chardet/__pycache__/langcyrillicmodel.cpython-36.pyc rename to venv/Lib/site-packages/chardet/__pycache__/langcyrillicmodel.cpython-36.pyc index 349d1ed2d60690ba1efa6181f5a8b5754e4d8387..91a8c209cb77d540af65140a54a423783b9895eb 100644 GIT binary patch delta 724 zcmb7>&ubJh6vs2O)9G5bU=ivHDswH;!`5!8J%}g@MMbEdhQN>}uQPFHk|D|Ly1neh zqZi$)SD|>a6tVvP{p;j?4qiO#AK=Nfj8g1gOyH6C`M#G&zWMgUx%1N*oSK}RxDelp zj$K6PJKDPrA#~Q}`nC=1ZHU;r&|&XGmwgCp>|^M$PvIE*9QuI3XOG!7d%~WwXZQSY z9Gr?guSgx-ioB@E0jTYg_BMN2p$QnPie6RZAb1sdU6BTRa}CXW+1$8a8F|0RwTrkF({8*y1Kl$678RV)Yi4;+N}{% zGqqzydxUa4BlLV<@igUhgxp*{cV)4?r!n~Z++As5;oqj=UA;c|YJX7egkKwU2^Sia z#;e2>36=twvPNJAx?^OH3&DF*b#Nbu3g)qf477D4XkiNR{OQ&l&Xv3Y)Zi{8oTd;E zVfd^`V9f+;ghF6lm$9(+N)hP3ZO)puR&?=YzKX5wFq;$Fu}*3{d}K~~zKhWCVR2&1 REgm>$T&M22&Y%6i=ihEf{Ivi8 delta 643 zcma)&&ubGw6vtEN60X;cg_h9428F;+UcfRip@7??5eE;e64^K>tP2at} za;%Eb5A^q$Lg=_KFHt?Bl&>>WlM@mCE)%_T3P&SSlBX^?YDE%kr>19a2{5DG>yM4Zr0VPuAwk|CA*1 z+~nLg`{1*_)nB*kS6g9ot#XtsYfze8rl#wYx`YK~$0G}%J0^fOkR~aj50P72})gs4eZ%BIz}Iwm2MY tnEiVcT diff --git a/venv/Lib/site-packages/requests/packages/chardet/__pycache__/langgreekmodel.cpython-36.pyc b/venv/Lib/site-packages/chardet/__pycache__/langgreekmodel.cpython-36.pyc similarity index 93% rename from venv/Lib/site-packages/requests/packages/chardet/__pycache__/langgreekmodel.cpython-36.pyc rename to venv/Lib/site-packages/chardet/__pycache__/langgreekmodel.cpython-36.pyc index 243ae38c937f16b67072911c8e3cb7e358cc06be..8111240e41fedbc50d8df4c7c8df2af3146b765b 100644 GIT binary patch delta 457 zcmZWlyGjHx6isGV5m8Y@(MG0J!D8GM(aJ__>;#b^ZivZsChlx9Bw5$BvGKhs%C;6Z zHg@6<_!q*o{)Lqh6h!ZZ1LwXt=XPH4!z(70!NLC3Cj)^sE_x`b=*z!c%6b(^MM) zhBjDUjN}G52v8h6cSar*;^4diAx;9K(S;t0fRrP|bo zhj47(?#hWms?ntDK*;#$_*lcd_P&`szO-Rf9ll;uNwT6rX|hGlo=27>%qZ(lWFblpYQ!E72n8;o3vKKb&z8sznREFQ55Ar?n*iI2#44FQ=v^qU0;tSU~76 z`hOlHwBo&)^}_FB#DByAAPD$~U-9q!n%|sO;u638h-yDCn&%IWT%`p&8V+g|S7j;H z#44gR2Tl4kchy`20}hgb_g0HTH*JTxU^FASGQx^|AevgC+>;(aPCzD^Fe%BvTF`EC z{L+9WlJ>zp%BV~RG=cUU3J}tMi{It>;#2wI<(KlG%@^+3*86sSae0}%Z8f@NvqL)F zX4EC?jSsHcir#diEwa{Vza#6NX0%p(-kv%79PU>Q+a&qzvz2>Enki2fxg_Se_(N zcAJ~Xu5-_i4{}%aJRRRrx-c_8-zfh7a^xeL7CU9GTNNYG$$oA=`*s=#?1S8$6yLHn z2kTgq`|X5PHA*(rU?sS=Hz`}wYQxwz+XT1q9IK%V7wW_XR$Tlr_ogtzR;>91;n_M8 zB|3=TYp{h6GWDQVKQ^GJMQkxGBcYPn>7A`t$u)| zEEc|FZ2X3;1pmUy2}JN-IB*X4anAkJ{hYdJyU|$M4=?d%$8o-$|Fz;cdzS021vUvB z_8z!w8hGG<#~#=tdt%S*<+>JBz@00vbEV4Oj-A%W-Dy!72a5-}2#MlEv}$FOMnqvF zu~ZBcPDxfaGX)eF2nv=P#m~z%Gs-w63C^VEh7SNMVz?|+w9)`t2tv4c*=$0V-I22b=NxwzBC#+wzJRT* z4`7Ie;FZev@BwU%m5Z0enPif0CiCTg9b30!Ykwsgjm)2))<2dIdPDy!hS0iUWe$ix zVZ@)Y#b0m$5Cr%gAMz2uzY60ZSik)6%_06+LGkeo83b`WjAxibWz{Q64zfUf9P=eG z;NUVSP%Xs?p6gWmzF@Rn@|4h`2W6^-hi6*=e$H*Sg>v$sHAp-?aVgL{v@^H}UE{N% zi6$rGbCg*lH3d?U2Gw1M6kW(l<04s5E$#WF=88Q}w#WfcX{SjAI-rcxPLWJ*E4`Xp zCMD?|0n=m`9KqUPZ@5|{stz1#dy_J-%fP&*YZ7{{UFnY5Z#MMkYKA;Z2-cF; zQtTx~{1)u|3)lKDtlV@C%!4<~%zN)RQM#WjR}(Epl6Xxnj9b->?4 z#6Ln05O{pdpZGI>;jeeau)yCAQSI|_=V5A)`$sVqwPIdjG1bH>qBI9hx-`uzsRjld zBm>8-7U%iA?Wcm#grv#{D|$dQwL;}{9e|X8j1pmDl7O|K^O?y@1C~hIg?u`pGRkNK z2P?=!NV`UQ`0XzZPyEv8(k~wmz9ypy{NA%IoEgvtx2VlxtR!&lu{t5aYW_aGK5fq+UY>NbY94ce4J;IgSmx)4eRrtgls n3vO5T@V;na7Y^zvWgX|&;9)ad_E(+Z;Z;~2U4$jCQ1Jc$IIM|9 delta 344 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 literal 0 HcmV?d00001 diff --git a/venv/Lib/site-packages/chardet/__pycache__/latin1prober.cpython-36.pyc b/venv/Lib/site-packages/chardet/__pycache__/latin1prober.cpython-36.pyc new file mode 100644 index 0000000000000000000000000000000000000000..a938cfcb041df75066c28d3151addea12c7e7885 GIT binary patch literal 2991 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 literal 0 HcmV?d00001 diff --git a/venv/Lib/site-packages/chardet/__pycache__/mbcsgroupprober.cpython-36.pyc b/venv/Lib/site-packages/chardet/__pycache__/mbcsgroupprober.cpython-36.pyc new file mode 100644 index 0000000000000000000000000000000000000000..4b7476872c589cfe49821e38effd073a81bd099c GIT binary patch literal 1173 zcmZ8gUu)Yi5SMJHN$g}@(>?5IgB~TRQSE zNTE;r8iRc$v9~?#E9_|}B}+qP?)s2IhV zp$z*NYiuzqvwhoOn>ks@FB$BxwXE!y4KA@tR`sg}uQ50Ce9z!At7Ub+Zg7P?$kzRJ zgRAUew&8DJbb?|x_HIz@Q9QH#MqKNnR{al#G+J0S+JlgHsXXC%F*)OTk8<$37w2ye z?yTd zQ#7-N))dG1JJ2uf8Ilf231khV3{nB9g19r3RHle{Q#7p2kR}!)S{y ztgcF;m{86=h@mQkq~lZ)!gXA(i{T}$*0h4bKwKxqt6I6BRC!{U7plampt5BtM^M)1 zHQ0n$RYD>b3PH$E^!G>fA}9pqBIt#(7zFv4#yq{GK}^L+=98cpr&l>21=lp>&HX^o zj0#Ayxf4V**+1Ob4ItW(Ml!ghgEV5a8IEPTB?q)GoBc4NO-`dcfeO-m+!WVvIfJ9) z%iu%W3q&gE)+CHZVM0X^!SuvbKFfNMNc0HJ3)!Ar^9PXoQxNe86v7S5!KsqYs`7G9%`5#>gs!)S H?|t?^`uZ?d literal 0 HcmV?d00001 diff --git a/venv/Lib/site-packages/chardet/__pycache__/mbcssm.cpython-36.pyc b/venv/Lib/site-packages/chardet/__pycache__/mbcssm.cpython-36.pyc new file mode 100644 index 0000000000000000000000000000000000000000..8775b83c931101b7f653b9c48a14e24d9e4602d9 GIT binary patch literal 17626 zcmeHOOH&(15Z1y<2!VLNj4_t+3)z-!u#>V=sZ0{FSe*Tf+L!)L5TD%{Sc|W2LqCtcAQ=TI+ zdYKHcJ{n^&Hb4hx{P!q{(-avr$FN5=Y>;_RJ~|b0F-Eh}YnNYL=n!^_I+UUfO406Y zYs7nTjrs_EUfGE;%1=pxULiwlkS1Az4bc(w)i7NmNgAcxPv{w;PvE_!-`oXGlwO>x z-H3z}@c@0SPkEV)(5qyWCHY#7uu(dS_KwkOWZd+jy|&)byjBW1YA=tG33{DOvT-W2 z2{uW`Q1cYML8hIn!#x6*%W{WY==6@|tV17xw`SHrN52u34v8Pism0>U_sI;sNoLtJ zO|Tg@OUH3Wb99+pFm+meO^f_}*Xq1*ZkBh1et~wCCuRpea`q5tSIK8JPt)WgyTE5P z&o0sloYexoMJ_pKbs~{`ZY#UN zZqjMAewp4UX%i3q#EM}_XK9iS(-}T0%q@1x>|9u{E=S#3FWwe}H*7;cSaWQ3YzNk1 zQA=ouOc9;!VxfN!EcZTMLBn;rK7k%9CBiE^UL zYn9z^(oub=v|m)!f>zwwXZo;FDHlsxUD1bBP+^KjN_$16u+M5{U9J_Y>^KJc27ttY z@IznZIKhb?U4Q%d;p3xN_T75s+uIf??}(d*?1pSuF{@0@^#6eI!lb%G5z zWOrZ?AWBGr_y89Gww2QB1U9S^l5^$*$T{h#H*Miw22q$FdC+$!Nq&+24L4AwRnmMO zt!nvl{e11i8zbDnl^!N=won2RIFcwf38*C?Y#au+@7|c=?dn&~VSY?F@}rd+9cjV# z5k@Lhjl|iVJ#X*0fcj8DKx_!>{iB)h8rhN435R(Z(?Ta&e6jZK2{~sXZowOvZhDiz za;IaC`wC76qX^>(tPW3?{Lbrp>InsBPR8hMWL9qV&HJ@D@& z?c*c{Brdbn$w-n`)o}oA-iE5|E^ehQYq1p|hjaI|wO{r1VEd{n5; z#_rAVv7Tg3{^JG>wr+@Fl00uq-iN7`g~^ z$E5Llj7ARxo~N!etJ?pX=}pegSe<-F_vNtoqfh&%qwRC}^G_Q#0jJuT)5$D!nRAm1 zP@M;2c`ZF=@SewGOWrUb?clRx!t!7`qeofou&OHXa*`fjd-3d>!um!|k7l>F-fZd7 z-1d{LZ9Vp4J6G7u>H{dxZR?Xp$LCMB3LDwih3zM68(BSRNH+_cZ+^;d=!5v~5o(JY zEC)`Rjc(+KDYu~feWjOg4XD8a)NJ%XO}P{LYRiIh)`UXiNhrvj(CwcsC}&M5G@gWl zTtE}XYgC9GG;$Pvc{+;52K1^ zH+WR^aKSemaLx-jG&g`l4*`ew#2y(&BL_wsO>SV)keaYRBg%6KY9RmoQTi@_s4_*( z?-aGey?njKs8adJ@|39`wE98*uvYn0S3cxFv!arEm{(bqsTxyKEBO-JefW4~HGiPg z-?NgI|H$?#rG1tv*0f4S+hb)d#owP}DTS5lyS0i|sn=5KXAZ9NuC1Q^pl>n_=Z@l&O zu=Ms@oGTvMU*X1j>{eNx;dahR6L>9jb*-kj=6Pv~Yo3w1t9d~hL;r%0AEz>4xQWr*ov~nWTvI3bhOu7XK1_NqmNG`eD zrDvCNq*5me$hFt@0~E+5haUO?`Z4C#_T)>_b1&`h%}SP(M6;N;GxO%pdvD(Rz4`U> za=9@$!iaZAbRR={OU&<4(MeXR#e79O0fa;Yw@a zbPB?2v3lX9g{5^%FK-WfswJ~0DmjpE5nFhYsu#` z83%GN9Lp#iCW#2J*Q-LpQArO#B z$~qOXD%S8{{*t+@Q-vz)`gRM#Me@_5OkUCE z<$XvHVjdgxP5EYP@RvVR`D*K7GdLHN{?1uVKSLv9nKfq%dt@(|#pY;pXKsVKa|hHD z476Zq(NN#elA+}}8!gc~!62N~tXH&`&ZbhS0=CvZ=V2UXoa+LgBtk~I#FadhDwRT4 zc-)&vJ~eltmw41mGoC0Rm0sqle9nVp7UO18@UkT9MKpNP32<||%=?OFQrlB9m08`@ zZYra`_VNS$SLZEVIu5>2;yl2SDd%6Y|Nb@js5?t>R`;Nn&4%41mO_PxvMXdd&XQ?& z7KbkqHSQkCo~qsLrg9=v$X0v58_2=k58wZw3q3|M$hwDe7zUB7_2MjiCmYIsR_pfy zSyM7d1~5jL#I^JYizk>GA9nY`gKipT@||ff821J;?UFV^X78m3)PhdAiQb(asS>RE zGt_h)gjrRqVB@nczT?_8?(y#VRRk0ZROtW86Fx%cswW8J3Bn#&nLF|pY(4h_@{FP& z>Kh6_z|A|&m;b{KFHu>&tbF{82dFh_EfeuT^x8mXJf2N>kcV3+Q&lDI4I(QLGeJ zppsF`ZtBX}9T;b=JBkigZxAVioC%sscp)b7w@_1x0tO*{`}oc41iXB}56gK6n|xo+ zkt3`HWImVFk9zT71`n#cxs2zn$~pzus+j0!)L1IBD+Sv_gC*-G=nL$aVFwOA)i|Y5xY<11#xPaw?!^j;DOmn<@%-y*dR9NkIt>gP97yFur{J=38kkNaB8I zShe5Q-b#O2dm(GX-XV~z_9Bd9sg6JVp;-qqN?z1rIp}2o%vw53R2Iy#S~f)F4Tni2 zuvz`J+!24=4V&)-R2H*=BK>T+<&(7h(B%Y@%E#qjnLmkh+CM-7$2z5cLc&_1wgT;$^rr~i&AsUIg>2u!8143@6pt}8 zrSN4|8J`O*EL&@iUnnCtP_0mo07kCZD`>4*Wt&E;mJg1PuWbIdWmC^Se*HR-qQhQ+ z6GcDWjfwgu8iJyn;>sSo>N7zxW@YvW5oY3wZBneb6m^@7@Blr}a0+=}IAag%JmSHt z3(dhF*T3HR=ke*5+Qjw)RFwa0>08;+Gz{P}(*!va{>I@bVKSh}>tBDnRWIh5#N-r{ zas2ZeH4d1&4CR@+o!^6{zGGPRHn?-tlr~|oY1yv9f<9WuKfTUASN*7NKWx@-(DTQ< zIXK=a^!}Me5>KHD=g()oDCa23=BiHQ7eszVgizI_I_)F%<298X`O0%c(JgC_qA@j* gs3@vT8qZU^Np}~74%7a}xthPD44Be_inZ?iAIgyK8~^|S literal 0 HcmV?d00001 diff --git a/venv/Lib/site-packages/chardet/__pycache__/sbcsgroupprober.cpython-36.pyc b/venv/Lib/site-packages/chardet/__pycache__/sbcsgroupprober.cpython-36.pyc new file mode 100644 index 0000000000000000000000000000000000000000..af6dfc587987085638eb7bf50e8f01300f336f4b GIT binary patch literal 1663 zcmaJ>U2oeq6eT5p$hI7R#7VPZAAU8qc1_x3-7pM8f-Ni776lw&03kq-B}P_4$}UN# z%iumaK>x%ZhXMObeBIOj!k)%UI%(1Ylc0mcd#^;^!y`Uwx0~PRSFvs*^cT8yRSf^m zJn}aK8Okt2921Ozd(7iL@h$gRg;zTlr^)~70Ox^uYB@B7LL)V z{WmsC9AVu*nkHgQ)v=f@<}bx;LWPOm8y98H=;5WJ>-;)Z(}SOja(8ck_vlg-j1}qg zSw@*|{xmC|2*)>{C8{X*?-q2QC+Xct>*<6)IXH0d*unn39gIBPwV(L%SWtTI3VLqZ zNAE(WY~W@(T(CS5MN+!bt@R4;hD}$Ulc(c@y@w~$q;M0N_Fe7%k8~pF>+5LfhBtEb z-8?4?abC!&txAo2HHkaPgUwIfU(OLIwu*5LV{gpAZiEP1&G6W61_~B%< zt*de|r$Y42vUL#0MOmmg7SM`-zC;zE22ckG02%;IfEGXq00M{&fSv(epIb*t(S=Y4 zLOn@U%)xZ=I;m^)7e&iVR|Pf6QAJlIWv9A5wVS#w(_3to7iq%cyWzn_As6pQjaeFT zoU%m9IQ|p;^GEu1w2)NDXp*SKG@6w(6U7CMGAhs2Y#uGj;`L0NN0&4a!^e@NoJvK- za5qY6{`jliy~r%~jHW8Opwl8{beNQ?xUZ)4R1Hs)lnw<=XStEBn3Y3$X3Nb<8Kvfr&8Yf9PEwh}Z|ih;FuxQ7qtNH(kpKv9cs2Z=yIRAciC1u7 zb0Kcx!25OQJzGAw-o#NAHndDQjbq)6LHY#)9>(!2Bb>|FnRR=uSxOl*+y9AKgM|?m z9|Qjs06g-Ud8B6`z;^s%^r7xUUuOSqwIrZKcTA%$j5*j|1asK$4LMH literal 0 HcmV?d00001 diff --git a/venv/Lib/site-packages/chardet/__pycache__/sjisprober.cpython-36.pyc b/venv/Lib/site-packages/chardet/__pycache__/sjisprober.cpython-36.pyc new file mode 100644 index 0000000000000000000000000000000000000000..45833215959dd6407ab7cd211e0a3f7b3feae1cb GIT binary patch literal 2489 zcmZt|%WfMtkldG6vLq{Z;@Cw|C_n>LK$A9YP_#u*G_{q)fnTr`6cto#*Go!Xc^?i* zrM97*xHHwMu(<8oa9$@+X=3IRJkT zL;eC2Ba9{_r9Da!wh}9~d$xh?#7W(rYhWkw(o(NvU^ns8a<6P)FR7$+y}7j7t5Wim zuoCl63G+Ff+PxYpcSx&pMuAO>>ZQ$bqT(Np6<^&CMTe^$k?(NG3JO-}8=*Pyhb!{MAs@n|h@ulRwMNzykjhrh6!w9u zyeWaTqL6n422EiZX@86?u`(w$4?C*tYyx-3= z&P4o*_ZgQ5DnIOxv-sCs9Q2QQD4GxZlBZlME}9Se5g$JM=D`>JLy?bor24P;ejFvd z8D=WJr}p_kH3wnDn}SFA5OjhVXv$-_oC0a~s=pEM^<}L1y~8j%2!~wuBZw@<)n{@P zOL!H+>;B=fm;=4;!jKi12(8l!_2D})QB-*4{)N@v@176g-gWnY6YRoK7jAF_K5v{L z<`IIt1OJFdvE0C;1)LUfLW)meNOTCwbkewrk^9Et*F?c+Sw(suCSXoRwD7)V_~O;1f%HoU)>|r`7#_E$U?~GHV~H5895}eY&=F2pfCgO49rgiM%x*BbT?wG{6x$;5odJi6Q#0(1D7w7X?zUIE z>swFt{4iGm&+_qbKVYE>b=|y~XM>pWEaG~h^K5&!yZWLVbf4|EVY9K;a!vMVA58)> z3Qc3kuk#X$%4#2_3D6EEyRK5~6A+&Bip8Ou+dE>VvzSPMY2 zOee;OE~l6?v;w*YoM#d6g^TUtoaig~G8Wa?;|T57RlJ5n?l$X_Q6p^hSqKrjCkc t>A{l{x~l22F3-lPG%;?np=bq{(iU=~tlEE6SmZnGD@NcdIKTKB_P>~uU}gXS literal 0 HcmV?d00001 diff --git a/venv/Lib/site-packages/chardet/__pycache__/universaldetector.cpython-36.pyc b/venv/Lib/site-packages/chardet/__pycache__/universaldetector.cpython-36.pyc new file mode 100644 index 0000000000000000000000000000000000000000..2ff7c4ca1bb2f91518d4101047e6f144a381d785 GIT binary patch literal 5884 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 L70HdmCMNz16{jlP literal 0 HcmV?d00001 diff --git a/venv/Lib/site-packages/chardet/__pycache__/utf8prober.cpython-36.pyc b/venv/Lib/site-packages/chardet/__pycache__/utf8prober.cpython-36.pyc new file mode 100644 index 0000000000000000000000000000000000000000..b0231185aa78a46cfde98bb8a454f3d3bd464810 GIT binary patch literal 2020 zcmah~Pj4GV6rb6DUOVeFN-6;oLKcW3qqZneM2ZllP28qZVpp~+B+F>D-WfY<@2=CC zb!j5!7VEg*^lwT~K zFX1ImyAQWmXP@o2b{cyT+D*e-6MJsw*4Um{@@DRgT`c)01}nA&8CMnn*u=$|L&huI`ifYDtvvI-ht?SfaIy+}UxB{5K+Cm>BVS$I zhdTglyLpBIOG7_v=7n`76EAY6kZ>espxs8h-D*p0S?x7jUAEuQUa>)YkGmb5`wv@B zn>*}rSG%3={dQMxjNo;mnUo@fFVu4)GE+Rz!G_DqJB@B*yZgBLNUxf`(`*=XkwrqU zcXnIt?)K9z>+ZH2FxlIwJEr8cKRC(-_?DVRPzC3`Zelgn@uozap%DBo#H>C5L7-Uz z7(R6_IP6{OexbD$uC5nhmzSd%w+|v|A6rik+psS(d~T z@mAT(8m#TXP}qvZq_T$Lzqb_rRV?cPvLtp1W4gjvI_0wj^?CP3W^yub~d!0|T> zr8MgmT|Mv6g5o4%tz7}6txT~M)wf<-uf22-DU}-9FIeg_k|HLIL;K$p SDS!Ju27`>*z5>Ajn1p4>mCUu#3qI^8!2cxQ+SoNY#62V~l=G35vz*&7^;t$=HU0X-RK!S-!| z9$X2kmR=*LrFSiC4A;g2A@^O@jUcUt?Za*gs4qIH*0Ms%(sU_%uAN`PCu!khBkgt! zjvDG z>SyE+0*0;p`JtAgr;tGulKWaXi`tt3g+^Ml>qKwO#`(1vQF>Si!WM}`&{LtXTD&`b zD?0CPQLz}XHY$LVmd!~(Q! +# +# 128 --> 0.42261 +# 256 --> 0.57851 +# 512 --> 0.74851 +# 1024 --> 0.89384 +# 2048 --> 0.97583 +# +# Ideal Distribution Ratio = 0.74851/(1-0.74851) =2.98 +# Random Distribution Ration = 512/(5401-512)=0.105 +# +# Typical Distribution Ratio about 25% of Ideal one, still much higher than RDR + +BIG5_TYPICAL_DISTRIBUTION_RATIO = 0.75 + +#Char to FreqOrder table +BIG5_TABLE_SIZE = 5376 + +BIG5_CHAR_TO_FREQ_ORDER = ( + 1,1801,1506, 255,1431, 198, 9, 82, 6,5008, 177, 202,3681,1256,2821, 110, # 16 +3814, 33,3274, 261, 76, 44,2114, 16,2946,2187,1176, 659,3971, 26,3451,2653, # 32 +1198,3972,3350,4202, 410,2215, 302, 590, 361,1964, 8, 204, 58,4510,5009,1932, # 48 + 63,5010,5011, 317,1614, 75, 222, 159,4203,2417,1480,5012,3555,3091, 224,2822, # 64 +3682, 3, 10,3973,1471, 29,2787,1135,2866,1940, 873, 130,3275,1123, 312,5013, # 80 +4511,2052, 507, 252, 682,5014, 142,1915, 124, 206,2947, 34,3556,3204, 64, 604, # 96 +5015,2501,1977,1978, 155,1991, 645, 641,1606,5016,3452, 337, 72, 406,5017, 80, # 112 + 630, 238,3205,1509, 263, 939,1092,2654, 756,1440,1094,3453, 449, 69,2987, 591, # 128 + 179,2096, 471, 115,2035,1844, 60, 50,2988, 134, 806,1869, 734,2036,3454, 180, # 144 + 995,1607, 156, 537,2907, 688,5018, 319,1305, 779,2145, 514,2379, 298,4512, 359, # 160 +2502, 90,2716,1338, 663, 11, 906,1099,2553, 20,2441, 182, 532,1716,5019, 732, # 176 +1376,4204,1311,1420,3206, 25,2317,1056, 113, 399, 382,1950, 242,3455,2474, 529, # 192 +3276, 475,1447,3683,5020, 117, 21, 656, 810,1297,2300,2334,3557,5021, 126,4205, # 208 + 706, 456, 150, 613,4513, 71,1118,2037,4206, 145,3092, 85, 835, 486,2115,1246, # 224 +1426, 428, 727,1285,1015, 800, 106, 623, 303,1281,5022,2128,2359, 347,3815, 221, # 240 +3558,3135,5023,1956,1153,4207, 83, 296,1199,3093, 192, 624, 93,5024, 822,1898, # 256 +2823,3136, 795,2065, 991,1554,1542,1592, 27, 43,2867, 859, 139,1456, 860,4514, # 272 + 437, 712,3974, 164,2397,3137, 695, 211,3037,2097, 195,3975,1608,3559,3560,3684, # 288 +3976, 234, 811,2989,2098,3977,2233,1441,3561,1615,2380, 668,2077,1638, 305, 228, # 304 +1664,4515, 467, 415,5025, 262,2099,1593, 239, 108, 300, 200,1033, 512,1247,2078, # 320 +5026,5027,2176,3207,3685,2682, 593, 845,1062,3277, 88,1723,2038,3978,1951, 212, # 336 + 266, 152, 149, 468,1899,4208,4516, 77, 187,5028,3038, 37, 5,2990,5029,3979, # 352 +5030,5031, 39,2524,4517,2908,3208,2079, 55, 148, 74,4518, 545, 483,1474,1029, # 368 +1665, 217,1870,1531,3138,1104,2655,4209, 24, 172,3562, 900,3980,3563,3564,4519, # 384 + 32,1408,2824,1312, 329, 487,2360,2251,2717, 784,2683, 4,3039,3351,1427,1789, # 400 + 188, 109, 499,5032,3686,1717,1790, 888,1217,3040,4520,5033,3565,5034,3352,1520, # 416 +3687,3981, 196,1034, 775,5035,5036, 929,1816, 249, 439, 38,5037,1063,5038, 794, # 432 +3982,1435,2301, 46, 178,3278,2066,5039,2381,5040, 214,1709,4521, 804, 35, 707, # 448 + 324,3688,1601,2554, 140, 459,4210,5041,5042,1365, 839, 272, 978,2262,2580,3456, # 464 +2129,1363,3689,1423, 697, 100,3094, 48, 70,1231, 495,3139,2196,5043,1294,5044, # 480 +2080, 462, 586,1042,3279, 853, 256, 988, 185,2382,3457,1698, 434,1084,5045,3458, # 496 + 314,2625,2788,4522,2335,2336, 569,2285, 637,1817,2525, 757,1162,1879,1616,3459, # 512 + 287,1577,2116, 768,4523,1671,2868,3566,2526,1321,3816, 909,2418,5046,4211, 933, # 528 +3817,4212,2053,2361,1222,4524, 765,2419,1322, 786,4525,5047,1920,1462,1677,2909, # 544 +1699,5048,4526,1424,2442,3140,3690,2600,3353,1775,1941,3460,3983,4213, 309,1369, # 560 +1130,2825, 364,2234,1653,1299,3984,3567,3985,3986,2656, 525,1085,3041, 902,2001, # 576 +1475, 964,4527, 421,1845,1415,1057,2286, 940,1364,3141, 376,4528,4529,1381, 7, # 592 +2527, 983,2383, 336,1710,2684,1846, 321,3461, 559,1131,3042,2752,1809,1132,1313, # 608 + 265,1481,1858,5049, 352,1203,2826,3280, 167,1089, 420,2827, 776, 792,1724,3568, # 624 +4214,2443,3281,5050,4215,5051, 446, 229, 333,2753, 901,3818,1200,1557,4530,2657, # 640 +1921, 395,2754,2685,3819,4216,1836, 125, 916,3209,2626,4531,5052,5053,3820,5054, # 656 +5055,5056,4532,3142,3691,1133,2555,1757,3462,1510,2318,1409,3569,5057,2146, 438, # 672 +2601,2910,2384,3354,1068, 958,3043, 461, 311,2869,2686,4217,1916,3210,4218,1979, # 688 + 383, 750,2755,2627,4219, 274, 539, 385,1278,1442,5058,1154,1965, 384, 561, 210, # 704 + 98,1295,2556,3570,5059,1711,2420,1482,3463,3987,2911,1257, 129,5060,3821, 642, # 720 + 523,2789,2790,2658,5061, 141,2235,1333, 68, 176, 441, 876, 907,4220, 603,2602, # 736 + 710, 171,3464, 404, 549, 18,3143,2398,1410,3692,1666,5062,3571,4533,2912,4534, # 752 +5063,2991, 368,5064, 146, 366, 99, 871,3693,1543, 748, 807,1586,1185, 22,2263, # 768 + 379,3822,3211,5065,3212, 505,1942,2628,1992,1382,2319,5066, 380,2362, 218, 702, # 784 +1818,1248,3465,3044,3572,3355,3282,5067,2992,3694, 930,3283,3823,5068, 59,5069, # 800 + 585, 601,4221, 497,3466,1112,1314,4535,1802,5070,1223,1472,2177,5071, 749,1837, # 816 + 690,1900,3824,1773,3988,1476, 429,1043,1791,2236,2117, 917,4222, 447,1086,1629, # 832 +5072, 556,5073,5074,2021,1654, 844,1090, 105, 550, 966,1758,2828,1008,1783, 686, # 848 +1095,5075,2287, 793,1602,5076,3573,2603,4536,4223,2948,2302,4537,3825, 980,2503, # 864 + 544, 353, 527,4538, 908,2687,2913,5077, 381,2629,1943,1348,5078,1341,1252, 560, # 880 +3095,5079,3467,2870,5080,2054, 973, 886,2081, 143,4539,5081,5082, 157,3989, 496, # 896 +4224, 57, 840, 540,2039,4540,4541,3468,2118,1445, 970,2264,1748,1966,2082,4225, # 912 +3144,1234,1776,3284,2829,3695, 773,1206,2130,1066,2040,1326,3990,1738,1725,4226, # 928 + 279,3145, 51,1544,2604, 423,1578,2131,2067, 173,4542,1880,5083,5084,1583, 264, # 944 + 610,3696,4543,2444, 280, 154,5085,5086,5087,1739, 338,1282,3096, 693,2871,1411, # 960 +1074,3826,2445,5088,4544,5089,5090,1240, 952,2399,5091,2914,1538,2688, 685,1483, # 976 +4227,2475,1436, 953,4228,2055,4545, 671,2400, 79,4229,2446,3285, 608, 567,2689, # 992 +3469,4230,4231,1691, 393,1261,1792,2401,5092,4546,5093,5094,5095,5096,1383,1672, # 1008 +3827,3213,1464, 522,1119, 661,1150, 216, 675,4547,3991,1432,3574, 609,4548,2690, # 1024 +2402,5097,5098,5099,4232,3045, 0,5100,2476, 315, 231,2447, 301,3356,4549,2385, # 1040 +5101, 233,4233,3697,1819,4550,4551,5102, 96,1777,1315,2083,5103, 257,5104,1810, # 1056 +3698,2718,1139,1820,4234,2022,1124,2164,2791,1778,2659,5105,3097, 363,1655,3214, # 1072 +5106,2993,5107,5108,5109,3992,1567,3993, 718, 103,3215, 849,1443, 341,3357,2949, # 1088 +1484,5110,1712, 127, 67, 339,4235,2403, 679,1412, 821,5111,5112, 834, 738, 351, # 1104 +2994,2147, 846, 235,1497,1881, 418,1993,3828,2719, 186,1100,2148,2756,3575,1545, # 1120 +1355,2950,2872,1377, 583,3994,4236,2581,2995,5113,1298,3699,1078,2557,3700,2363, # 1136 + 78,3829,3830, 267,1289,2100,2002,1594,4237, 348, 369,1274,2197,2178,1838,4552, # 1152 +1821,2830,3701,2757,2288,2003,4553,2951,2758, 144,3358, 882,4554,3995,2759,3470, # 1168 +4555,2915,5114,4238,1726, 320,5115,3996,3046, 788,2996,5116,2831,1774,1327,2873, # 1184 +3997,2832,5117,1306,4556,2004,1700,3831,3576,2364,2660, 787,2023, 506, 824,3702, # 1200 + 534, 323,4557,1044,3359,2024,1901, 946,3471,5118,1779,1500,1678,5119,1882,4558, # 1216 + 165, 243,4559,3703,2528, 123, 683,4239, 764,4560, 36,3998,1793, 589,2916, 816, # 1232 + 626,1667,3047,2237,1639,1555,1622,3832,3999,5120,4000,2874,1370,1228,1933, 891, # 1248 +2084,2917, 304,4240,5121, 292,2997,2720,3577, 691,2101,4241,1115,4561, 118, 662, # 1264 +5122, 611,1156, 854,2386,1316,2875, 2, 386, 515,2918,5123,5124,3286, 868,2238, # 1280 +1486, 855,2661, 785,2216,3048,5125,1040,3216,3578,5126,3146, 448,5127,1525,5128, # 1296 +2165,4562,5129,3833,5130,4242,2833,3579,3147, 503, 818,4001,3148,1568, 814, 676, # 1312 +1444, 306,1749,5131,3834,1416,1030, 197,1428, 805,2834,1501,4563,5132,5133,5134, # 1328 +1994,5135,4564,5136,5137,2198, 13,2792,3704,2998,3149,1229,1917,5138,3835,2132, # 1344 +5139,4243,4565,2404,3580,5140,2217,1511,1727,1120,5141,5142, 646,3836,2448, 307, # 1360 +5143,5144,1595,3217,5145,5146,5147,3705,1113,1356,4002,1465,2529,2530,5148, 519, # 1376 +5149, 128,2133, 92,2289,1980,5150,4003,1512, 342,3150,2199,5151,2793,2218,1981, # 1392 +3360,4244, 290,1656,1317, 789, 827,2365,5152,3837,4566, 562, 581,4004,5153, 401, # 1408 +4567,2252, 94,4568,5154,1399,2794,5155,1463,2025,4569,3218,1944,5156, 828,1105, # 1424 +4245,1262,1394,5157,4246, 605,4570,5158,1784,2876,5159,2835, 819,2102, 578,2200, # 1440 +2952,5160,1502, 436,3287,4247,3288,2836,4005,2919,3472,3473,5161,2721,2320,5162, # 1456 +5163,2337,2068, 23,4571, 193, 826,3838,2103, 699,1630,4248,3098, 390,1794,1064, # 1472 +3581,5164,1579,3099,3100,1400,5165,4249,1839,1640,2877,5166,4572,4573, 137,4250, # 1488 + 598,3101,1967, 780, 104, 974,2953,5167, 278, 899, 253, 402, 572, 504, 493,1339, # 1504 +5168,4006,1275,4574,2582,2558,5169,3706,3049,3102,2253, 565,1334,2722, 863, 41, # 1520 +5170,5171,4575,5172,1657,2338, 19, 463,2760,4251, 606,5173,2999,3289,1087,2085, # 1536 +1323,2662,3000,5174,1631,1623,1750,4252,2691,5175,2878, 791,2723,2663,2339, 232, # 1552 +2421,5176,3001,1498,5177,2664,2630, 755,1366,3707,3290,3151,2026,1609, 119,1918, # 1568 +3474, 862,1026,4253,5178,4007,3839,4576,4008,4577,2265,1952,2477,5179,1125, 817, # 1584 +4254,4255,4009,1513,1766,2041,1487,4256,3050,3291,2837,3840,3152,5180,5181,1507, # 1600 +5182,2692, 733, 40,1632,1106,2879, 345,4257, 841,2531, 230,4578,3002,1847,3292, # 1616 +3475,5183,1263, 986,3476,5184, 735, 879, 254,1137, 857, 622,1300,1180,1388,1562, # 1632 +4010,4011,2954, 967,2761,2665,1349, 592,2134,1692,3361,3003,1995,4258,1679,4012, # 1648 +1902,2188,5185, 739,3708,2724,1296,1290,5186,4259,2201,2202,1922,1563,2605,2559, # 1664 +1871,2762,3004,5187, 435,5188, 343,1108, 596, 17,1751,4579,2239,3477,3709,5189, # 1680 +4580, 294,3582,2955,1693, 477, 979, 281,2042,3583, 643,2043,3710,2631,2795,2266, # 1696 +1031,2340,2135,2303,3584,4581, 367,1249,2560,5190,3585,5191,4582,1283,3362,2005, # 1712 + 240,1762,3363,4583,4584, 836,1069,3153, 474,5192,2149,2532, 268,3586,5193,3219, # 1728 +1521,1284,5194,1658,1546,4260,5195,3587,3588,5196,4261,3364,2693,1685,4262, 961, # 1744 +1673,2632, 190,2006,2203,3841,4585,4586,5197, 570,2504,3711,1490,5198,4587,2633, # 1760 +3293,1957,4588, 584,1514, 396,1045,1945,5199,4589,1968,2449,5200,5201,4590,4013, # 1776 + 619,5202,3154,3294, 215,2007,2796,2561,3220,4591,3221,4592, 763,4263,3842,4593, # 1792 +5203,5204,1958,1767,2956,3365,3712,1174, 452,1477,4594,3366,3155,5205,2838,1253, # 1808 +2387,2189,1091,2290,4264, 492,5206, 638,1169,1825,2136,1752,4014, 648, 926,1021, # 1824 +1324,4595, 520,4596, 997, 847,1007, 892,4597,3843,2267,1872,3713,2405,1785,4598, # 1840 +1953,2957,3103,3222,1728,4265,2044,3714,4599,2008,1701,3156,1551, 30,2268,4266, # 1856 +5207,2027,4600,3589,5208, 501,5209,4267, 594,3478,2166,1822,3590,3479,3591,3223, # 1872 + 829,2839,4268,5210,1680,3157,1225,4269,5211,3295,4601,4270,3158,2341,5212,4602, # 1888 +4271,5213,4015,4016,5214,1848,2388,2606,3367,5215,4603, 374,4017, 652,4272,4273, # 1904 + 375,1140, 798,5216,5217,5218,2366,4604,2269, 546,1659, 138,3051,2450,4605,5219, # 1920 +2254, 612,1849, 910, 796,3844,1740,1371, 825,3845,3846,5220,2920,2562,5221, 692, # 1936 + 444,3052,2634, 801,4606,4274,5222,1491, 244,1053,3053,4275,4276, 340,5223,4018, # 1952 +1041,3005, 293,1168, 87,1357,5224,1539, 959,5225,2240, 721, 694,4277,3847, 219, # 1968 +1478, 644,1417,3368,2666,1413,1401,1335,1389,4019,5226,5227,3006,2367,3159,1826, # 1984 + 730,1515, 184,2840, 66,4607,5228,1660,2958, 246,3369, 378,1457, 226,3480, 975, # 2000 +4020,2959,1264,3592, 674, 696,5229, 163,5230,1141,2422,2167, 713,3593,3370,4608, # 2016 +4021,5231,5232,1186, 15,5233,1079,1070,5234,1522,3224,3594, 276,1050,2725, 758, # 2032 +1126, 653,2960,3296,5235,2342, 889,3595,4022,3104,3007, 903,1250,4609,4023,3481, # 2048 +3596,1342,1681,1718, 766,3297, 286, 89,2961,3715,5236,1713,5237,2607,3371,3008, # 2064 +5238,2962,2219,3225,2880,5239,4610,2505,2533, 181, 387,1075,4024, 731,2190,3372, # 2080 +5240,3298, 310, 313,3482,2304, 770,4278, 54,3054, 189,4611,3105,3848,4025,5241, # 2096 +1230,1617,1850, 355,3597,4279,4612,3373, 111,4280,3716,1350,3160,3483,3055,4281, # 2112 +2150,3299,3598,5242,2797,4026,4027,3009, 722,2009,5243,1071, 247,1207,2343,2478, # 2128 +1378,4613,2010, 864,1437,1214,4614, 373,3849,1142,2220, 667,4615, 442,2763,2563, # 2144 +3850,4028,1969,4282,3300,1840, 837, 170,1107, 934,1336,1883,5244,5245,2119,4283, # 2160 +2841, 743,1569,5246,4616,4284, 582,2389,1418,3484,5247,1803,5248, 357,1395,1729, # 2176 +3717,3301,2423,1564,2241,5249,3106,3851,1633,4617,1114,2086,4285,1532,5250, 482, # 2192 +2451,4618,5251,5252,1492, 833,1466,5253,2726,3599,1641,2842,5254,1526,1272,3718, # 2208 +4286,1686,1795, 416,2564,1903,1954,1804,5255,3852,2798,3853,1159,2321,5256,2881, # 2224 +4619,1610,1584,3056,2424,2764, 443,3302,1163,3161,5257,5258,4029,5259,4287,2506, # 2240 +3057,4620,4030,3162,2104,1647,3600,2011,1873,4288,5260,4289, 431,3485,5261, 250, # 2256 + 97, 81,4290,5262,1648,1851,1558, 160, 848,5263, 866, 740,1694,5264,2204,2843, # 2272 +3226,4291,4621,3719,1687, 950,2479, 426, 469,3227,3720,3721,4031,5265,5266,1188, # 2288 + 424,1996, 861,3601,4292,3854,2205,2694, 168,1235,3602,4293,5267,2087,1674,4622, # 2304 +3374,3303, 220,2565,1009,5268,3855, 670,3010, 332,1208, 717,5269,5270,3603,2452, # 2320 +4032,3375,5271, 513,5272,1209,2882,3376,3163,4623,1080,5273,5274,5275,5276,2534, # 2336 +3722,3604, 815,1587,4033,4034,5277,3605,3486,3856,1254,4624,1328,3058,1390,4035, # 2352 +1741,4036,3857,4037,5278, 236,3858,2453,3304,5279,5280,3723,3859,1273,3860,4625, # 2368 +5281, 308,5282,4626, 245,4627,1852,2480,1307,2583, 430, 715,2137,2454,5283, 270, # 2384 + 199,2883,4038,5284,3606,2727,1753, 761,1754, 725,1661,1841,4628,3487,3724,5285, # 2400 +5286, 587, 14,3305, 227,2608, 326, 480,2270, 943,2765,3607, 291, 650,1884,5287, # 2416 +1702,1226, 102,1547, 62,3488, 904,4629,3489,1164,4294,5288,5289,1224,1548,2766, # 2432 + 391, 498,1493,5290,1386,1419,5291,2056,1177,4630, 813, 880,1081,2368, 566,1145, # 2448 +4631,2291,1001,1035,2566,2609,2242, 394,1286,5292,5293,2069,5294, 86,1494,1730, # 2464 +4039, 491,1588, 745, 897,2963, 843,3377,4040,2767,2884,3306,1768, 998,2221,2070, # 2480 + 397,1827,1195,1970,3725,3011,3378, 284,5295,3861,2507,2138,2120,1904,5296,4041, # 2496 +2151,4042,4295,1036,3490,1905, 114,2567,4296, 209,1527,5297,5298,2964,2844,2635, # 2512 +2390,2728,3164, 812,2568,5299,3307,5300,1559, 737,1885,3726,1210, 885, 28,2695, # 2528 +3608,3862,5301,4297,1004,1780,4632,5302, 346,1982,2222,2696,4633,3863,1742, 797, # 2544 +1642,4043,1934,1072,1384,2152, 896,4044,3308,3727,3228,2885,3609,5303,2569,1959, # 2560 +4634,2455,1786,5304,5305,5306,4045,4298,1005,1308,3728,4299,2729,4635,4636,1528, # 2576 +2610, 161,1178,4300,1983, 987,4637,1101,4301, 631,4046,1157,3229,2425,1343,1241, # 2592 +1016,2243,2570, 372, 877,2344,2508,1160, 555,1935, 911,4047,5307, 466,1170, 169, # 2608 +1051,2921,2697,3729,2481,3012,1182,2012,2571,1251,2636,5308, 992,2345,3491,1540, # 2624 +2730,1201,2071,2406,1997,2482,5309,4638, 528,1923,2191,1503,1874,1570,2369,3379, # 2640 +3309,5310, 557,1073,5311,1828,3492,2088,2271,3165,3059,3107, 767,3108,2799,4639, # 2656 +1006,4302,4640,2346,1267,2179,3730,3230, 778,4048,3231,2731,1597,2667,5312,4641, # 2672 +5313,3493,5314,5315,5316,3310,2698,1433,3311, 131, 95,1504,4049, 723,4303,3166, # 2688 +1842,3610,2768,2192,4050,2028,2105,3731,5317,3013,4051,1218,5318,3380,3232,4052, # 2704 +4304,2584, 248,1634,3864, 912,5319,2845,3732,3060,3865, 654, 53,5320,3014,5321, # 2720 +1688,4642, 777,3494,1032,4053,1425,5322, 191, 820,2121,2846, 971,4643, 931,3233, # 2736 + 135, 664, 783,3866,1998, 772,2922,1936,4054,3867,4644,2923,3234, 282,2732, 640, # 2752 +1372,3495,1127, 922, 325,3381,5323,5324, 711,2045,5325,5326,4055,2223,2800,1937, # 2768 +4056,3382,2224,2255,3868,2305,5327,4645,3869,1258,3312,4057,3235,2139,2965,4058, # 2784 +4059,5328,2225, 258,3236,4646, 101,1227,5329,3313,1755,5330,1391,3314,5331,2924, # 2800 +2057, 893,5332,5333,5334,1402,4305,2347,5335,5336,3237,3611,5337,5338, 878,1325, # 2816 +1781,2801,4647, 259,1385,2585, 744,1183,2272,4648,5339,4060,2509,5340, 684,1024, # 2832 +4306,5341, 472,3612,3496,1165,3315,4061,4062, 322,2153, 881, 455,1695,1152,1340, # 2848 + 660, 554,2154,4649,1058,4650,4307, 830,1065,3383,4063,4651,1924,5342,1703,1919, # 2864 +5343, 932,2273, 122,5344,4652, 947, 677,5345,3870,2637, 297,1906,1925,2274,4653, # 2880 +2322,3316,5346,5347,4308,5348,4309, 84,4310, 112, 989,5349, 547,1059,4064, 701, # 2896 +3613,1019,5350,4311,5351,3497, 942, 639, 457,2306,2456, 993,2966, 407, 851, 494, # 2912 +4654,3384, 927,5352,1237,5353,2426,3385, 573,4312, 680, 921,2925,1279,1875, 285, # 2928 + 790,1448,1984, 719,2168,5354,5355,4655,4065,4066,1649,5356,1541, 563,5357,1077, # 2944 +5358,3386,3061,3498, 511,3015,4067,4068,3733,4069,1268,2572,3387,3238,4656,4657, # 2960 +5359, 535,1048,1276,1189,2926,2029,3167,1438,1373,2847,2967,1134,2013,5360,4313, # 2976 +1238,2586,3109,1259,5361, 700,5362,2968,3168,3734,4314,5363,4315,1146,1876,1907, # 2992 +4658,2611,4070, 781,2427, 132,1589, 203, 147, 273,2802,2407, 898,1787,2155,4071, # 3008 +4072,5364,3871,2803,5365,5366,4659,4660,5367,3239,5368,1635,3872, 965,5369,1805, # 3024 +2699,1516,3614,1121,1082,1329,3317,4073,1449,3873, 65,1128,2848,2927,2769,1590, # 3040 +3874,5370,5371, 12,2668, 45, 976,2587,3169,4661, 517,2535,1013,1037,3240,5372, # 3056 +3875,2849,5373,3876,5374,3499,5375,2612, 614,1999,2323,3877,3110,2733,2638,5376, # 3072 +2588,4316, 599,1269,5377,1811,3735,5378,2700,3111, 759,1060, 489,1806,3388,3318, # 3088 +1358,5379,5380,2391,1387,1215,2639,2256, 490,5381,5382,4317,1759,2392,2348,5383, # 3104 +4662,3878,1908,4074,2640,1807,3241,4663,3500,3319,2770,2349, 874,5384,5385,3501, # 3120 +3736,1859, 91,2928,3737,3062,3879,4664,5386,3170,4075,2669,5387,3502,1202,1403, # 3136 +3880,2969,2536,1517,2510,4665,3503,2511,5388,4666,5389,2701,1886,1495,1731,4076, # 3152 +2370,4667,5390,2030,5391,5392,4077,2702,1216, 237,2589,4318,2324,4078,3881,4668, # 3168 +4669,2703,3615,3504, 445,4670,5393,5394,5395,5396,2771, 61,4079,3738,1823,4080, # 3184 +5397, 687,2046, 935, 925, 405,2670, 703,1096,1860,2734,4671,4081,1877,1367,2704, # 3200 +3389, 918,2106,1782,2483, 334,3320,1611,1093,4672, 564,3171,3505,3739,3390, 945, # 3216 +2641,2058,4673,5398,1926, 872,4319,5399,3506,2705,3112, 349,4320,3740,4082,4674, # 3232 +3882,4321,3741,2156,4083,4675,4676,4322,4677,2408,2047, 782,4084, 400, 251,4323, # 3248 +1624,5400,5401, 277,3742, 299,1265, 476,1191,3883,2122,4324,4325,1109, 205,5402, # 3264 +2590,1000,2157,3616,1861,5403,5404,5405,4678,5406,4679,2573, 107,2484,2158,4085, # 3280 +3507,3172,5407,1533, 541,1301, 158, 753,4326,2886,3617,5408,1696, 370,1088,4327, # 3296 +4680,3618, 579, 327, 440, 162,2244, 269,1938,1374,3508, 968,3063, 56,1396,3113, # 3312 +2107,3321,3391,5409,1927,2159,4681,3016,5410,3619,5411,5412,3743,4682,2485,5413, # 3328 +2804,5414,1650,4683,5415,2613,5416,5417,4086,2671,3392,1149,3393,4087,3884,4088, # 3344 +5418,1076, 49,5419, 951,3242,3322,3323, 450,2850, 920,5420,1812,2805,2371,4328, # 3360 +1909,1138,2372,3885,3509,5421,3243,4684,1910,1147,1518,2428,4685,3886,5422,4686, # 3376 +2393,2614, 260,1796,3244,5423,5424,3887,3324, 708,5425,3620,1704,5426,3621,1351, # 3392 +1618,3394,3017,1887, 944,4329,3395,4330,3064,3396,4331,5427,3744, 422, 413,1714, # 3408 +3325, 500,2059,2350,4332,2486,5428,1344,1911, 954,5429,1668,5430,5431,4089,2409, # 3424 +4333,3622,3888,4334,5432,2307,1318,2512,3114, 133,3115,2887,4687, 629, 31,2851, # 3440 +2706,3889,4688, 850, 949,4689,4090,2970,1732,2089,4335,1496,1853,5433,4091, 620, # 3456 +3245, 981,1242,3745,3397,1619,3746,1643,3326,2140,2457,1971,1719,3510,2169,5434, # 3472 +3246,5435,5436,3398,1829,5437,1277,4690,1565,2048,5438,1636,3623,3116,5439, 869, # 3488 +2852, 655,3890,3891,3117,4092,3018,3892,1310,3624,4691,5440,5441,5442,1733, 558, # 3504 +4692,3747, 335,1549,3065,1756,4336,3748,1946,3511,1830,1291,1192, 470,2735,2108, # 3520 +2806, 913,1054,4093,5443,1027,5444,3066,4094,4693, 982,2672,3399,3173,3512,3247, # 3536 +3248,1947,2807,5445, 571,4694,5446,1831,5447,3625,2591,1523,2429,5448,2090, 984, # 3552 +4695,3749,1960,5449,3750, 852, 923,2808,3513,3751, 969,1519, 999,2049,2325,1705, # 3568 +5450,3118, 615,1662, 151, 597,4095,2410,2326,1049, 275,4696,3752,4337, 568,3753, # 3584 +3626,2487,4338,3754,5451,2430,2275, 409,3249,5452,1566,2888,3514,1002, 769,2853, # 3600 + 194,2091,3174,3755,2226,3327,4339, 628,1505,5453,5454,1763,2180,3019,4096, 521, # 3616 +1161,2592,1788,2206,2411,4697,4097,1625,4340,4341, 412, 42,3119, 464,5455,2642, # 3632 +4698,3400,1760,1571,2889,3515,2537,1219,2207,3893,2643,2141,2373,4699,4700,3328, # 3648 +1651,3401,3627,5456,5457,3628,2488,3516,5458,3756,5459,5460,2276,2092, 460,5461, # 3664 +4701,5462,3020, 962, 588,3629, 289,3250,2644,1116, 52,5463,3067,1797,5464,5465, # 3680 +5466,1467,5467,1598,1143,3757,4342,1985,1734,1067,4702,1280,3402, 465,4703,1572, # 3696 + 510,5468,1928,2245,1813,1644,3630,5469,4704,3758,5470,5471,2673,1573,1534,5472, # 3712 +5473, 536,1808,1761,3517,3894,3175,2645,5474,5475,5476,4705,3518,2929,1912,2809, # 3728 +5477,3329,1122, 377,3251,5478, 360,5479,5480,4343,1529, 551,5481,2060,3759,1769, # 3744 +2431,5482,2930,4344,3330,3120,2327,2109,2031,4706,1404, 136,1468,1479, 672,1171, # 3760 +3252,2308, 271,3176,5483,2772,5484,2050, 678,2736, 865,1948,4707,5485,2014,4098, # 3776 +2971,5486,2737,2227,1397,3068,3760,4708,4709,1735,2931,3403,3631,5487,3895, 509, # 3792 +2854,2458,2890,3896,5488,5489,3177,3178,4710,4345,2538,4711,2309,1166,1010, 552, # 3808 + 681,1888,5490,5491,2972,2973,4099,1287,1596,1862,3179, 358, 453, 736, 175, 478, # 3824 +1117, 905,1167,1097,5492,1854,1530,5493,1706,5494,2181,3519,2292,3761,3520,3632, # 3840 +4346,2093,4347,5495,3404,1193,2489,4348,1458,2193,2208,1863,1889,1421,3331,2932, # 3856 +3069,2182,3521, 595,2123,5496,4100,5497,5498,4349,1707,2646, 223,3762,1359, 751, # 3872 +3121, 183,3522,5499,2810,3021, 419,2374, 633, 704,3897,2394, 241,5500,5501,5502, # 3888 + 838,3022,3763,2277,2773,2459,3898,1939,2051,4101,1309,3122,2246,1181,5503,1136, # 3904 +2209,3899,2375,1446,4350,2310,4712,5504,5505,4351,1055,2615, 484,3764,5506,4102, # 3920 + 625,4352,2278,3405,1499,4353,4103,5507,4104,4354,3253,2279,2280,3523,5508,5509, # 3936 +2774, 808,2616,3765,3406,4105,4355,3123,2539, 526,3407,3900,4356, 955,5510,1620, # 3952 +4357,2647,2432,5511,1429,3766,1669,1832, 994, 928,5512,3633,1260,5513,5514,5515, # 3968 +1949,2293, 741,2933,1626,4358,2738,2460, 867,1184, 362,3408,1392,5516,5517,4106, # 3984 +4359,1770,1736,3254,2934,4713,4714,1929,2707,1459,1158,5518,3070,3409,2891,1292, # 4000 +1930,2513,2855,3767,1986,1187,2072,2015,2617,4360,5519,2574,2514,2170,3768,2490, # 4016 +3332,5520,3769,4715,5521,5522, 666,1003,3023,1022,3634,4361,5523,4716,1814,2257, # 4032 + 574,3901,1603, 295,1535, 705,3902,4362, 283, 858, 417,5524,5525,3255,4717,4718, # 4048 +3071,1220,1890,1046,2281,2461,4107,1393,1599, 689,2575, 388,4363,5526,2491, 802, # 4064 +5527,2811,3903,2061,1405,2258,5528,4719,3904,2110,1052,1345,3256,1585,5529, 809, # 4080 +5530,5531,5532, 575,2739,3524, 956,1552,1469,1144,2328,5533,2329,1560,2462,3635, # 4096 +3257,4108, 616,2210,4364,3180,2183,2294,5534,1833,5535,3525,4720,5536,1319,3770, # 4112 +3771,1211,3636,1023,3258,1293,2812,5537,5538,5539,3905, 607,2311,3906, 762,2892, # 4128 +1439,4365,1360,4721,1485,3072,5540,4722,1038,4366,1450,2062,2648,4367,1379,4723, # 4144 +2593,5541,5542,4368,1352,1414,2330,2935,1172,5543,5544,3907,3908,4724,1798,1451, # 4160 +5545,5546,5547,5548,2936,4109,4110,2492,2351, 411,4111,4112,3637,3333,3124,4725, # 4176 +1561,2674,1452,4113,1375,5549,5550, 47,2974, 316,5551,1406,1591,2937,3181,5552, # 4192 +1025,2142,3125,3182, 354,2740, 884,2228,4369,2412, 508,3772, 726,3638, 996,2433, # 4208 +3639, 729,5553, 392,2194,1453,4114,4726,3773,5554,5555,2463,3640,2618,1675,2813, # 4224 + 919,2352,2975,2353,1270,4727,4115, 73,5556,5557, 647,5558,3259,2856,2259,1550, # 4240 +1346,3024,5559,1332, 883,3526,5560,5561,5562,5563,3334,2775,5564,1212, 831,1347, # 4256 +4370,4728,2331,3909,1864,3073, 720,3910,4729,4730,3911,5565,4371,5566,5567,4731, # 4272 +5568,5569,1799,4732,3774,2619,4733,3641,1645,2376,4734,5570,2938, 669,2211,2675, # 4288 +2434,5571,2893,5572,5573,1028,3260,5574,4372,2413,5575,2260,1353,5576,5577,4735, # 4304 +3183, 518,5578,4116,5579,4373,1961,5580,2143,4374,5581,5582,3025,2354,2355,3912, # 4320 + 516,1834,1454,4117,2708,4375,4736,2229,2620,1972,1129,3642,5583,2776,5584,2976, # 4336 +1422, 577,1470,3026,1524,3410,5585,5586, 432,4376,3074,3527,5587,2594,1455,2515, # 4352 +2230,1973,1175,5588,1020,2741,4118,3528,4737,5589,2742,5590,1743,1361,3075,3529, # 4368 +2649,4119,4377,4738,2295, 895, 924,4378,2171, 331,2247,3076, 166,1627,3077,1098, # 4384 +5591,1232,2894,2231,3411,4739, 657, 403,1196,2377, 542,3775,3412,1600,4379,3530, # 4400 +5592,4740,2777,3261, 576, 530,1362,4741,4742,2540,2676,3776,4120,5593, 842,3913, # 4416 +5594,2814,2032,1014,4121, 213,2709,3413, 665, 621,4380,5595,3777,2939,2435,5596, # 4432 +2436,3335,3643,3414,4743,4381,2541,4382,4744,3644,1682,4383,3531,1380,5597, 724, # 4448 +2282, 600,1670,5598,1337,1233,4745,3126,2248,5599,1621,4746,5600, 651,4384,5601, # 4464 +1612,4385,2621,5602,2857,5603,2743,2312,3078,5604, 716,2464,3079, 174,1255,2710, # 4480 +4122,3645, 548,1320,1398, 728,4123,1574,5605,1891,1197,3080,4124,5606,3081,3082, # 4496 +3778,3646,3779, 747,5607, 635,4386,4747,5608,5609,5610,4387,5611,5612,4748,5613, # 4512 +3415,4749,2437, 451,5614,3780,2542,2073,4388,2744,4389,4125,5615,1764,4750,5616, # 4528 +4390, 350,4751,2283,2395,2493,5617,4391,4126,2249,1434,4127, 488,4752, 458,4392, # 4544 +4128,3781, 771,1330,2396,3914,2576,3184,2160,2414,1553,2677,3185,4393,5618,2494, # 4560 +2895,2622,1720,2711,4394,3416,4753,5619,2543,4395,5620,3262,4396,2778,5621,2016, # 4576 +2745,5622,1155,1017,3782,3915,5623,3336,2313, 201,1865,4397,1430,5624,4129,5625, # 4592 +5626,5627,5628,5629,4398,1604,5630, 414,1866, 371,2595,4754,4755,3532,2017,3127, # 4608 +4756,1708, 960,4399, 887, 389,2172,1536,1663,1721,5631,2232,4130,2356,2940,1580, # 4624 +5632,5633,1744,4757,2544,4758,4759,5634,4760,5635,2074,5636,4761,3647,3417,2896, # 4640 +4400,5637,4401,2650,3418,2815, 673,2712,2465, 709,3533,4131,3648,4402,5638,1148, # 4656 + 502, 634,5639,5640,1204,4762,3649,1575,4763,2623,3783,5641,3784,3128, 948,3263, # 4672 + 121,1745,3916,1110,5642,4403,3083,2516,3027,4132,3785,1151,1771,3917,1488,4133, # 4688 +1987,5643,2438,3534,5644,5645,2094,5646,4404,3918,1213,1407,2816, 531,2746,2545, # 4704 +3264,1011,1537,4764,2779,4405,3129,1061,5647,3786,3787,1867,2897,5648,2018, 120, # 4720 +4406,4407,2063,3650,3265,2314,3919,2678,3419,1955,4765,4134,5649,3535,1047,2713, # 4736 +1266,5650,1368,4766,2858, 649,3420,3920,2546,2747,1102,2859,2679,5651,5652,2000, # 4752 +5653,1111,3651,2977,5654,2495,3921,3652,2817,1855,3421,3788,5655,5656,3422,2415, # 4768 +2898,3337,3266,3653,5657,2577,5658,3654,2818,4135,1460, 856,5659,3655,5660,2899, # 4784 +2978,5661,2900,3922,5662,4408, 632,2517, 875,3923,1697,3924,2296,5663,5664,4767, # 4800 +3028,1239, 580,4768,4409,5665, 914, 936,2075,1190,4136,1039,2124,5666,5667,5668, # 4816 +5669,3423,1473,5670,1354,4410,3925,4769,2173,3084,4137, 915,3338,4411,4412,3339, # 4832 +1605,1835,5671,2748, 398,3656,4413,3926,4138, 328,1913,2860,4139,3927,1331,4414, # 4848 +3029, 937,4415,5672,3657,4140,4141,3424,2161,4770,3425, 524, 742, 538,3085,1012, # 4864 +5673,5674,3928,2466,5675, 658,1103, 225,3929,5676,5677,4771,5678,4772,5679,3267, # 4880 +1243,5680,4142, 963,2250,4773,5681,2714,3658,3186,5682,5683,2596,2332,5684,4774, # 4896 +5685,5686,5687,3536, 957,3426,2547,2033,1931,2941,2467, 870,2019,3659,1746,2780, # 4912 +2781,2439,2468,5688,3930,5689,3789,3130,3790,3537,3427,3791,5690,1179,3086,5691, # 4928 +3187,2378,4416,3792,2548,3188,3131,2749,4143,5692,3428,1556,2549,2297, 977,2901, # 4944 +2034,4144,1205,3429,5693,1765,3430,3189,2125,1271, 714,1689,4775,3538,5694,2333, # 4960 +3931, 533,4417,3660,2184, 617,5695,2469,3340,3539,2315,5696,5697,3190,5698,5699, # 4976 +3932,1988, 618, 427,2651,3540,3431,5700,5701,1244,1690,5702,2819,4418,4776,5703, # 4992 +3541,4777,5704,2284,1576, 473,3661,4419,3432, 972,5705,3662,5706,3087,5707,5708, # 5008 +4778,4779,5709,3793,4145,4146,5710, 153,4780, 356,5711,1892,2902,4420,2144, 408, # 5024 + 803,2357,5712,3933,5713,4421,1646,2578,2518,4781,4782,3934,5714,3935,4422,5715, # 5040 +2416,3433, 752,5716,5717,1962,3341,2979,5718, 746,3030,2470,4783,4423,3794, 698, # 5056 +4784,1893,4424,3663,2550,4785,3664,3936,5719,3191,3434,5720,1824,1302,4147,2715, # 5072 +3937,1974,4425,5721,4426,3192, 823,1303,1288,1236,2861,3542,4148,3435, 774,3938, # 5088 +5722,1581,4786,1304,2862,3939,4787,5723,2440,2162,1083,3268,4427,4149,4428, 344, # 5104 +1173, 288,2316, 454,1683,5724,5725,1461,4788,4150,2597,5726,5727,4789, 985, 894, # 5120 +5728,3436,3193,5729,1914,2942,3795,1989,5730,2111,1975,5731,4151,5732,2579,1194, # 5136 + 425,5733,4790,3194,1245,3796,4429,5734,5735,2863,5736, 636,4791,1856,3940, 760, # 5152 +1800,5737,4430,2212,1508,4792,4152,1894,1684,2298,5738,5739,4793,4431,4432,2213, # 5168 + 479,5740,5741, 832,5742,4153,2496,5743,2980,2497,3797, 990,3132, 627,1815,2652, # 5184 +4433,1582,4434,2126,2112,3543,4794,5744, 799,4435,3195,5745,4795,2113,1737,3031, # 5200 +1018, 543, 754,4436,3342,1676,4796,4797,4154,4798,1489,5746,3544,5747,2624,2903, # 5216 +4155,5748,5749,2981,5750,5751,5752,5753,3196,4799,4800,2185,1722,5754,3269,3270, # 5232 +1843,3665,1715, 481, 365,1976,1857,5755,5756,1963,2498,4801,5757,2127,3666,3271, # 5248 + 433,1895,2064,2076,5758, 602,2750,5759,5760,5761,5762,5763,3032,1628,3437,5764, # 5264 +3197,4802,4156,2904,4803,2519,5765,2551,2782,5766,5767,5768,3343,4804,2905,5769, # 5280 +4805,5770,2864,4806,4807,1221,2982,4157,2520,5771,5772,5773,1868,1990,5774,5775, # 5296 +5776,1896,5777,5778,4808,1897,4158, 318,5779,2095,4159,4437,5780,5781, 485,5782, # 5312 + 938,3941, 553,2680, 116,5783,3942,3667,5784,3545,2681,2783,3438,3344,2820,5785, # 5328 +3668,2943,4160,1747,2944,2983,5786,5787, 207,5788,4809,5789,4810,2521,5790,3033, # 5344 + 890,3669,3943,5791,1878,3798,3439,5792,2186,2358,3440,1652,5793,5794,5795, 941, # 5360 +2299, 208,3546,4161,2020, 330,4438,3944,2906,2499,3799,4439,4811,5796,5797,5798, # 5376 +) + diff --git a/venv/Lib/site-packages/requests/packages/chardet/big5prober.py b/venv/Lib/site-packages/chardet/big5prober.py similarity index 82% rename from venv/Lib/site-packages/requests/packages/chardet/big5prober.py rename to venv/Lib/site-packages/chardet/big5prober.py index becce81e5..98f997012 100644 --- a/venv/Lib/site-packages/requests/packages/chardet/big5prober.py +++ b/venv/Lib/site-packages/chardet/big5prober.py @@ -28,15 +28,20 @@ from .mbcharsetprober import MultiByteCharSetProber from .codingstatemachine import CodingStateMachine from .chardistribution import Big5DistributionAnalysis -from .mbcssm import Big5SMModel +from .mbcssm import BIG5_SM_MODEL class Big5Prober(MultiByteCharSetProber): def __init__(self): - MultiByteCharSetProber.__init__(self) - self._mCodingSM = CodingStateMachine(Big5SMModel) - self._mDistributionAnalyzer = Big5DistributionAnalysis() + super(Big5Prober, self).__init__() + self.coding_sm = CodingStateMachine(BIG5_SM_MODEL) + self.distribution_analyzer = Big5DistributionAnalysis() self.reset() - def get_charset_name(self): + @property + def charset_name(self): return "Big5" + + @property + def language(self): + return "Chinese" diff --git a/venv/Lib/site-packages/requests/packages/chardet/chardistribution.py b/venv/Lib/site-packages/chardet/chardistribution.py similarity index 61% rename from venv/Lib/site-packages/requests/packages/chardet/chardistribution.py rename to venv/Lib/site-packages/chardet/chardistribution.py index 4e64a00be..c0395f4a4 100644 --- a/venv/Lib/site-packages/requests/packages/chardet/chardistribution.py +++ b/venv/Lib/site-packages/chardet/chardistribution.py @@ -25,82 +25,84 @@ # 02110-1301 USA ######################### END LICENSE BLOCK ######################### -from .euctwfreq import (EUCTWCharToFreqOrder, EUCTW_TABLE_SIZE, +from .euctwfreq import (EUCTW_CHAR_TO_FREQ_ORDER, EUCTW_TABLE_SIZE, EUCTW_TYPICAL_DISTRIBUTION_RATIO) -from .euckrfreq import (EUCKRCharToFreqOrder, EUCKR_TABLE_SIZE, +from .euckrfreq import (EUCKR_CHAR_TO_FREQ_ORDER, EUCKR_TABLE_SIZE, EUCKR_TYPICAL_DISTRIBUTION_RATIO) -from .gb2312freq import (GB2312CharToFreqOrder, GB2312_TABLE_SIZE, +from .gb2312freq import (GB2312_CHAR_TO_FREQ_ORDER, GB2312_TABLE_SIZE, GB2312_TYPICAL_DISTRIBUTION_RATIO) -from .big5freq import (Big5CharToFreqOrder, BIG5_TABLE_SIZE, +from .big5freq import (BIG5_CHAR_TO_FREQ_ORDER, BIG5_TABLE_SIZE, BIG5_TYPICAL_DISTRIBUTION_RATIO) -from .jisfreq import (JISCharToFreqOrder, JIS_TABLE_SIZE, +from .jisfreq import (JIS_CHAR_TO_FREQ_ORDER, JIS_TABLE_SIZE, JIS_TYPICAL_DISTRIBUTION_RATIO) -from .compat import wrap_ord - -ENOUGH_DATA_THRESHOLD = 1024 -SURE_YES = 0.99 -SURE_NO = 0.01 -MINIMUM_DATA_THRESHOLD = 3 -class CharDistributionAnalysis: +class CharDistributionAnalysis(object): + ENOUGH_DATA_THRESHOLD = 1024 + SURE_YES = 0.99 + SURE_NO = 0.01 + MINIMUM_DATA_THRESHOLD = 3 + def __init__(self): # Mapping table to get frequency order from char order (get from # GetOrder()) - self._mCharToFreqOrder = None - self._mTableSize = None # Size of above table + self._char_to_freq_order = None + self._table_size = None # Size of above table # This is a constant value which varies from language to language, # used in calculating confidence. See # http://www.mozilla.org/projects/intl/UniversalCharsetDetection.html # for further detail. - self._mTypicalDistributionRatio = None + self.typical_distribution_ratio = None + self._done = None + self._total_chars = None + self._freq_chars = None self.reset() def reset(self): """reset analyser, clear any state""" # If this flag is set to True, detection is done and conclusion has # been made - self._mDone = False - self._mTotalChars = 0 # Total characters encountered + self._done = False + self._total_chars = 0 # Total characters encountered # The number of characters whose frequency order is less than 512 - self._mFreqChars = 0 + self._freq_chars = 0 - def feed(self, aBuf, aCharLen): + def feed(self, char, char_len): """feed a character with known length""" - if aCharLen == 2: + if char_len == 2: # we only care about 2-bytes character in our distribution analysis - order = self.get_order(aBuf) + order = self.get_order(char) else: order = -1 if order >= 0: - self._mTotalChars += 1 + self._total_chars += 1 # order is valid - if order < self._mTableSize: - if 512 > self._mCharToFreqOrder[order]: - self._mFreqChars += 1 + if order < self._table_size: + if 512 > self._char_to_freq_order[order]: + self._freq_chars += 1 def get_confidence(self): """return confidence based on existing data""" # if we didn't receive any character in our consideration range, # return negative answer - if self._mTotalChars <= 0 or self._mFreqChars <= MINIMUM_DATA_THRESHOLD: - return SURE_NO + if self._total_chars <= 0 or self._freq_chars <= self.MINIMUM_DATA_THRESHOLD: + return self.SURE_NO - if self._mTotalChars != self._mFreqChars: - r = (self._mFreqChars / ((self._mTotalChars - self._mFreqChars) - * self._mTypicalDistributionRatio)) - if r < SURE_YES: + if self._total_chars != self._freq_chars: + r = (self._freq_chars / ((self._total_chars - self._freq_chars) + * self.typical_distribution_ratio)) + if r < self.SURE_YES: return r # normalize confidence (we don't want to be 100% sure) - return SURE_YES + return self.SURE_YES def got_enough_data(self): # It is not necessary to receive all data to draw conclusion. # For charset detection, certain amount of data is enough - return self._mTotalChars > ENOUGH_DATA_THRESHOLD + return self._total_chars > self.ENOUGH_DATA_THRESHOLD - def get_order(self, aBuf): + def get_order(self, byte_str): # We do not handle characters based on the original encoding string, # but convert this encoding string to a number, here called order. # This allows multiple encodings of a language to share one frequency @@ -110,55 +112,55 @@ class CharDistributionAnalysis: class EUCTWDistributionAnalysis(CharDistributionAnalysis): def __init__(self): - CharDistributionAnalysis.__init__(self) - self._mCharToFreqOrder = EUCTWCharToFreqOrder - self._mTableSize = EUCTW_TABLE_SIZE - self._mTypicalDistributionRatio = EUCTW_TYPICAL_DISTRIBUTION_RATIO + super(EUCTWDistributionAnalysis, self).__init__() + self._char_to_freq_order = EUCTW_CHAR_TO_FREQ_ORDER + self._table_size = EUCTW_TABLE_SIZE + self.typical_distribution_ratio = EUCTW_TYPICAL_DISTRIBUTION_RATIO - def get_order(self, aBuf): + def get_order(self, byte_str): # for euc-TW encoding, we are interested # first byte range: 0xc4 -- 0xfe # second byte range: 0xa1 -- 0xfe # no validation needed here. State machine has done that - first_char = wrap_ord(aBuf[0]) + first_char = byte_str[0] if first_char >= 0xC4: - return 94 * (first_char - 0xC4) + wrap_ord(aBuf[1]) - 0xA1 + return 94 * (first_char - 0xC4) + byte_str[1] - 0xA1 else: return -1 class EUCKRDistributionAnalysis(CharDistributionAnalysis): def __init__(self): - CharDistributionAnalysis.__init__(self) - self._mCharToFreqOrder = EUCKRCharToFreqOrder - self._mTableSize = EUCKR_TABLE_SIZE - self._mTypicalDistributionRatio = EUCKR_TYPICAL_DISTRIBUTION_RATIO + super(EUCKRDistributionAnalysis, self).__init__() + self._char_to_freq_order = EUCKR_CHAR_TO_FREQ_ORDER + self._table_size = EUCKR_TABLE_SIZE + self.typical_distribution_ratio = EUCKR_TYPICAL_DISTRIBUTION_RATIO - def get_order(self, aBuf): + def get_order(self, byte_str): # for euc-KR encoding, we are interested # first byte range: 0xb0 -- 0xfe # second byte range: 0xa1 -- 0xfe # no validation needed here. State machine has done that - first_char = wrap_ord(aBuf[0]) + first_char = byte_str[0] if first_char >= 0xB0: - return 94 * (first_char - 0xB0) + wrap_ord(aBuf[1]) - 0xA1 + return 94 * (first_char - 0xB0) + byte_str[1] - 0xA1 else: return -1 class GB2312DistributionAnalysis(CharDistributionAnalysis): def __init__(self): - CharDistributionAnalysis.__init__(self) - self._mCharToFreqOrder = GB2312CharToFreqOrder - self._mTableSize = GB2312_TABLE_SIZE - self._mTypicalDistributionRatio = GB2312_TYPICAL_DISTRIBUTION_RATIO + super(GB2312DistributionAnalysis, self).__init__() + self._char_to_freq_order = GB2312_CHAR_TO_FREQ_ORDER + self._table_size = GB2312_TABLE_SIZE + self.typical_distribution_ratio = GB2312_TYPICAL_DISTRIBUTION_RATIO - def get_order(self, aBuf): + def get_order(self, byte_str): # for GB2312 encoding, we are interested # first byte range: 0xb0 -- 0xfe # second byte range: 0xa1 -- 0xfe # no validation needed here. State machine has done that - first_char, second_char = wrap_ord(aBuf[0]), wrap_ord(aBuf[1]) + first_char, second_char = byte_str[0], byte_str[1] if (first_char >= 0xB0) and (second_char >= 0xA1): return 94 * (first_char - 0xB0) + second_char - 0xA1 else: @@ -167,17 +169,17 @@ class GB2312DistributionAnalysis(CharDistributionAnalysis): class Big5DistributionAnalysis(CharDistributionAnalysis): def __init__(self): - CharDistributionAnalysis.__init__(self) - self._mCharToFreqOrder = Big5CharToFreqOrder - self._mTableSize = BIG5_TABLE_SIZE - self._mTypicalDistributionRatio = BIG5_TYPICAL_DISTRIBUTION_RATIO + super(Big5DistributionAnalysis, self).__init__() + self._char_to_freq_order = BIG5_CHAR_TO_FREQ_ORDER + self._table_size = BIG5_TABLE_SIZE + self.typical_distribution_ratio = BIG5_TYPICAL_DISTRIBUTION_RATIO - def get_order(self, aBuf): + def get_order(self, byte_str): # for big5 encoding, we are interested # first byte range: 0xa4 -- 0xfe # second byte range: 0x40 -- 0x7e , 0xa1 -- 0xfe # no validation needed here. State machine has done that - first_char, second_char = wrap_ord(aBuf[0]), wrap_ord(aBuf[1]) + first_char, second_char = byte_str[0], byte_str[1] if first_char >= 0xA4: if second_char >= 0xA1: return 157 * (first_char - 0xA4) + second_char - 0xA1 + 63 @@ -189,17 +191,17 @@ class Big5DistributionAnalysis(CharDistributionAnalysis): class SJISDistributionAnalysis(CharDistributionAnalysis): def __init__(self): - CharDistributionAnalysis.__init__(self) - self._mCharToFreqOrder = JISCharToFreqOrder - self._mTableSize = JIS_TABLE_SIZE - self._mTypicalDistributionRatio = JIS_TYPICAL_DISTRIBUTION_RATIO + super(SJISDistributionAnalysis, self).__init__() + self._char_to_freq_order = JIS_CHAR_TO_FREQ_ORDER + self._table_size = JIS_TABLE_SIZE + self.typical_distribution_ratio = JIS_TYPICAL_DISTRIBUTION_RATIO - def get_order(self, aBuf): + def get_order(self, byte_str): # for sjis encoding, we are interested # first byte range: 0x81 -- 0x9f , 0xe0 -- 0xfe # second byte range: 0x40 -- 0x7e, 0x81 -- oxfe # no validation needed here. State machine has done that - first_char, second_char = wrap_ord(aBuf[0]), wrap_ord(aBuf[1]) + first_char, second_char = byte_str[0], byte_str[1] if (first_char >= 0x81) and (first_char <= 0x9F): order = 188 * (first_char - 0x81) elif (first_char >= 0xE0) and (first_char <= 0xEF): @@ -214,18 +216,18 @@ class SJISDistributionAnalysis(CharDistributionAnalysis): class EUCJPDistributionAnalysis(CharDistributionAnalysis): def __init__(self): - CharDistributionAnalysis.__init__(self) - self._mCharToFreqOrder = JISCharToFreqOrder - self._mTableSize = JIS_TABLE_SIZE - self._mTypicalDistributionRatio = JIS_TYPICAL_DISTRIBUTION_RATIO + super(EUCJPDistributionAnalysis, self).__init__() + self._char_to_freq_order = JIS_CHAR_TO_FREQ_ORDER + self._table_size = JIS_TABLE_SIZE + self.typical_distribution_ratio = JIS_TYPICAL_DISTRIBUTION_RATIO - def get_order(self, aBuf): + def get_order(self, byte_str): # for euc-JP encoding, we are interested # first byte range: 0xa0 -- 0xfe # second byte range: 0xa1 -- 0xfe # no validation needed here. State machine has done that - char = wrap_ord(aBuf[0]) + char = byte_str[0] if char >= 0xA0: - return 94 * (char - 0xA1) + wrap_ord(aBuf[1]) - 0xa1 + return 94 * (char - 0xA1) + byte_str[1] - 0xa1 else: return -1 diff --git a/venv/Lib/site-packages/chardet/charsetgroupprober.py b/venv/Lib/site-packages/chardet/charsetgroupprober.py new file mode 100644 index 000000000..8b3738efd --- /dev/null +++ b/venv/Lib/site-packages/chardet/charsetgroupprober.py @@ -0,0 +1,106 @@ +######################## BEGIN LICENSE BLOCK ######################## +# The Original Code is Mozilla Communicator client code. +# +# The Initial Developer of the Original Code is +# Netscape Communications Corporation. +# Portions created by the Initial Developer are Copyright (C) 1998 +# the Initial Developer. All Rights Reserved. +# +# Contributor(s): +# Mark Pilgrim - port to Python +# +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; either +# version 2.1 of the License, or (at your option) any later version. +# +# This library 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 +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this library; if not, write to the Free Software +# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA +# 02110-1301 USA +######################### END LICENSE BLOCK ######################### + +from .enums import ProbingState +from .charsetprober import CharSetProber + + +class CharSetGroupProber(CharSetProber): + def __init__(self, lang_filter=None): + super(CharSetGroupProber, self).__init__(lang_filter=lang_filter) + self._active_num = 0 + self.probers = [] + self._best_guess_prober = None + + def reset(self): + super(CharSetGroupProber, self).reset() + self._active_num = 0 + for prober in self.probers: + if prober: + prober.reset() + prober.active = True + self._active_num += 1 + self._best_guess_prober = None + + @property + def charset_name(self): + if not self._best_guess_prober: + self.get_confidence() + if not self._best_guess_prober: + return None + return self._best_guess_prober.charset_name + + @property + def language(self): + if not self._best_guess_prober: + self.get_confidence() + if not self._best_guess_prober: + return None + return self._best_guess_prober.language + + def feed(self, byte_str): + for prober in self.probers: + if not prober: + continue + if not prober.active: + continue + state = prober.feed(byte_str) + if not state: + continue + if state == ProbingState.FOUND_IT: + self._best_guess_prober = prober + return self.state + elif state == ProbingState.NOT_ME: + prober.active = False + self._active_num -= 1 + if self._active_num <= 0: + self._state = ProbingState.NOT_ME + return self.state + return self.state + + def get_confidence(self): + state = self.state + if state == ProbingState.FOUND_IT: + return 0.99 + elif state == ProbingState.NOT_ME: + return 0.01 + best_conf = 0.0 + self._best_guess_prober = None + for prober in self.probers: + if not prober: + continue + if not prober.active: + self.logger.debug('%s not active', prober.charset_name) + continue + conf = prober.get_confidence() + self.logger.debug('%s %s confidence = %s', prober.charset_name, prober.language, conf) + if best_conf < conf: + best_conf = conf + self._best_guess_prober = prober + if not self._best_guess_prober: + return 0.0 + return best_conf diff --git a/venv/Lib/site-packages/chardet/charsetprober.py b/venv/Lib/site-packages/chardet/charsetprober.py new file mode 100644 index 000000000..eac4e5986 --- /dev/null +++ b/venv/Lib/site-packages/chardet/charsetprober.py @@ -0,0 +1,145 @@ +######################## BEGIN LICENSE BLOCK ######################## +# The Original Code is Mozilla Universal charset detector code. +# +# The Initial Developer of the Original Code is +# Netscape Communications Corporation. +# Portions created by the Initial Developer are Copyright (C) 2001 +# the Initial Developer. All Rights Reserved. +# +# Contributor(s): +# Mark Pilgrim - port to Python +# Shy Shalom - original C code +# +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; either +# version 2.1 of the License, or (at your option) any later version. +# +# This library 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 +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this library; if not, write to the Free Software +# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA +# 02110-1301 USA +######################### END LICENSE BLOCK ######################### + +import logging +import re + +from .enums import ProbingState + + +class CharSetProber(object): + + SHORTCUT_THRESHOLD = 0.95 + + def __init__(self, lang_filter=None): + self._state = None + self.lang_filter = lang_filter + self.logger = logging.getLogger(__name__) + + def reset(self): + self._state = ProbingState.DETECTING + + @property + def charset_name(self): + return None + + def feed(self, buf): + pass + + @property + def state(self): + return self._state + + def get_confidence(self): + return 0.0 + + @staticmethod + def filter_high_byte_only(buf): + buf = re.sub(b'([\x00-\x7F])+', b' ', buf) + return buf + + @staticmethod + def filter_international_words(buf): + """ + We define three types of bytes: + alphabet: english alphabets [a-zA-Z] + international: international characters [\x80-\xFF] + marker: everything else [^a-zA-Z\x80-\xFF] + + The input buffer can be thought to contain a series of words delimited + by markers. This function works to filter all words that contain at + least one international character. All contiguous sequences of markers + are replaced by a single space ascii character. + + This filter applies to all scripts which do not use English characters. + """ + filtered = bytearray() + + # This regex expression filters out only words that have at-least one + # international character. The word may include one marker character at + # the end. + words = re.findall(b'[a-zA-Z]*[\x80-\xFF]+[a-zA-Z]*[^a-zA-Z\x80-\xFF]?', + buf) + + for word in words: + filtered.extend(word[:-1]) + + # If the last character in the word is a marker, replace it with a + # space as markers shouldn't affect our analysis (they are used + # similarly across all languages and may thus have similar + # frequencies). + last_char = word[-1:] + if not last_char.isalpha() and last_char < b'\x80': + last_char = b' ' + filtered.extend(last_char) + + return filtered + + @staticmethod + def filter_with_english_letters(buf): + """ + Returns a copy of ``buf`` that retains only the sequences of English + alphabet and high byte characters that are not between <> characters. + Also retains English alphabet and high byte characters immediately + before occurrences of >. + + This filter can be applied to all scripts which contain both English + characters and extended ASCII characters, but is currently only used by + ``Latin1Prober``. + """ + filtered = bytearray() + in_tag = False + prev = 0 + + for curr in range(len(buf)): + # Slice here to get bytes instead of an int with Python 3 + buf_char = buf[curr:curr + 1] + # Check if we're coming out of or entering an HTML tag + if buf_char == b'>': + in_tag = False + elif buf_char == b'<': + in_tag = True + + # If current character is not extended-ASCII and not alphabetic... + if buf_char < b'\x80' and not buf_char.isalpha(): + # ...and we're not in a tag + if curr > prev and not in_tag: + # Keep everything after last non-extended-ASCII, + # non-alphabetic character + filtered.extend(buf[prev:curr]) + # Output a space to delimit stretch we kept + filtered.extend(b' ') + prev = curr + 1 + + # If we're not in a tag... + if not in_tag: + # Keep everything after last non-extended-ASCII, non-alphabetic + # character + filtered.extend(buf[prev:]) + + return filtered diff --git a/venv/Lib/site-packages/chardet/cli/__init__.py b/venv/Lib/site-packages/chardet/cli/__init__.py new file mode 100644 index 000000000..8b1378917 --- /dev/null +++ b/venv/Lib/site-packages/chardet/cli/__init__.py @@ -0,0 +1 @@ + diff --git a/venv/Lib/site-packages/chardet/cli/__pycache__/__init__.cpython-36.pyc b/venv/Lib/site-packages/chardet/cli/__pycache__/__init__.cpython-36.pyc new file mode 100644 index 0000000000000000000000000000000000000000..c8138669ed8362a1a7955360e16d05b55e414d7d GIT binary patch literal 246 zcmYL@F-yci6omJ{LWKJd+ghB*=`|-JHg;lT`(WAI%q7nxyJ6o;B)$K{%D-gmzp!%C z=)gC{FavY5USB-c?`~y``7Zov2_6b^R;)5F=5qD?Y4Q^P+s{Y1rBRTDj$X%xQbd(` z0#%S!(?Db7x0G9&;j`V7pob{3-BCcjKkTk)$mtb9X+p!HgY{8)qYX}KPd>nAgj7dX zPSMI-#(k;AiJtgK!ivq{L+fh@g~sO!x(yv~o#V1`?rNC7&hPqEjUDcn^HMOs1-wgx literal 0 HcmV?d00001 diff --git a/venv/Lib/site-packages/chardet/cli/__pycache__/chardetect.cpython-36.pyc b/venv/Lib/site-packages/chardet/cli/__pycache__/chardetect.cpython-36.pyc new file mode 100644 index 0000000000000000000000000000000000000000..99dd973179d74c058340c4c932f7f6108d404245 GIT binary patch literal 3134 zcmd5;OOIQ(6}~TBY3^v`ap44U>KI%!trb{`XF3TIp(q-}DH^~S3=+3NR3+C}A|+kT zeJCU~W67G8vNez&&|T3*xA{5TX4StCAV9xENn;t_v{@9rg2+Si@bEl8^0x;E(I=yC zZy<-gYm<`He zm~xyU*n{?a*X-8uQr zU){a(wY&6J?v=mvCLU3)1Im~6Gv}N77eogXW%QM+K!@^d=}xM;HrZPtpH|+Ly9~H@ z+mQwLC(&{r1ykFq zvAFZ>!BvMnJGy!$-<};`ndn8bE*h2-*(ZgXW%{(aFRKWs*&{_0DU-PghC*-?a8#YC z46;%Q6Rx>sNUR|jlv&1Cb7fwGOUMY&TI5@WOgJoMp6F)9RID*3ARCN3GXag|Aq4%? zk+;$P_>V!SH&aN!UO&;ZaS!KmiHz(apy#@r_K?b#r9AJ=p&&cyDV&4DBs=O2#OUP1 zqvIZ8J%Rgr7XqjO$0vnOTL{z;<&&U9B{UutsrBz#Q?M2ny+>)kr%)iRX)-uZMnd&A z$nfqUOW%Eg67A{SG}iewB_VM+d=sjxJ7}CJbR)OsMqcQK=tDPf57E~#BY%nY0Z`3; z0a|jlEu-&1XlLRQ$Ub*b0`A1)J`XVG^UBKQp$_CdU73VMNbRILa(VT61!Y8>08}1L zYI+Zx`_Fwl8!a6aq4)Fzg|?5vdc{sd@6Op%s(PAE$;V~HHi5McllO(E_IwLk!i`bi`p_vQKl`$dO6 z+LYM!=KBCfmZIjSVvr6~!8g#oJ*!1$t&56^@%jU1o+2~uvnNjw!8S?%>rv;cCr?>3HVy2vB2}taLeqG%Z`^m9feFSUo0@1jQQWn-Um726u;q+~($o{qW2{=dF*Pcn$H;1X|Hxk;J!K7z3H!6* zP)K=;X6TV(A}f!!D*2XWNmZit+*IuQ$b@*S+NO?6Xs*1B$EGin2u@dUQ+=-%E=;+kAPm`)@elzlZ<; literal 0 HcmV?d00001 diff --git a/venv/Lib/site-packages/requests/packages/chardet/chardetect.py b/venv/Lib/site-packages/chardet/cli/chardetect.py similarity index 83% rename from venv/Lib/site-packages/requests/packages/chardet/chardetect.py rename to venv/Lib/site-packages/chardet/cli/chardetect.py index ffe892f25..f0a4cc5d7 100644 --- a/venv/Lib/site-packages/requests/packages/chardet/chardetect.py +++ b/venv/Lib/site-packages/chardet/cli/chardetect.py @@ -17,9 +17,9 @@ from __future__ import absolute_import, print_function, unicode_literals import argparse import sys -from io import open from chardet import __version__ +from chardet.compat import PY2 from chardet.universaldetector import UniversalDetector @@ -35,9 +35,15 @@ def description_of(lines, name='stdin'): """ u = UniversalDetector() for line in lines: + line = bytearray(line) u.feed(line) + # shortcut out of the loop to save reading further - particularly useful if we read a BOM. + if u.done: + break u.close() result = u.result + if PY2: + name = name.decode(sys.getfilesystemencoding(), 'ignore') if result['encoding']: return '{0}: {1} with confidence {2}'.format(name, result['encoding'], result['confidence']) @@ -46,23 +52,22 @@ def description_of(lines, name='stdin'): def main(argv=None): - ''' + """ Handles command line arguments and gets things started. :param argv: List of arguments, as if specified on the command-line. If None, ``sys.argv[1:]`` is used instead. :type argv: list of str - ''' + """ # Get command line arguments parser = argparse.ArgumentParser( description="Takes one or more file paths and reports their detected \ - encodings", - formatter_class=argparse.ArgumentDefaultsHelpFormatter, - conflict_handler='resolve') + encodings") parser.add_argument('input', - help='File whose encoding we would like to determine.', + help='File whose encoding we would like to determine. \ + (default: stdin)', type=argparse.FileType('rb'), nargs='*', - default=[sys.stdin]) + default=[sys.stdin if PY2 else sys.stdin.buffer]) parser.add_argument('--version', action='version', version='%(prog)s {0}'.format(__version__)) args = parser.parse_args(argv) diff --git a/venv/Lib/site-packages/chardet/codingstatemachine.py b/venv/Lib/site-packages/chardet/codingstatemachine.py new file mode 100644 index 000000000..68fba44f1 --- /dev/null +++ b/venv/Lib/site-packages/chardet/codingstatemachine.py @@ -0,0 +1,88 @@ +######################## BEGIN LICENSE BLOCK ######################## +# The Original Code is mozilla.org code. +# +# The Initial Developer of the Original Code is +# Netscape Communications Corporation. +# Portions created by the Initial Developer are Copyright (C) 1998 +# the Initial Developer. All Rights Reserved. +# +# Contributor(s): +# Mark Pilgrim - port to Python +# +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; either +# version 2.1 of the License, or (at your option) any later version. +# +# This library 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 +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this library; if not, write to the Free Software +# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA +# 02110-1301 USA +######################### END LICENSE BLOCK ######################### + +import logging + +from .enums import MachineState + + +class CodingStateMachine(object): + """ + A state machine to verify a byte sequence for a particular encoding. For + each byte the detector receives, it will feed that byte to every active + state machine available, one byte at a time. The state machine changes its + state based on its previous state and the byte it receives. There are 3 + states in a state machine that are of interest to an auto-detector: + + START state: This is the state to start with, or a legal byte sequence + (i.e. a valid code point) for character has been identified. + + ME state: This indicates that the state machine identified a byte sequence + that is specific to the charset it is designed for and that + there is no other possible encoding which can contain this byte + sequence. This will to lead to an immediate positive answer for + the detector. + + ERROR state: This indicates the state machine identified an illegal byte + sequence for that encoding. This will lead to an immediate + negative answer for this encoding. Detector will exclude this + encoding from consideration from here on. + """ + def __init__(self, sm): + self._model = sm + self._curr_byte_pos = 0 + self._curr_char_len = 0 + self._curr_state = None + self.logger = logging.getLogger(__name__) + self.reset() + + def reset(self): + self._curr_state = MachineState.START + + def next_state(self, c): + # for each byte we get its class + # if it is first byte, we also get byte length + byte_class = self._model['class_table'][c] + if self._curr_state == MachineState.START: + self._curr_byte_pos = 0 + self._curr_char_len = self._model['char_len_table'][byte_class] + # from byte's class and state_table, we get its next state + curr_state = (self._curr_state * self._model['class_factor'] + + byte_class) + self._curr_state = self._model['state_table'][curr_state] + self._curr_byte_pos += 1 + return self._curr_state + + def get_current_charlen(self): + return self._curr_char_len + + def get_coding_state_machine(self): + return self._model['name'] + + @property + def language(self): + return self._model['language'] diff --git a/venv/Lib/site-packages/requests/packages/chardet/compat.py b/venv/Lib/site-packages/chardet/compat.py similarity index 85% rename from venv/Lib/site-packages/requests/packages/chardet/compat.py rename to venv/Lib/site-packages/chardet/compat.py index d9e30addf..ddd74687c 100644 --- a/venv/Lib/site-packages/requests/packages/chardet/compat.py +++ b/venv/Lib/site-packages/chardet/compat.py @@ -1,6 +1,7 @@ ######################## BEGIN LICENSE BLOCK ######################## # Contributor(s): -# Ian Cordasco - port to Python +# Dan Blanchard +# Ian Cordasco # # This library is free software; you can redistribute it and/or # modify it under the terms of the GNU Lesser General Public @@ -22,13 +23,12 @@ import sys if sys.version_info < (3, 0): + PY2 = True + PY3 = False base_str = (str, unicode) + text_type = unicode else: + PY2 = False + PY3 = True base_str = (bytes, str) - - -def wrap_ord(a): - if sys.version_info < (3, 0) and isinstance(a, base_str): - return ord(a) - else: - return a + text_type = str diff --git a/venv/Lib/site-packages/requests/packages/chardet/cp949prober.py b/venv/Lib/site-packages/chardet/cp949prober.py similarity index 83% rename from venv/Lib/site-packages/requests/packages/chardet/cp949prober.py rename to venv/Lib/site-packages/chardet/cp949prober.py index ff4272f82..efd793abc 100644 --- a/venv/Lib/site-packages/requests/packages/chardet/cp949prober.py +++ b/venv/Lib/site-packages/chardet/cp949prober.py @@ -25,20 +25,25 @@ # 02110-1301 USA ######################### END LICENSE BLOCK ######################### -from .mbcharsetprober import MultiByteCharSetProber -from .codingstatemachine import CodingStateMachine from .chardistribution import EUCKRDistributionAnalysis -from .mbcssm import CP949SMModel +from .codingstatemachine import CodingStateMachine +from .mbcharsetprober import MultiByteCharSetProber +from .mbcssm import CP949_SM_MODEL class CP949Prober(MultiByteCharSetProber): def __init__(self): - MultiByteCharSetProber.__init__(self) - self._mCodingSM = CodingStateMachine(CP949SMModel) + super(CP949Prober, self).__init__() + self.coding_sm = CodingStateMachine(CP949_SM_MODEL) # NOTE: CP949 is a superset of EUC-KR, so the distribution should be # not different. - self._mDistributionAnalyzer = EUCKRDistributionAnalysis() + self.distribution_analyzer = EUCKRDistributionAnalysis() self.reset() - def get_charset_name(self): + @property + def charset_name(self): return "CP949" + + @property + def language(self): + return "Korean" diff --git a/venv/Lib/site-packages/chardet/enums.py b/venv/Lib/site-packages/chardet/enums.py new file mode 100644 index 000000000..045120722 --- /dev/null +++ b/venv/Lib/site-packages/chardet/enums.py @@ -0,0 +1,76 @@ +""" +All of the Enums that are used throughout the chardet package. + +:author: Dan Blanchard (dan.blanchard@gmail.com) +""" + + +class InputState(object): + """ + This enum represents the different states a universal detector can be in. + """ + PURE_ASCII = 0 + ESC_ASCII = 1 + HIGH_BYTE = 2 + + +class LanguageFilter(object): + """ + This enum represents the different language filters we can apply to a + ``UniversalDetector``. + """ + CHINESE_SIMPLIFIED = 0x01 + CHINESE_TRADITIONAL = 0x02 + JAPANESE = 0x04 + KOREAN = 0x08 + NON_CJK = 0x10 + ALL = 0x1F + CHINESE = CHINESE_SIMPLIFIED | CHINESE_TRADITIONAL + CJK = CHINESE | JAPANESE | KOREAN + + +class ProbingState(object): + """ + This enum represents the different states a prober can be in. + """ + DETECTING = 0 + FOUND_IT = 1 + NOT_ME = 2 + + +class MachineState(object): + """ + This enum represents the different states a state machine can be in. + """ + START = 0 + ERROR = 1 + ITS_ME = 2 + + +class SequenceLikelihood(object): + """ + This enum represents the likelihood of a character following the previous one. + """ + NEGATIVE = 0 + UNLIKELY = 1 + LIKELY = 2 + POSITIVE = 3 + + @classmethod + def get_num_categories(cls): + """:returns: The number of likelihood categories in the enum.""" + return 4 + + +class CharacterCategory(object): + """ + This enum represents the different categories language models for + ``SingleByteCharsetProber`` put characters into. + + Anything less than CONTROL is considered a letter. + """ + UNDEFINED = 255 + LINE_BREAK = 254 + SYMBOL = 253 + DIGIT = 252 + CONTROL = 251 diff --git a/venv/Lib/site-packages/chardet/escprober.py b/venv/Lib/site-packages/chardet/escprober.py new file mode 100644 index 000000000..c70493f2b --- /dev/null +++ b/venv/Lib/site-packages/chardet/escprober.py @@ -0,0 +1,101 @@ +######################## BEGIN LICENSE BLOCK ######################## +# The Original Code is mozilla.org code. +# +# The Initial Developer of the Original Code is +# Netscape Communications Corporation. +# Portions created by the Initial Developer are Copyright (C) 1998 +# the Initial Developer. All Rights Reserved. +# +# Contributor(s): +# Mark Pilgrim - port to Python +# +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; either +# version 2.1 of the License, or (at your option) any later version. +# +# This library 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 +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this library; if not, write to the Free Software +# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA +# 02110-1301 USA +######################### END LICENSE BLOCK ######################### + +from .charsetprober import CharSetProber +from .codingstatemachine import CodingStateMachine +from .enums import LanguageFilter, ProbingState, MachineState +from .escsm import (HZ_SM_MODEL, ISO2022CN_SM_MODEL, ISO2022JP_SM_MODEL, + ISO2022KR_SM_MODEL) + + +class EscCharSetProber(CharSetProber): + """ + This CharSetProber uses a "code scheme" approach for detecting encodings, + whereby easily recognizable escape or shift sequences are relied on to + identify these encodings. + """ + + def __init__(self, lang_filter=None): + super(EscCharSetProber, self).__init__(lang_filter=lang_filter) + self.coding_sm = [] + if self.lang_filter & LanguageFilter.CHINESE_SIMPLIFIED: + self.coding_sm.append(CodingStateMachine(HZ_SM_MODEL)) + self.coding_sm.append(CodingStateMachine(ISO2022CN_SM_MODEL)) + if self.lang_filter & LanguageFilter.JAPANESE: + self.coding_sm.append(CodingStateMachine(ISO2022JP_SM_MODEL)) + if self.lang_filter & LanguageFilter.KOREAN: + self.coding_sm.append(CodingStateMachine(ISO2022KR_SM_MODEL)) + self.active_sm_count = None + self._detected_charset = None + self._detected_language = None + self._state = None + self.reset() + + def reset(self): + super(EscCharSetProber, self).reset() + for coding_sm in self.coding_sm: + if not coding_sm: + continue + coding_sm.active = True + coding_sm.reset() + self.active_sm_count = len(self.coding_sm) + self._detected_charset = None + self._detected_language = None + + @property + def charset_name(self): + return self._detected_charset + + @property + def language(self): + return self._detected_language + + def get_confidence(self): + if self._detected_charset: + return 0.99 + else: + return 0.00 + + def feed(self, byte_str): + for c in byte_str: + for coding_sm in self.coding_sm: + if not coding_sm or not coding_sm.active: + continue + coding_state = coding_sm.next_state(c) + if coding_state == MachineState.ERROR: + coding_sm.active = False + self.active_sm_count -= 1 + if self.active_sm_count <= 0: + self._state = ProbingState.NOT_ME + return self.state + elif coding_state == MachineState.ITS_ME: + self._state = ProbingState.FOUND_IT + self._detected_charset = coding_sm.get_coding_state_machine() + self._detected_language = coding_sm.language + return self.state + + return self.state diff --git a/venv/Lib/site-packages/chardet/escsm.py b/venv/Lib/site-packages/chardet/escsm.py new file mode 100644 index 000000000..0069523a0 --- /dev/null +++ b/venv/Lib/site-packages/chardet/escsm.py @@ -0,0 +1,246 @@ +######################## BEGIN LICENSE BLOCK ######################## +# The Original Code is mozilla.org code. +# +# The Initial Developer of the Original Code is +# Netscape Communications Corporation. +# Portions created by the Initial Developer are Copyright (C) 1998 +# the Initial Developer. All Rights Reserved. +# +# Contributor(s): +# Mark Pilgrim - port to Python +# +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; either +# version 2.1 of the License, or (at your option) any later version. +# +# This library 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 +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this library; if not, write to the Free Software +# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA +# 02110-1301 USA +######################### END LICENSE BLOCK ######################### + +from .enums import MachineState + +HZ_CLS = ( +1,0,0,0,0,0,0,0, # 00 - 07 +0,0,0,0,0,0,0,0, # 08 - 0f +0,0,0,0,0,0,0,0, # 10 - 17 +0,0,0,1,0,0,0,0, # 18 - 1f +0,0,0,0,0,0,0,0, # 20 - 27 +0,0,0,0,0,0,0,0, # 28 - 2f +0,0,0,0,0,0,0,0, # 30 - 37 +0,0,0,0,0,0,0,0, # 38 - 3f +0,0,0,0,0,0,0,0, # 40 - 47 +0,0,0,0,0,0,0,0, # 48 - 4f +0,0,0,0,0,0,0,0, # 50 - 57 +0,0,0,0,0,0,0,0, # 58 - 5f +0,0,0,0,0,0,0,0, # 60 - 67 +0,0,0,0,0,0,0,0, # 68 - 6f +0,0,0,0,0,0,0,0, # 70 - 77 +0,0,0,4,0,5,2,0, # 78 - 7f +1,1,1,1,1,1,1,1, # 80 - 87 +1,1,1,1,1,1,1,1, # 88 - 8f +1,1,1,1,1,1,1,1, # 90 - 97 +1,1,1,1,1,1,1,1, # 98 - 9f +1,1,1,1,1,1,1,1, # a0 - a7 +1,1,1,1,1,1,1,1, # a8 - af +1,1,1,1,1,1,1,1, # b0 - b7 +1,1,1,1,1,1,1,1, # b8 - bf +1,1,1,1,1,1,1,1, # c0 - c7 +1,1,1,1,1,1,1,1, # c8 - cf +1,1,1,1,1,1,1,1, # d0 - d7 +1,1,1,1,1,1,1,1, # d8 - df +1,1,1,1,1,1,1,1, # e0 - e7 +1,1,1,1,1,1,1,1, # e8 - ef +1,1,1,1,1,1,1,1, # f0 - f7 +1,1,1,1,1,1,1,1, # f8 - ff +) + +HZ_ST = ( +MachineState.START,MachineState.ERROR, 3,MachineState.START,MachineState.START,MachineState.START,MachineState.ERROR,MachineState.ERROR,# 00-07 +MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ITS_ME,MachineState.ITS_ME,MachineState.ITS_ME,MachineState.ITS_ME,# 08-0f +MachineState.ITS_ME,MachineState.ITS_ME,MachineState.ERROR,MachineState.ERROR,MachineState.START,MachineState.START, 4,MachineState.ERROR,# 10-17 + 5,MachineState.ERROR, 6,MachineState.ERROR, 5, 5, 4,MachineState.ERROR,# 18-1f + 4,MachineState.ERROR, 4, 4, 4,MachineState.ERROR, 4,MachineState.ERROR,# 20-27 + 4,MachineState.ITS_ME,MachineState.START,MachineState.START,MachineState.START,MachineState.START,MachineState.START,MachineState.START,# 28-2f +) + +HZ_CHAR_LEN_TABLE = (0, 0, 0, 0, 0, 0) + +HZ_SM_MODEL = {'class_table': HZ_CLS, + 'class_factor': 6, + 'state_table': HZ_ST, + 'char_len_table': HZ_CHAR_LEN_TABLE, + 'name': "HZ-GB-2312", + 'language': 'Chinese'} + +ISO2022CN_CLS = ( +2,0,0,0,0,0,0,0, # 00 - 07 +0,0,0,0,0,0,0,0, # 08 - 0f +0,0,0,0,0,0,0,0, # 10 - 17 +0,0,0,1,0,0,0,0, # 18 - 1f +0,0,0,0,0,0,0,0, # 20 - 27 +0,3,0,0,0,0,0,0, # 28 - 2f +0,0,0,0,0,0,0,0, # 30 - 37 +0,0,0,0,0,0,0,0, # 38 - 3f +0,0,0,4,0,0,0,0, # 40 - 47 +0,0,0,0,0,0,0,0, # 48 - 4f +0,0,0,0,0,0,0,0, # 50 - 57 +0,0,0,0,0,0,0,0, # 58 - 5f +0,0,0,0,0,0,0,0, # 60 - 67 +0,0,0,0,0,0,0,0, # 68 - 6f +0,0,0,0,0,0,0,0, # 70 - 77 +0,0,0,0,0,0,0,0, # 78 - 7f +2,2,2,2,2,2,2,2, # 80 - 87 +2,2,2,2,2,2,2,2, # 88 - 8f +2,2,2,2,2,2,2,2, # 90 - 97 +2,2,2,2,2,2,2,2, # 98 - 9f +2,2,2,2,2,2,2,2, # a0 - a7 +2,2,2,2,2,2,2,2, # a8 - af +2,2,2,2,2,2,2,2, # b0 - b7 +2,2,2,2,2,2,2,2, # b8 - bf +2,2,2,2,2,2,2,2, # c0 - c7 +2,2,2,2,2,2,2,2, # c8 - cf +2,2,2,2,2,2,2,2, # d0 - d7 +2,2,2,2,2,2,2,2, # d8 - df +2,2,2,2,2,2,2,2, # e0 - e7 +2,2,2,2,2,2,2,2, # e8 - ef +2,2,2,2,2,2,2,2, # f0 - f7 +2,2,2,2,2,2,2,2, # f8 - ff +) + +ISO2022CN_ST = ( +MachineState.START, 3,MachineState.ERROR,MachineState.START,MachineState.START,MachineState.START,MachineState.START,MachineState.START,# 00-07 +MachineState.START,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,# 08-0f +MachineState.ERROR,MachineState.ERROR,MachineState.ITS_ME,MachineState.ITS_ME,MachineState.ITS_ME,MachineState.ITS_ME,MachineState.ITS_ME,MachineState.ITS_ME,# 10-17 +MachineState.ITS_ME,MachineState.ITS_ME,MachineState.ITS_ME,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR, 4,MachineState.ERROR,# 18-1f +MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ITS_ME,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,# 20-27 + 5, 6,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,# 28-2f +MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ITS_ME,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,# 30-37 +MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ITS_ME,MachineState.ERROR,MachineState.START,# 38-3f +) + +ISO2022CN_CHAR_LEN_TABLE = (0, 0, 0, 0, 0, 0, 0, 0, 0) + +ISO2022CN_SM_MODEL = {'class_table': ISO2022CN_CLS, + 'class_factor': 9, + 'state_table': ISO2022CN_ST, + 'char_len_table': ISO2022CN_CHAR_LEN_TABLE, + 'name': "ISO-2022-CN", + 'language': 'Chinese'} + +ISO2022JP_CLS = ( +2,0,0,0,0,0,0,0, # 00 - 07 +0,0,0,0,0,0,2,2, # 08 - 0f +0,0,0,0,0,0,0,0, # 10 - 17 +0,0,0,1,0,0,0,0, # 18 - 1f +0,0,0,0,7,0,0,0, # 20 - 27 +3,0,0,0,0,0,0,0, # 28 - 2f +0,0,0,0,0,0,0,0, # 30 - 37 +0,0,0,0,0,0,0,0, # 38 - 3f +6,0,4,0,8,0,0,0, # 40 - 47 +0,9,5,0,0,0,0,0, # 48 - 4f +0,0,0,0,0,0,0,0, # 50 - 57 +0,0,0,0,0,0,0,0, # 58 - 5f +0,0,0,0,0,0,0,0, # 60 - 67 +0,0,0,0,0,0,0,0, # 68 - 6f +0,0,0,0,0,0,0,0, # 70 - 77 +0,0,0,0,0,0,0,0, # 78 - 7f +2,2,2,2,2,2,2,2, # 80 - 87 +2,2,2,2,2,2,2,2, # 88 - 8f +2,2,2,2,2,2,2,2, # 90 - 97 +2,2,2,2,2,2,2,2, # 98 - 9f +2,2,2,2,2,2,2,2, # a0 - a7 +2,2,2,2,2,2,2,2, # a8 - af +2,2,2,2,2,2,2,2, # b0 - b7 +2,2,2,2,2,2,2,2, # b8 - bf +2,2,2,2,2,2,2,2, # c0 - c7 +2,2,2,2,2,2,2,2, # c8 - cf +2,2,2,2,2,2,2,2, # d0 - d7 +2,2,2,2,2,2,2,2, # d8 - df +2,2,2,2,2,2,2,2, # e0 - e7 +2,2,2,2,2,2,2,2, # e8 - ef +2,2,2,2,2,2,2,2, # f0 - f7 +2,2,2,2,2,2,2,2, # f8 - ff +) + +ISO2022JP_ST = ( +MachineState.START, 3,MachineState.ERROR,MachineState.START,MachineState.START,MachineState.START,MachineState.START,MachineState.START,# 00-07 +MachineState.START,MachineState.START,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,# 08-0f +MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ITS_ME,MachineState.ITS_ME,MachineState.ITS_ME,MachineState.ITS_ME,# 10-17 +MachineState.ITS_ME,MachineState.ITS_ME,MachineState.ITS_ME,MachineState.ITS_ME,MachineState.ITS_ME,MachineState.ITS_ME,MachineState.ERROR,MachineState.ERROR,# 18-1f +MachineState.ERROR, 5,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR, 4,MachineState.ERROR,MachineState.ERROR,# 20-27 +MachineState.ERROR,MachineState.ERROR,MachineState.ERROR, 6,MachineState.ITS_ME,MachineState.ERROR,MachineState.ITS_ME,MachineState.ERROR,# 28-2f +MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ITS_ME,MachineState.ITS_ME,# 30-37 +MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ITS_ME,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,# 38-3f +MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ITS_ME,MachineState.ERROR,MachineState.START,MachineState.START,# 40-47 +) + +ISO2022JP_CHAR_LEN_TABLE = (0, 0, 0, 0, 0, 0, 0, 0, 0, 0) + +ISO2022JP_SM_MODEL = {'class_table': ISO2022JP_CLS, + 'class_factor': 10, + 'state_table': ISO2022JP_ST, + 'char_len_table': ISO2022JP_CHAR_LEN_TABLE, + 'name': "ISO-2022-JP", + 'language': 'Japanese'} + +ISO2022KR_CLS = ( +2,0,0,0,0,0,0,0, # 00 - 07 +0,0,0,0,0,0,0,0, # 08 - 0f +0,0,0,0,0,0,0,0, # 10 - 17 +0,0,0,1,0,0,0,0, # 18 - 1f +0,0,0,0,3,0,0,0, # 20 - 27 +0,4,0,0,0,0,0,0, # 28 - 2f +0,0,0,0,0,0,0,0, # 30 - 37 +0,0,0,0,0,0,0,0, # 38 - 3f +0,0,0,5,0,0,0,0, # 40 - 47 +0,0,0,0,0,0,0,0, # 48 - 4f +0,0,0,0,0,0,0,0, # 50 - 57 +0,0,0,0,0,0,0,0, # 58 - 5f +0,0,0,0,0,0,0,0, # 60 - 67 +0,0,0,0,0,0,0,0, # 68 - 6f +0,0,0,0,0,0,0,0, # 70 - 77 +0,0,0,0,0,0,0,0, # 78 - 7f +2,2,2,2,2,2,2,2, # 80 - 87 +2,2,2,2,2,2,2,2, # 88 - 8f +2,2,2,2,2,2,2,2, # 90 - 97 +2,2,2,2,2,2,2,2, # 98 - 9f +2,2,2,2,2,2,2,2, # a0 - a7 +2,2,2,2,2,2,2,2, # a8 - af +2,2,2,2,2,2,2,2, # b0 - b7 +2,2,2,2,2,2,2,2, # b8 - bf +2,2,2,2,2,2,2,2, # c0 - c7 +2,2,2,2,2,2,2,2, # c8 - cf +2,2,2,2,2,2,2,2, # d0 - d7 +2,2,2,2,2,2,2,2, # d8 - df +2,2,2,2,2,2,2,2, # e0 - e7 +2,2,2,2,2,2,2,2, # e8 - ef +2,2,2,2,2,2,2,2, # f0 - f7 +2,2,2,2,2,2,2,2, # f8 - ff +) + +ISO2022KR_ST = ( +MachineState.START, 3,MachineState.ERROR,MachineState.START,MachineState.START,MachineState.START,MachineState.ERROR,MachineState.ERROR,# 00-07 +MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ITS_ME,MachineState.ITS_ME,MachineState.ITS_ME,MachineState.ITS_ME,# 08-0f +MachineState.ITS_ME,MachineState.ITS_ME,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR, 4,MachineState.ERROR,MachineState.ERROR,# 10-17 +MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR, 5,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,# 18-1f +MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ITS_ME,MachineState.START,MachineState.START,MachineState.START,MachineState.START,# 20-27 +) + +ISO2022KR_CHAR_LEN_TABLE = (0, 0, 0, 0, 0, 0) + +ISO2022KR_SM_MODEL = {'class_table': ISO2022KR_CLS, + 'class_factor': 6, + 'state_table': ISO2022KR_ST, + 'char_len_table': ISO2022KR_CHAR_LEN_TABLE, + 'name': "ISO-2022-KR", + 'language': 'Korean'} + + diff --git a/venv/Lib/site-packages/chardet/eucjpprober.py b/venv/Lib/site-packages/chardet/eucjpprober.py new file mode 100644 index 000000000..20ce8f7d1 --- /dev/null +++ b/venv/Lib/site-packages/chardet/eucjpprober.py @@ -0,0 +1,92 @@ +######################## BEGIN LICENSE BLOCK ######################## +# The Original Code is mozilla.org code. +# +# The Initial Developer of the Original Code is +# Netscape Communications Corporation. +# Portions created by the Initial Developer are Copyright (C) 1998 +# the Initial Developer. All Rights Reserved. +# +# Contributor(s): +# Mark Pilgrim - port to Python +# +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; either +# version 2.1 of the License, or (at your option) any later version. +# +# This library 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 +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this library; if not, write to the Free Software +# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA +# 02110-1301 USA +######################### END LICENSE BLOCK ######################### + +from .enums import ProbingState, MachineState +from .mbcharsetprober import MultiByteCharSetProber +from .codingstatemachine import CodingStateMachine +from .chardistribution import EUCJPDistributionAnalysis +from .jpcntx import EUCJPContextAnalysis +from .mbcssm import EUCJP_SM_MODEL + + +class EUCJPProber(MultiByteCharSetProber): + def __init__(self): + super(EUCJPProber, self).__init__() + self.coding_sm = CodingStateMachine(EUCJP_SM_MODEL) + self.distribution_analyzer = EUCJPDistributionAnalysis() + self.context_analyzer = EUCJPContextAnalysis() + self.reset() + + def reset(self): + super(EUCJPProber, self).reset() + self.context_analyzer.reset() + + @property + def charset_name(self): + return "EUC-JP" + + @property + def language(self): + return "Japanese" + + def feed(self, byte_str): + for i in range(len(byte_str)): + # PY3K: byte_str is a byte array, so byte_str[i] is an int, not a byte + coding_state = self.coding_sm.next_state(byte_str[i]) + if coding_state == MachineState.ERROR: + self.logger.debug('%s %s prober hit error at byte %s', + self.charset_name, self.language, i) + self._state = ProbingState.NOT_ME + break + elif coding_state == MachineState.ITS_ME: + self._state = ProbingState.FOUND_IT + break + elif coding_state == MachineState.START: + char_len = self.coding_sm.get_current_charlen() + if i == 0: + self._last_char[1] = byte_str[0] + self.context_analyzer.feed(self._last_char, char_len) + self.distribution_analyzer.feed(self._last_char, char_len) + else: + self.context_analyzer.feed(byte_str[i - 1:i + 1], + char_len) + self.distribution_analyzer.feed(byte_str[i - 1:i + 1], + char_len) + + self._last_char[0] = byte_str[-1] + + if self.state == ProbingState.DETECTING: + if (self.context_analyzer.got_enough_data() and + (self.get_confidence() > self.SHORTCUT_THRESHOLD)): + self._state = ProbingState.FOUND_IT + + return self.state + + def get_confidence(self): + context_conf = self.context_analyzer.get_confidence() + distrib_conf = self.distribution_analyzer.get_confidence() + return max(context_conf, distrib_conf) diff --git a/venv/Lib/site-packages/chardet/euckrfreq.py b/venv/Lib/site-packages/chardet/euckrfreq.py new file mode 100644 index 000000000..b68078cb9 --- /dev/null +++ b/venv/Lib/site-packages/chardet/euckrfreq.py @@ -0,0 +1,195 @@ +######################## BEGIN LICENSE BLOCK ######################## +# The Original Code is Mozilla Communicator client code. +# +# The Initial Developer of the Original Code is +# Netscape Communications Corporation. +# Portions created by the Initial Developer are Copyright (C) 1998 +# the Initial Developer. All Rights Reserved. +# +# Contributor(s): +# Mark Pilgrim - port to Python +# +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; either +# version 2.1 of the License, or (at your option) any later version. +# +# This library 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 +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this library; if not, write to the Free Software +# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA +# 02110-1301 USA +######################### END LICENSE BLOCK ######################### + +# Sampling from about 20M text materials include literature and computer technology + +# 128 --> 0.79 +# 256 --> 0.92 +# 512 --> 0.986 +# 1024 --> 0.99944 +# 2048 --> 0.99999 +# +# Idea Distribution Ratio = 0.98653 / (1-0.98653) = 73.24 +# Random Distribution Ration = 512 / (2350-512) = 0.279. +# +# Typical Distribution Ratio + +EUCKR_TYPICAL_DISTRIBUTION_RATIO = 6.0 + +EUCKR_TABLE_SIZE = 2352 + +# Char to FreqOrder table , +EUCKR_CHAR_TO_FREQ_ORDER = ( + 13, 130, 120,1396, 481,1719,1720, 328, 609, 212,1721, 707, 400, 299,1722, 87, +1397,1723, 104, 536,1117,1203,1724,1267, 685,1268, 508,1725,1726,1727,1728,1398, +1399,1729,1730,1731, 141, 621, 326,1057, 368,1732, 267, 488, 20,1733,1269,1734, + 945,1400,1735, 47, 904,1270,1736,1737, 773, 248,1738, 409, 313, 786, 429,1739, + 116, 987, 813,1401, 683, 75,1204, 145,1740,1741,1742,1743, 16, 847, 667, 622, + 708,1744,1745,1746, 966, 787, 304, 129,1747, 60, 820, 123, 676,1748,1749,1750, +1751, 617,1752, 626,1753,1754,1755,1756, 653,1757,1758,1759,1760,1761,1762, 856, + 344,1763,1764,1765,1766, 89, 401, 418, 806, 905, 848,1767,1768,1769, 946,1205, + 709,1770,1118,1771, 241,1772,1773,1774,1271,1775, 569,1776, 999,1777,1778,1779, +1780, 337, 751,1058, 28, 628, 254,1781, 177, 906, 270, 349, 891,1079,1782, 19, +1783, 379,1784, 315,1785, 629, 754,1402, 559,1786, 636, 203,1206,1787, 710, 567, +1788, 935, 814,1789,1790,1207, 766, 528,1791,1792,1208,1793,1794,1795,1796,1797, +1403,1798,1799, 533,1059,1404,1405,1156,1406, 936, 884,1080,1800, 351,1801,1802, +1803,1804,1805, 801,1806,1807,1808,1119,1809,1157, 714, 474,1407,1810, 298, 899, + 885,1811,1120, 802,1158,1812, 892,1813,1814,1408, 659,1815,1816,1121,1817,1818, +1819,1820,1821,1822, 319,1823, 594, 545,1824, 815, 937,1209,1825,1826, 573,1409, +1022,1827,1210,1828,1829,1830,1831,1832,1833, 556, 722, 807,1122,1060,1834, 697, +1835, 900, 557, 715,1836,1410, 540,1411, 752,1159, 294, 597,1211, 976, 803, 770, +1412,1837,1838, 39, 794,1413, 358,1839, 371, 925,1840, 453, 661, 788, 531, 723, + 544,1023,1081, 869, 91,1841, 392, 430, 790, 602,1414, 677,1082, 457,1415,1416, +1842,1843, 475, 327,1024,1417, 795, 121,1844, 733, 403,1418,1845,1846,1847, 300, + 119, 711,1212, 627,1848,1272, 207,1849,1850, 796,1213, 382,1851, 519,1852,1083, + 893,1853,1854,1855, 367, 809, 487, 671,1856, 663,1857,1858, 956, 471, 306, 857, +1859,1860,1160,1084,1861,1862,1863,1864,1865,1061,1866,1867,1868,1869,1870,1871, + 282, 96, 574,1872, 502,1085,1873,1214,1874, 907,1875,1876, 827, 977,1419,1420, +1421, 268,1877,1422,1878,1879,1880, 308,1881, 2, 537,1882,1883,1215,1884,1885, + 127, 791,1886,1273,1423,1887, 34, 336, 404, 643,1888, 571, 654, 894, 840,1889, + 0, 886,1274, 122, 575, 260, 908, 938,1890,1275, 410, 316,1891,1892, 100,1893, +1894,1123, 48,1161,1124,1025,1895, 633, 901,1276,1896,1897, 115, 816,1898, 317, +1899, 694,1900, 909, 734,1424, 572, 866,1425, 691, 85, 524,1010, 543, 394, 841, +1901,1902,1903,1026,1904,1905,1906,1907,1908,1909, 30, 451, 651, 988, 310,1910, +1911,1426, 810,1216, 93,1912,1913,1277,1217,1914, 858, 759, 45, 58, 181, 610, + 269,1915,1916, 131,1062, 551, 443,1000, 821,1427, 957, 895,1086,1917,1918, 375, +1919, 359,1920, 687,1921, 822,1922, 293,1923,1924, 40, 662, 118, 692, 29, 939, + 887, 640, 482, 174,1925, 69,1162, 728,1428, 910,1926,1278,1218,1279, 386, 870, + 217, 854,1163, 823,1927,1928,1929,1930, 834,1931, 78,1932, 859,1933,1063,1934, +1935,1936,1937, 438,1164, 208, 595,1938,1939,1940,1941,1219,1125,1942, 280, 888, +1429,1430,1220,1431,1943,1944,1945,1946,1947,1280, 150, 510,1432,1948,1949,1950, +1951,1952,1953,1954,1011,1087,1955,1433,1043,1956, 881,1957, 614, 958,1064,1065, +1221,1958, 638,1001, 860, 967, 896,1434, 989, 492, 553,1281,1165,1959,1282,1002, +1283,1222,1960,1961,1962,1963, 36, 383, 228, 753, 247, 454,1964, 876, 678,1965, +1966,1284, 126, 464, 490, 835, 136, 672, 529, 940,1088,1435, 473,1967,1968, 467, + 50, 390, 227, 587, 279, 378, 598, 792, 968, 240, 151, 160, 849, 882,1126,1285, + 639,1044, 133, 140, 288, 360, 811, 563,1027, 561, 142, 523,1969,1970,1971, 7, + 103, 296, 439, 407, 506, 634, 990,1972,1973,1974,1975, 645,1976,1977,1978,1979, +1980,1981, 236,1982,1436,1983,1984,1089, 192, 828, 618, 518,1166, 333,1127,1985, + 818,1223,1986,1987,1988,1989,1990,1991,1992,1993, 342,1128,1286, 746, 842,1994, +1995, 560, 223,1287, 98, 8, 189, 650, 978,1288,1996,1437,1997, 17, 345, 250, + 423, 277, 234, 512, 226, 97, 289, 42, 167,1998, 201,1999,2000, 843, 836, 824, + 532, 338, 783,1090, 182, 576, 436,1438,1439, 527, 500,2001, 947, 889,2002,2003, +2004,2005, 262, 600, 314, 447,2006, 547,2007, 693, 738,1129,2008, 71,1440, 745, + 619, 688,2009, 829,2010,2011, 147,2012, 33, 948,2013,2014, 74, 224,2015, 61, + 191, 918, 399, 637,2016,1028,1130, 257, 902,2017,2018,2019,2020,2021,2022,2023, +2024,2025,2026, 837,2027,2028,2029,2030, 179, 874, 591, 52, 724, 246,2031,2032, +2033,2034,1167, 969,2035,1289, 630, 605, 911,1091,1168,2036,2037,2038,1441, 912, +2039, 623,2040,2041, 253,1169,1290,2042,1442, 146, 620, 611, 577, 433,2043,1224, + 719,1170, 959, 440, 437, 534, 84, 388, 480,1131, 159, 220, 198, 679,2044,1012, + 819,1066,1443, 113,1225, 194, 318,1003,1029,2045,2046,2047,2048,1067,2049,2050, +2051,2052,2053, 59, 913, 112,2054, 632,2055, 455, 144, 739,1291,2056, 273, 681, + 499,2057, 448,2058,2059, 760,2060,2061, 970, 384, 169, 245,1132,2062,2063, 414, +1444,2064,2065, 41, 235,2066, 157, 252, 877, 568, 919, 789, 580,2067, 725,2068, +2069,1292,2070,2071,1445,2072,1446,2073,2074, 55, 588, 66,1447, 271,1092,2075, +1226,2076, 960,1013, 372,2077,2078,2079,2080,2081,1293,2082,2083,2084,2085, 850, +2086,2087,2088,2089,2090, 186,2091,1068, 180,2092,2093,2094, 109,1227, 522, 606, +2095, 867,1448,1093, 991,1171, 926, 353,1133,2096, 581,2097,2098,2099,1294,1449, +1450,2100, 596,1172,1014,1228,2101,1451,1295,1173,1229,2102,2103,1296,1134,1452, + 949,1135,2104,2105,1094,1453,1454,1455,2106,1095,2107,2108,2109,2110,2111,2112, +2113,2114,2115,2116,2117, 804,2118,2119,1230,1231, 805,1456, 405,1136,2120,2121, +2122,2123,2124, 720, 701,1297, 992,1457, 927,1004,2125,2126,2127,2128,2129,2130, + 22, 417,2131, 303,2132, 385,2133, 971, 520, 513,2134,1174, 73,1096, 231, 274, + 962,1458, 673,2135,1459,2136, 152,1137,2137,2138,2139,2140,1005,1138,1460,1139, +2141,2142,2143,2144, 11, 374, 844,2145, 154,1232, 46,1461,2146, 838, 830, 721, +1233, 106,2147, 90, 428, 462, 578, 566,1175, 352,2148,2149, 538,1234, 124,1298, +2150,1462, 761, 565,2151, 686,2152, 649,2153, 72, 173,2154, 460, 415,2155,1463, +2156,1235, 305,2157,2158,2159,2160,2161,2162, 579,2163,2164,2165,2166,2167, 747, +2168,2169,2170,2171,1464, 669,2172,2173,2174,2175,2176,1465,2177, 23, 530, 285, +2178, 335, 729,2179, 397,2180,2181,2182,1030,2183,2184, 698,2185,2186, 325,2187, +2188, 369,2189, 799,1097,1015, 348,2190,1069, 680,2191, 851,1466,2192,2193, 10, +2194, 613, 424,2195, 979, 108, 449, 589, 27, 172, 81,1031, 80, 774, 281, 350, +1032, 525, 301, 582,1176,2196, 674,1045,2197,2198,1467, 730, 762,2199,2200,2201, +2202,1468,2203, 993,2204,2205, 266,1070, 963,1140,2206,2207,2208, 664,1098, 972, +2209,2210,2211,1177,1469,1470, 871,2212,2213,2214,2215,2216,1471,2217,2218,2219, +2220,2221,2222,2223,2224,2225,2226,2227,1472,1236,2228,2229,2230,2231,2232,2233, +2234,2235,1299,2236,2237, 200,2238, 477, 373,2239,2240, 731, 825, 777,2241,2242, +2243, 521, 486, 548,2244,2245,2246,1473,1300, 53, 549, 137, 875, 76, 158,2247, +1301,1474, 469, 396,1016, 278, 712,2248, 321, 442, 503, 767, 744, 941,1237,1178, +1475,2249, 82, 178,1141,1179, 973,2250,1302,2251, 297,2252,2253, 570,2254,2255, +2256, 18, 450, 206,2257, 290, 292,1142,2258, 511, 162, 99, 346, 164, 735,2259, +1476,1477, 4, 554, 343, 798,1099,2260,1100,2261, 43, 171,1303, 139, 215,2262, +2263, 717, 775,2264,1033, 322, 216,2265, 831,2266, 149,2267,1304,2268,2269, 702, +1238, 135, 845, 347, 309,2270, 484,2271, 878, 655, 238,1006,1478,2272, 67,2273, + 295,2274,2275, 461,2276, 478, 942, 412,2277,1034,2278,2279,2280, 265,2281, 541, +2282,2283,2284,2285,2286, 70, 852,1071,2287,2288,2289,2290, 21, 56, 509, 117, + 432,2291,2292, 331, 980, 552,1101, 148, 284, 105, 393,1180,1239, 755,2293, 187, +2294,1046,1479,2295, 340,2296, 63,1047, 230,2297,2298,1305, 763,1306, 101, 800, + 808, 494,2299,2300,2301, 903,2302, 37,1072, 14, 5,2303, 79, 675,2304, 312, +2305,2306,2307,2308,2309,1480, 6,1307,2310,2311,2312, 1, 470, 35, 24, 229, +2313, 695, 210, 86, 778, 15, 784, 592, 779, 32, 77, 855, 964,2314, 259,2315, + 501, 380,2316,2317, 83, 981, 153, 689,1308,1481,1482,1483,2318,2319, 716,1484, +2320,2321,2322,2323,2324,2325,1485,2326,2327, 128, 57, 68, 261,1048, 211, 170, +1240, 31,2328, 51, 435, 742,2329,2330,2331, 635,2332, 264, 456,2333,2334,2335, + 425,2336,1486, 143, 507, 263, 943,2337, 363, 920,1487, 256,1488,1102, 243, 601, +1489,2338,2339,2340,2341,2342,2343,2344, 861,2345,2346,2347,2348,2349,2350, 395, +2351,1490,1491, 62, 535, 166, 225,2352,2353, 668, 419,1241, 138, 604, 928,2354, +1181,2355,1492,1493,2356,2357,2358,1143,2359, 696,2360, 387, 307,1309, 682, 476, +2361,2362, 332, 12, 222, 156,2363, 232,2364, 641, 276, 656, 517,1494,1495,1035, + 416, 736,1496,2365,1017, 586,2366,2367,2368,1497,2369, 242,2370,2371,2372,1498, +2373, 965, 713,2374,2375,2376,2377, 740, 982,1499, 944,1500,1007,2378,2379,1310, +1501,2380,2381,2382, 785, 329,2383,2384,1502,2385,2386,2387, 932,2388,1503,2389, +2390,2391,2392,1242,2393,2394,2395,2396,2397, 994, 950,2398,2399,2400,2401,1504, +1311,2402,2403,2404,2405,1049, 749,2406,2407, 853, 718,1144,1312,2408,1182,1505, +2409,2410, 255, 516, 479, 564, 550, 214,1506,1507,1313, 413, 239, 444, 339,1145, +1036,1508,1509,1314,1037,1510,1315,2411,1511,2412,2413,2414, 176, 703, 497, 624, + 593, 921, 302,2415, 341, 165,1103,1512,2416,1513,2417,2418,2419, 376,2420, 700, +2421,2422,2423, 258, 768,1316,2424,1183,2425, 995, 608,2426,2427,2428,2429, 221, +2430,2431,2432,2433,2434,2435,2436,2437, 195, 323, 726, 188, 897, 983,1317, 377, + 644,1050, 879,2438, 452,2439,2440,2441,2442,2443,2444, 914,2445,2446,2447,2448, + 915, 489,2449,1514,1184,2450,2451, 515, 64, 427, 495,2452, 583,2453, 483, 485, +1038, 562, 213,1515, 748, 666,2454,2455,2456,2457, 334,2458, 780, 996,1008, 705, +1243,2459,2460,2461,2462,2463, 114,2464, 493,1146, 366, 163,1516, 961,1104,2465, + 291,2466,1318,1105,2467,1517, 365,2468, 355, 951,1244,2469,1319,2470, 631,2471, +2472, 218,1320, 364, 320, 756,1518,1519,1321,1520,1322,2473,2474,2475,2476, 997, +2477,2478,2479,2480, 665,1185,2481, 916,1521,2482,2483,2484, 584, 684,2485,2486, + 797,2487,1051,1186,2488,2489,2490,1522,2491,2492, 370,2493,1039,1187, 65,2494, + 434, 205, 463,1188,2495, 125, 812, 391, 402, 826, 699, 286, 398, 155, 781, 771, + 585,2496, 590, 505,1073,2497, 599, 244, 219, 917,1018, 952, 646,1523,2498,1323, +2499,2500, 49, 984, 354, 741,2501, 625,2502,1324,2503,1019, 190, 357, 757, 491, + 95, 782, 868,2504,2505,2506,2507,2508,2509, 134,1524,1074, 422,1525, 898,2510, + 161,2511,2512,2513,2514, 769,2515,1526,2516,2517, 411,1325,2518, 472,1527,2519, +2520,2521,2522,2523,2524, 985,2525,2526,2527,2528,2529,2530, 764,2531,1245,2532, +2533, 25, 204, 311,2534, 496,2535,1052,2536,2537,2538,2539,2540,2541,2542, 199, + 704, 504, 468, 758, 657,1528, 196, 44, 839,1246, 272, 750,2543, 765, 862,2544, +2545,1326,2546, 132, 615, 933,2547, 732,2548,2549,2550,1189,1529,2551, 283,1247, +1053, 607, 929,2552,2553,2554, 930, 183, 872, 616,1040,1147,2555,1148,1020, 441, + 249,1075,2556,2557,2558, 466, 743,2559,2560,2561, 92, 514, 426, 420, 526,2562, +2563,2564,2565,2566,2567,2568, 185,2569,2570,2571,2572, 776,1530, 658,2573, 362, +2574, 361, 922,1076, 793,2575,2576,2577,2578,2579,2580,1531, 251,2581,2582,2583, +2584,1532, 54, 612, 237,1327,2585,2586, 275, 408, 647, 111,2587,1533,1106, 465, + 3, 458, 9, 38,2588, 107, 110, 890, 209, 26, 737, 498,2589,1534,2590, 431, + 202, 88,1535, 356, 287,1107, 660,1149,2591, 381,1536, 986,1150, 445,1248,1151, + 974,2592,2593, 846,2594, 446, 953, 184,1249,1250, 727,2595, 923, 193, 883,2596, +2597,2598, 102, 324, 539, 817,2599, 421,1041,2600, 832,2601, 94, 175, 197, 406, +2602, 459,2603,2604,2605,2606,2607, 330, 555,2608,2609,2610, 706,1108, 389,2611, +2612,2613,2614, 233,2615, 833, 558, 931, 954,1251,2616,2617,1537, 546,2618,2619, +1009,2620,2621,2622,1538, 690,1328,2623, 955,2624,1539,2625,2626, 772,2627,2628, +2629,2630,2631, 924, 648, 863, 603,2632,2633, 934,1540, 864, 865,2634, 642,1042, + 670,1190,2635,2636,2637,2638, 168,2639, 652, 873, 542,1054,1541,2640,2641,2642, # 512, 256 +) + diff --git a/venv/Lib/site-packages/requests/packages/chardet/euckrprober.py b/venv/Lib/site-packages/chardet/euckrprober.py similarity index 82% rename from venv/Lib/site-packages/requests/packages/chardet/euckrprober.py rename to venv/Lib/site-packages/chardet/euckrprober.py index 5982a46b6..345a060d0 100644 --- a/venv/Lib/site-packages/requests/packages/chardet/euckrprober.py +++ b/venv/Lib/site-packages/chardet/euckrprober.py @@ -28,15 +28,20 @@ from .mbcharsetprober import MultiByteCharSetProber from .codingstatemachine import CodingStateMachine from .chardistribution import EUCKRDistributionAnalysis -from .mbcssm import EUCKRSMModel +from .mbcssm import EUCKR_SM_MODEL class EUCKRProber(MultiByteCharSetProber): def __init__(self): - MultiByteCharSetProber.__init__(self) - self._mCodingSM = CodingStateMachine(EUCKRSMModel) - self._mDistributionAnalyzer = EUCKRDistributionAnalysis() + super(EUCKRProber, self).__init__() + self.coding_sm = CodingStateMachine(EUCKR_SM_MODEL) + self.distribution_analyzer = EUCKRDistributionAnalysis() self.reset() - def get_charset_name(self): + @property + def charset_name(self): return "EUC-KR" + + @property + def language(self): + return "Korean" diff --git a/venv/Lib/site-packages/requests/packages/chardet/euctwfreq.py b/venv/Lib/site-packages/chardet/euctwfreq.py similarity index 66% rename from venv/Lib/site-packages/requests/packages/chardet/euctwfreq.py rename to venv/Lib/site-packages/chardet/euctwfreq.py index 576e7504d..ed7a995a3 100644 --- a/venv/Lib/site-packages/requests/packages/chardet/euctwfreq.py +++ b/venv/Lib/site-packages/chardet/euctwfreq.py @@ -44,385 +44,344 @@ EUCTW_TYPICAL_DISTRIBUTION_RATIO = 0.75 # Char to FreqOrder table , -EUCTW_TABLE_SIZE = 8102 +EUCTW_TABLE_SIZE = 5376 -EUCTWCharToFreqOrder = ( - 1,1800,1506, 255,1431, 198, 9, 82, 6,7310, 177, 202,3615,1256,2808, 110, # 2742 -3735, 33,3241, 261, 76, 44,2113, 16,2931,2184,1176, 659,3868, 26,3404,2643, # 2758 -1198,3869,3313,4060, 410,2211, 302, 590, 361,1963, 8, 204, 58,4296,7311,1931, # 2774 - 63,7312,7313, 317,1614, 75, 222, 159,4061,2412,1480,7314,3500,3068, 224,2809, # 2790 -3616, 3, 10,3870,1471, 29,2774,1135,2852,1939, 873, 130,3242,1123, 312,7315, # 2806 -4297,2051, 507, 252, 682,7316, 142,1914, 124, 206,2932, 34,3501,3173, 64, 604, # 2822 -7317,2494,1976,1977, 155,1990, 645, 641,1606,7318,3405, 337, 72, 406,7319, 80, # 2838 - 630, 238,3174,1509, 263, 939,1092,2644, 756,1440,1094,3406, 449, 69,2969, 591, # 2854 - 179,2095, 471, 115,2034,1843, 60, 50,2970, 134, 806,1868, 734,2035,3407, 180, # 2870 - 995,1607, 156, 537,2893, 688,7320, 319,1305, 779,2144, 514,2374, 298,4298, 359, # 2886 -2495, 90,2707,1338, 663, 11, 906,1099,2545, 20,2436, 182, 532,1716,7321, 732, # 2902 -1376,4062,1311,1420,3175, 25,2312,1056, 113, 399, 382,1949, 242,3408,2467, 529, # 2918 -3243, 475,1447,3617,7322, 117, 21, 656, 810,1297,2295,2329,3502,7323, 126,4063, # 2934 - 706, 456, 150, 613,4299, 71,1118,2036,4064, 145,3069, 85, 835, 486,2114,1246, # 2950 -1426, 428, 727,1285,1015, 800, 106, 623, 303,1281,7324,2127,2354, 347,3736, 221, # 2966 -3503,3110,7325,1955,1153,4065, 83, 296,1199,3070, 192, 624, 93,7326, 822,1897, # 2982 -2810,3111, 795,2064, 991,1554,1542,1592, 27, 43,2853, 859, 139,1456, 860,4300, # 2998 - 437, 712,3871, 164,2392,3112, 695, 211,3017,2096, 195,3872,1608,3504,3505,3618, # 3014 -3873, 234, 811,2971,2097,3874,2229,1441,3506,1615,2375, 668,2076,1638, 305, 228, # 3030 -1664,4301, 467, 415,7327, 262,2098,1593, 239, 108, 300, 200,1033, 512,1247,2077, # 3046 -7328,7329,2173,3176,3619,2673, 593, 845,1062,3244, 88,1723,2037,3875,1950, 212, # 3062 - 266, 152, 149, 468,1898,4066,4302, 77, 187,7330,3018, 37, 5,2972,7331,3876, # 3078 -7332,7333, 39,2517,4303,2894,3177,2078, 55, 148, 74,4304, 545, 483,1474,1029, # 3094 -1665, 217,1869,1531,3113,1104,2645,4067, 24, 172,3507, 900,3877,3508,3509,4305, # 3110 - 32,1408,2811,1312, 329, 487,2355,2247,2708, 784,2674, 4,3019,3314,1427,1788, # 3126 - 188, 109, 499,7334,3620,1717,1789, 888,1217,3020,4306,7335,3510,7336,3315,1520, # 3142 -3621,3878, 196,1034, 775,7337,7338, 929,1815, 249, 439, 38,7339,1063,7340, 794, # 3158 -3879,1435,2296, 46, 178,3245,2065,7341,2376,7342, 214,1709,4307, 804, 35, 707, # 3174 - 324,3622,1601,2546, 140, 459,4068,7343,7344,1365, 839, 272, 978,2257,2572,3409, # 3190 -2128,1363,3623,1423, 697, 100,3071, 48, 70,1231, 495,3114,2193,7345,1294,7346, # 3206 -2079, 462, 586,1042,3246, 853, 256, 988, 185,2377,3410,1698, 434,1084,7347,3411, # 3222 - 314,2615,2775,4308,2330,2331, 569,2280, 637,1816,2518, 757,1162,1878,1616,3412, # 3238 - 287,1577,2115, 768,4309,1671,2854,3511,2519,1321,3737, 909,2413,7348,4069, 933, # 3254 -3738,7349,2052,2356,1222,4310, 765,2414,1322, 786,4311,7350,1919,1462,1677,2895, # 3270 -1699,7351,4312,1424,2437,3115,3624,2590,3316,1774,1940,3413,3880,4070, 309,1369, # 3286 -1130,2812, 364,2230,1653,1299,3881,3512,3882,3883,2646, 525,1085,3021, 902,2000, # 3302 -1475, 964,4313, 421,1844,1415,1057,2281, 940,1364,3116, 376,4314,4315,1381, 7, # 3318 -2520, 983,2378, 336,1710,2675,1845, 321,3414, 559,1131,3022,2742,1808,1132,1313, # 3334 - 265,1481,1857,7352, 352,1203,2813,3247, 167,1089, 420,2814, 776, 792,1724,3513, # 3350 -4071,2438,3248,7353,4072,7354, 446, 229, 333,2743, 901,3739,1200,1557,4316,2647, # 3366 -1920, 395,2744,2676,3740,4073,1835, 125, 916,3178,2616,4317,7355,7356,3741,7357, # 3382 -7358,7359,4318,3117,3625,1133,2547,1757,3415,1510,2313,1409,3514,7360,2145, 438, # 3398 -2591,2896,2379,3317,1068, 958,3023, 461, 311,2855,2677,4074,1915,3179,4075,1978, # 3414 - 383, 750,2745,2617,4076, 274, 539, 385,1278,1442,7361,1154,1964, 384, 561, 210, # 3430 - 98,1295,2548,3515,7362,1711,2415,1482,3416,3884,2897,1257, 129,7363,3742, 642, # 3446 - 523,2776,2777,2648,7364, 141,2231,1333, 68, 176, 441, 876, 907,4077, 603,2592, # 3462 - 710, 171,3417, 404, 549, 18,3118,2393,1410,3626,1666,7365,3516,4319,2898,4320, # 3478 -7366,2973, 368,7367, 146, 366, 99, 871,3627,1543, 748, 807,1586,1185, 22,2258, # 3494 - 379,3743,3180,7368,3181, 505,1941,2618,1991,1382,2314,7369, 380,2357, 218, 702, # 3510 -1817,1248,3418,3024,3517,3318,3249,7370,2974,3628, 930,3250,3744,7371, 59,7372, # 3526 - 585, 601,4078, 497,3419,1112,1314,4321,1801,7373,1223,1472,2174,7374, 749,1836, # 3542 - 690,1899,3745,1772,3885,1476, 429,1043,1790,2232,2116, 917,4079, 447,1086,1629, # 3558 -7375, 556,7376,7377,2020,1654, 844,1090, 105, 550, 966,1758,2815,1008,1782, 686, # 3574 -1095,7378,2282, 793,1602,7379,3518,2593,4322,4080,2933,2297,4323,3746, 980,2496, # 3590 - 544, 353, 527,4324, 908,2678,2899,7380, 381,2619,1942,1348,7381,1341,1252, 560, # 3606 -3072,7382,3420,2856,7383,2053, 973, 886,2080, 143,4325,7384,7385, 157,3886, 496, # 3622 -4081, 57, 840, 540,2038,4326,4327,3421,2117,1445, 970,2259,1748,1965,2081,4082, # 3638 -3119,1234,1775,3251,2816,3629, 773,1206,2129,1066,2039,1326,3887,1738,1725,4083, # 3654 - 279,3120, 51,1544,2594, 423,1578,2130,2066, 173,4328,1879,7386,7387,1583, 264, # 3670 - 610,3630,4329,2439, 280, 154,7388,7389,7390,1739, 338,1282,3073, 693,2857,1411, # 3686 -1074,3747,2440,7391,4330,7392,7393,1240, 952,2394,7394,2900,1538,2679, 685,1483, # 3702 -4084,2468,1436, 953,4085,2054,4331, 671,2395, 79,4086,2441,3252, 608, 567,2680, # 3718 -3422,4087,4088,1691, 393,1261,1791,2396,7395,4332,7396,7397,7398,7399,1383,1672, # 3734 -3748,3182,1464, 522,1119, 661,1150, 216, 675,4333,3888,1432,3519, 609,4334,2681, # 3750 -2397,7400,7401,7402,4089,3025, 0,7403,2469, 315, 231,2442, 301,3319,4335,2380, # 3766 -7404, 233,4090,3631,1818,4336,4337,7405, 96,1776,1315,2082,7406, 257,7407,1809, # 3782 -3632,2709,1139,1819,4091,2021,1124,2163,2778,1777,2649,7408,3074, 363,1655,3183, # 3798 -7409,2975,7410,7411,7412,3889,1567,3890, 718, 103,3184, 849,1443, 341,3320,2934, # 3814 -1484,7413,1712, 127, 67, 339,4092,2398, 679,1412, 821,7414,7415, 834, 738, 351, # 3830 -2976,2146, 846, 235,1497,1880, 418,1992,3749,2710, 186,1100,2147,2746,3520,1545, # 3846 -1355,2935,2858,1377, 583,3891,4093,2573,2977,7416,1298,3633,1078,2549,3634,2358, # 3862 - 78,3750,3751, 267,1289,2099,2001,1594,4094, 348, 369,1274,2194,2175,1837,4338, # 3878 -1820,2817,3635,2747,2283,2002,4339,2936,2748, 144,3321, 882,4340,3892,2749,3423, # 3894 -4341,2901,7417,4095,1726, 320,7418,3893,3026, 788,2978,7419,2818,1773,1327,2859, # 3910 -3894,2819,7420,1306,4342,2003,1700,3752,3521,2359,2650, 787,2022, 506, 824,3636, # 3926 - 534, 323,4343,1044,3322,2023,1900, 946,3424,7421,1778,1500,1678,7422,1881,4344, # 3942 - 165, 243,4345,3637,2521, 123, 683,4096, 764,4346, 36,3895,1792, 589,2902, 816, # 3958 - 626,1667,3027,2233,1639,1555,1622,3753,3896,7423,3897,2860,1370,1228,1932, 891, # 3974 -2083,2903, 304,4097,7424, 292,2979,2711,3522, 691,2100,4098,1115,4347, 118, 662, # 3990 -7425, 611,1156, 854,2381,1316,2861, 2, 386, 515,2904,7426,7427,3253, 868,2234, # 4006 -1486, 855,2651, 785,2212,3028,7428,1040,3185,3523,7429,3121, 448,7430,1525,7431, # 4022 -2164,4348,7432,3754,7433,4099,2820,3524,3122, 503, 818,3898,3123,1568, 814, 676, # 4038 -1444, 306,1749,7434,3755,1416,1030, 197,1428, 805,2821,1501,4349,7435,7436,7437, # 4054 -1993,7438,4350,7439,7440,2195, 13,2779,3638,2980,3124,1229,1916,7441,3756,2131, # 4070 -7442,4100,4351,2399,3525,7443,2213,1511,1727,1120,7444,7445, 646,3757,2443, 307, # 4086 -7446,7447,1595,3186,7448,7449,7450,3639,1113,1356,3899,1465,2522,2523,7451, 519, # 4102 -7452, 128,2132, 92,2284,1979,7453,3900,1512, 342,3125,2196,7454,2780,2214,1980, # 4118 -3323,7455, 290,1656,1317, 789, 827,2360,7456,3758,4352, 562, 581,3901,7457, 401, # 4134 -4353,2248, 94,4354,1399,2781,7458,1463,2024,4355,3187,1943,7459, 828,1105,4101, # 4150 -1262,1394,7460,4102, 605,4356,7461,1783,2862,7462,2822, 819,2101, 578,2197,2937, # 4166 -7463,1502, 436,3254,4103,3255,2823,3902,2905,3425,3426,7464,2712,2315,7465,7466, # 4182 -2332,2067, 23,4357, 193, 826,3759,2102, 699,1630,4104,3075, 390,1793,1064,3526, # 4198 -7467,1579,3076,3077,1400,7468,4105,1838,1640,2863,7469,4358,4359, 137,4106, 598, # 4214 -3078,1966, 780, 104, 974,2938,7470, 278, 899, 253, 402, 572, 504, 493,1339,7471, # 4230 -3903,1275,4360,2574,2550,7472,3640,3029,3079,2249, 565,1334,2713, 863, 41,7473, # 4246 -7474,4361,7475,1657,2333, 19, 463,2750,4107, 606,7476,2981,3256,1087,2084,1323, # 4262 -2652,2982,7477,1631,1623,1750,4108,2682,7478,2864, 791,2714,2653,2334, 232,2416, # 4278 -7479,2983,1498,7480,2654,2620, 755,1366,3641,3257,3126,2025,1609, 119,1917,3427, # 4294 - 862,1026,4109,7481,3904,3760,4362,3905,4363,2260,1951,2470,7482,1125, 817,4110, # 4310 -4111,3906,1513,1766,2040,1487,4112,3030,3258,2824,3761,3127,7483,7484,1507,7485, # 4326 -2683, 733, 40,1632,1106,2865, 345,4113, 841,2524, 230,4364,2984,1846,3259,3428, # 4342 -7486,1263, 986,3429,7487, 735, 879, 254,1137, 857, 622,1300,1180,1388,1562,3907, # 4358 -3908,2939, 967,2751,2655,1349, 592,2133,1692,3324,2985,1994,4114,1679,3909,1901, # 4374 -2185,7488, 739,3642,2715,1296,1290,7489,4115,2198,2199,1921,1563,2595,2551,1870, # 4390 -2752,2986,7490, 435,7491, 343,1108, 596, 17,1751,4365,2235,3430,3643,7492,4366, # 4406 - 294,3527,2940,1693, 477, 979, 281,2041,3528, 643,2042,3644,2621,2782,2261,1031, # 4422 -2335,2134,2298,3529,4367, 367,1249,2552,7493,3530,7494,4368,1283,3325,2004, 240, # 4438 -1762,3326,4369,4370, 836,1069,3128, 474,7495,2148,2525, 268,3531,7496,3188,1521, # 4454 -1284,7497,1658,1546,4116,7498,3532,3533,7499,4117,3327,2684,1685,4118, 961,1673, # 4470 -2622, 190,2005,2200,3762,4371,4372,7500, 570,2497,3645,1490,7501,4373,2623,3260, # 4486 -1956,4374, 584,1514, 396,1045,1944,7502,4375,1967,2444,7503,7504,4376,3910, 619, # 4502 -7505,3129,3261, 215,2006,2783,2553,3189,4377,3190,4378, 763,4119,3763,4379,7506, # 4518 -7507,1957,1767,2941,3328,3646,1174, 452,1477,4380,3329,3130,7508,2825,1253,2382, # 4534 -2186,1091,2285,4120, 492,7509, 638,1169,1824,2135,1752,3911, 648, 926,1021,1324, # 4550 -4381, 520,4382, 997, 847,1007, 892,4383,3764,2262,1871,3647,7510,2400,1784,4384, # 4566 -1952,2942,3080,3191,1728,4121,2043,3648,4385,2007,1701,3131,1551, 30,2263,4122, # 4582 -7511,2026,4386,3534,7512, 501,7513,4123, 594,3431,2165,1821,3535,3432,3536,3192, # 4598 - 829,2826,4124,7514,1680,3132,1225,4125,7515,3262,4387,4126,3133,2336,7516,4388, # 4614 -4127,7517,3912,3913,7518,1847,2383,2596,3330,7519,4389, 374,3914, 652,4128,4129, # 4630 - 375,1140, 798,7520,7521,7522,2361,4390,2264, 546,1659, 138,3031,2445,4391,7523, # 4646 -2250, 612,1848, 910, 796,3765,1740,1371, 825,3766,3767,7524,2906,2554,7525, 692, # 4662 - 444,3032,2624, 801,4392,4130,7526,1491, 244,1053,3033,4131,4132, 340,7527,3915, # 4678 -1041,2987, 293,1168, 87,1357,7528,1539, 959,7529,2236, 721, 694,4133,3768, 219, # 4694 -1478, 644,1417,3331,2656,1413,1401,1335,1389,3916,7530,7531,2988,2362,3134,1825, # 4710 - 730,1515, 184,2827, 66,4393,7532,1660,2943, 246,3332, 378,1457, 226,3433, 975, # 4726 -3917,2944,1264,3537, 674, 696,7533, 163,7534,1141,2417,2166, 713,3538,3333,4394, # 4742 -3918,7535,7536,1186, 15,7537,1079,1070,7538,1522,3193,3539, 276,1050,2716, 758, # 4758 -1126, 653,2945,3263,7539,2337, 889,3540,3919,3081,2989, 903,1250,4395,3920,3434, # 4774 -3541,1342,1681,1718, 766,3264, 286, 89,2946,3649,7540,1713,7541,2597,3334,2990, # 4790 -7542,2947,2215,3194,2866,7543,4396,2498,2526, 181, 387,1075,3921, 731,2187,3335, # 4806 -7544,3265, 310, 313,3435,2299, 770,4134, 54,3034, 189,4397,3082,3769,3922,7545, # 4822 -1230,1617,1849, 355,3542,4135,4398,3336, 111,4136,3650,1350,3135,3436,3035,4137, # 4838 -2149,3266,3543,7546,2784,3923,3924,2991, 722,2008,7547,1071, 247,1207,2338,2471, # 4854 -1378,4399,2009, 864,1437,1214,4400, 373,3770,1142,2216, 667,4401, 442,2753,2555, # 4870 -3771,3925,1968,4138,3267,1839, 837, 170,1107, 934,1336,1882,7548,7549,2118,4139, # 4886 -2828, 743,1569,7550,4402,4140, 582,2384,1418,3437,7551,1802,7552, 357,1395,1729, # 4902 -3651,3268,2418,1564,2237,7553,3083,3772,1633,4403,1114,2085,4141,1532,7554, 482, # 4918 -2446,4404,7555,7556,1492, 833,1466,7557,2717,3544,1641,2829,7558,1526,1272,3652, # 4934 -4142,1686,1794, 416,2556,1902,1953,1803,7559,3773,2785,3774,1159,2316,7560,2867, # 4950 -4405,1610,1584,3036,2419,2754, 443,3269,1163,3136,7561,7562,3926,7563,4143,2499, # 4966 -3037,4406,3927,3137,2103,1647,3545,2010,1872,4144,7564,4145, 431,3438,7565, 250, # 4982 - 97, 81,4146,7566,1648,1850,1558, 160, 848,7567, 866, 740,1694,7568,2201,2830, # 4998 -3195,4147,4407,3653,1687, 950,2472, 426, 469,3196,3654,3655,3928,7569,7570,1188, # 5014 - 424,1995, 861,3546,4148,3775,2202,2685, 168,1235,3547,4149,7571,2086,1674,4408, # 5030 -3337,3270, 220,2557,1009,7572,3776, 670,2992, 332,1208, 717,7573,7574,3548,2447, # 5046 -3929,3338,7575, 513,7576,1209,2868,3339,3138,4409,1080,7577,7578,7579,7580,2527, # 5062 -3656,3549, 815,1587,3930,3931,7581,3550,3439,3777,1254,4410,1328,3038,1390,3932, # 5078 -1741,3933,3778,3934,7582, 236,3779,2448,3271,7583,7584,3657,3780,1273,3781,4411, # 5094 -7585, 308,7586,4412, 245,4413,1851,2473,1307,2575, 430, 715,2136,2449,7587, 270, # 5110 - 199,2869,3935,7588,3551,2718,1753, 761,1754, 725,1661,1840,4414,3440,3658,7589, # 5126 -7590, 587, 14,3272, 227,2598, 326, 480,2265, 943,2755,3552, 291, 650,1883,7591, # 5142 -1702,1226, 102,1547, 62,3441, 904,4415,3442,1164,4150,7592,7593,1224,1548,2756, # 5158 - 391, 498,1493,7594,1386,1419,7595,2055,1177,4416, 813, 880,1081,2363, 566,1145, # 5174 -4417,2286,1001,1035,2558,2599,2238, 394,1286,7596,7597,2068,7598, 86,1494,1730, # 5190 -3936, 491,1588, 745, 897,2948, 843,3340,3937,2757,2870,3273,1768, 998,2217,2069, # 5206 - 397,1826,1195,1969,3659,2993,3341, 284,7599,3782,2500,2137,2119,1903,7600,3938, # 5222 -2150,3939,4151,1036,3443,1904, 114,2559,4152, 209,1527,7601,7602,2949,2831,2625, # 5238 -2385,2719,3139, 812,2560,7603,3274,7604,1559, 737,1884,3660,1210, 885, 28,2686, # 5254 -3553,3783,7605,4153,1004,1779,4418,7606, 346,1981,2218,2687,4419,3784,1742, 797, # 5270 -1642,3940,1933,1072,1384,2151, 896,3941,3275,3661,3197,2871,3554,7607,2561,1958, # 5286 -4420,2450,1785,7608,7609,7610,3942,4154,1005,1308,3662,4155,2720,4421,4422,1528, # 5302 -2600, 161,1178,4156,1982, 987,4423,1101,4157, 631,3943,1157,3198,2420,1343,1241, # 5318 -1016,2239,2562, 372, 877,2339,2501,1160, 555,1934, 911,3944,7611, 466,1170, 169, # 5334 -1051,2907,2688,3663,2474,2994,1182,2011,2563,1251,2626,7612, 992,2340,3444,1540, # 5350 -2721,1201,2070,2401,1996,2475,7613,4424, 528,1922,2188,1503,1873,1570,2364,3342, # 5366 -3276,7614, 557,1073,7615,1827,3445,2087,2266,3140,3039,3084, 767,3085,2786,4425, # 5382 -1006,4158,4426,2341,1267,2176,3664,3199, 778,3945,3200,2722,1597,2657,7616,4427, # 5398 -7617,3446,7618,7619,7620,3277,2689,1433,3278, 131, 95,1504,3946, 723,4159,3141, # 5414 -1841,3555,2758,2189,3947,2027,2104,3665,7621,2995,3948,1218,7622,3343,3201,3949, # 5430 -4160,2576, 248,1634,3785, 912,7623,2832,3666,3040,3786, 654, 53,7624,2996,7625, # 5446 -1688,4428, 777,3447,1032,3950,1425,7626, 191, 820,2120,2833, 971,4429, 931,3202, # 5462 - 135, 664, 783,3787,1997, 772,2908,1935,3951,3788,4430,2909,3203, 282,2723, 640, # 5478 -1372,3448,1127, 922, 325,3344,7627,7628, 711,2044,7629,7630,3952,2219,2787,1936, # 5494 -3953,3345,2220,2251,3789,2300,7631,4431,3790,1258,3279,3954,3204,2138,2950,3955, # 5510 -3956,7632,2221, 258,3205,4432, 101,1227,7633,3280,1755,7634,1391,3281,7635,2910, # 5526 -2056, 893,7636,7637,7638,1402,4161,2342,7639,7640,3206,3556,7641,7642, 878,1325, # 5542 -1780,2788,4433, 259,1385,2577, 744,1183,2267,4434,7643,3957,2502,7644, 684,1024, # 5558 -4162,7645, 472,3557,3449,1165,3282,3958,3959, 322,2152, 881, 455,1695,1152,1340, # 5574 - 660, 554,2153,4435,1058,4436,4163, 830,1065,3346,3960,4437,1923,7646,1703,1918, # 5590 -7647, 932,2268, 122,7648,4438, 947, 677,7649,3791,2627, 297,1905,1924,2269,4439, # 5606 -2317,3283,7650,7651,4164,7652,4165, 84,4166, 112, 989,7653, 547,1059,3961, 701, # 5622 -3558,1019,7654,4167,7655,3450, 942, 639, 457,2301,2451, 993,2951, 407, 851, 494, # 5638 -4440,3347, 927,7656,1237,7657,2421,3348, 573,4168, 680, 921,2911,1279,1874, 285, # 5654 - 790,1448,1983, 719,2167,7658,7659,4441,3962,3963,1649,7660,1541, 563,7661,1077, # 5670 -7662,3349,3041,3451, 511,2997,3964,3965,3667,3966,1268,2564,3350,3207,4442,4443, # 5686 -7663, 535,1048,1276,1189,2912,2028,3142,1438,1373,2834,2952,1134,2012,7664,4169, # 5702 -1238,2578,3086,1259,7665, 700,7666,2953,3143,3668,4170,7667,4171,1146,1875,1906, # 5718 -4444,2601,3967, 781,2422, 132,1589, 203, 147, 273,2789,2402, 898,1786,2154,3968, # 5734 -3969,7668,3792,2790,7669,7670,4445,4446,7671,3208,7672,1635,3793, 965,7673,1804, # 5750 -2690,1516,3559,1121,1082,1329,3284,3970,1449,3794, 65,1128,2835,2913,2759,1590, # 5766 -3795,7674,7675, 12,2658, 45, 976,2579,3144,4447, 517,2528,1013,1037,3209,7676, # 5782 -3796,2836,7677,3797,7678,3452,7679,2602, 614,1998,2318,3798,3087,2724,2628,7680, # 5798 -2580,4172, 599,1269,7681,1810,3669,7682,2691,3088, 759,1060, 489,1805,3351,3285, # 5814 -1358,7683,7684,2386,1387,1215,2629,2252, 490,7685,7686,4173,1759,2387,2343,7687, # 5830 -4448,3799,1907,3971,2630,1806,3210,4449,3453,3286,2760,2344, 874,7688,7689,3454, # 5846 -3670,1858, 91,2914,3671,3042,3800,4450,7690,3145,3972,2659,7691,3455,1202,1403, # 5862 -3801,2954,2529,1517,2503,4451,3456,2504,7692,4452,7693,2692,1885,1495,1731,3973, # 5878 -2365,4453,7694,2029,7695,7696,3974,2693,1216, 237,2581,4174,2319,3975,3802,4454, # 5894 -4455,2694,3560,3457, 445,4456,7697,7698,7699,7700,2761, 61,3976,3672,1822,3977, # 5910 -7701, 687,2045, 935, 925, 405,2660, 703,1096,1859,2725,4457,3978,1876,1367,2695, # 5926 -3352, 918,2105,1781,2476, 334,3287,1611,1093,4458, 564,3146,3458,3673,3353, 945, # 5942 -2631,2057,4459,7702,1925, 872,4175,7703,3459,2696,3089, 349,4176,3674,3979,4460, # 5958 -3803,4177,3675,2155,3980,4461,4462,4178,4463,2403,2046, 782,3981, 400, 251,4179, # 5974 -1624,7704,7705, 277,3676, 299,1265, 476,1191,3804,2121,4180,4181,1109, 205,7706, # 5990 -2582,1000,2156,3561,1860,7707,7708,7709,4464,7710,4465,2565, 107,2477,2157,3982, # 6006 -3460,3147,7711,1533, 541,1301, 158, 753,4182,2872,3562,7712,1696, 370,1088,4183, # 6022 -4466,3563, 579, 327, 440, 162,2240, 269,1937,1374,3461, 968,3043, 56,1396,3090, # 6038 -2106,3288,3354,7713,1926,2158,4467,2998,7714,3564,7715,7716,3677,4468,2478,7717, # 6054 -2791,7718,1650,4469,7719,2603,7720,7721,3983,2661,3355,1149,3356,3984,3805,3985, # 6070 -7722,1076, 49,7723, 951,3211,3289,3290, 450,2837, 920,7724,1811,2792,2366,4184, # 6086 -1908,1138,2367,3806,3462,7725,3212,4470,1909,1147,1518,2423,4471,3807,7726,4472, # 6102 -2388,2604, 260,1795,3213,7727,7728,3808,3291, 708,7729,3565,1704,7730,3566,1351, # 6118 -1618,3357,2999,1886, 944,4185,3358,4186,3044,3359,4187,7731,3678, 422, 413,1714, # 6134 -3292, 500,2058,2345,4188,2479,7732,1344,1910, 954,7733,1668,7734,7735,3986,2404, # 6150 -4189,3567,3809,4190,7736,2302,1318,2505,3091, 133,3092,2873,4473, 629, 31,2838, # 6166 -2697,3810,4474, 850, 949,4475,3987,2955,1732,2088,4191,1496,1852,7737,3988, 620, # 6182 -3214, 981,1242,3679,3360,1619,3680,1643,3293,2139,2452,1970,1719,3463,2168,7738, # 6198 -3215,7739,7740,3361,1828,7741,1277,4476,1565,2047,7742,1636,3568,3093,7743, 869, # 6214 -2839, 655,3811,3812,3094,3989,3000,3813,1310,3569,4477,7744,7745,7746,1733, 558, # 6230 -4478,3681, 335,1549,3045,1756,4192,3682,1945,3464,1829,1291,1192, 470,2726,2107, # 6246 -2793, 913,1054,3990,7747,1027,7748,3046,3991,4479, 982,2662,3362,3148,3465,3216, # 6262 -3217,1946,2794,7749, 571,4480,7750,1830,7751,3570,2583,1523,2424,7752,2089, 984, # 6278 -4481,3683,1959,7753,3684, 852, 923,2795,3466,3685, 969,1519, 999,2048,2320,1705, # 6294 -7754,3095, 615,1662, 151, 597,3992,2405,2321,1049, 275,4482,3686,4193, 568,3687, # 6310 -3571,2480,4194,3688,7755,2425,2270, 409,3218,7756,1566,2874,3467,1002, 769,2840, # 6326 - 194,2090,3149,3689,2222,3294,4195, 628,1505,7757,7758,1763,2177,3001,3993, 521, # 6342 -1161,2584,1787,2203,2406,4483,3994,1625,4196,4197, 412, 42,3096, 464,7759,2632, # 6358 -4484,3363,1760,1571,2875,3468,2530,1219,2204,3814,2633,2140,2368,4485,4486,3295, # 6374 -1651,3364,3572,7760,7761,3573,2481,3469,7762,3690,7763,7764,2271,2091, 460,7765, # 6390 -4487,7766,3002, 962, 588,3574, 289,3219,2634,1116, 52,7767,3047,1796,7768,7769, # 6406 -7770,1467,7771,1598,1143,3691,4198,1984,1734,1067,4488,1280,3365, 465,4489,1572, # 6422 - 510,7772,1927,2241,1812,1644,3575,7773,4490,3692,7774,7775,2663,1573,1534,7776, # 6438 -7777,4199, 536,1807,1761,3470,3815,3150,2635,7778,7779,7780,4491,3471,2915,1911, # 6454 -2796,7781,3296,1122, 377,3220,7782, 360,7783,7784,4200,1529, 551,7785,2059,3693, # 6470 -1769,2426,7786,2916,4201,3297,3097,2322,2108,2030,4492,1404, 136,1468,1479, 672, # 6486 -1171,3221,2303, 271,3151,7787,2762,7788,2049, 678,2727, 865,1947,4493,7789,2013, # 6502 -3995,2956,7790,2728,2223,1397,3048,3694,4494,4495,1735,2917,3366,3576,7791,3816, # 6518 - 509,2841,2453,2876,3817,7792,7793,3152,3153,4496,4202,2531,4497,2304,1166,1010, # 6534 - 552, 681,1887,7794,7795,2957,2958,3996,1287,1596,1861,3154, 358, 453, 736, 175, # 6550 - 478,1117, 905,1167,1097,7796,1853,1530,7797,1706,7798,2178,3472,2287,3695,3473, # 6566 -3577,4203,2092,4204,7799,3367,1193,2482,4205,1458,2190,2205,1862,1888,1421,3298, # 6582 -2918,3049,2179,3474, 595,2122,7800,3997,7801,7802,4206,1707,2636, 223,3696,1359, # 6598 - 751,3098, 183,3475,7803,2797,3003, 419,2369, 633, 704,3818,2389, 241,7804,7805, # 6614 -7806, 838,3004,3697,2272,2763,2454,3819,1938,2050,3998,1309,3099,2242,1181,7807, # 6630 -1136,2206,3820,2370,1446,4207,2305,4498,7808,7809,4208,1055,2605, 484,3698,7810, # 6646 -3999, 625,4209,2273,3368,1499,4210,4000,7811,4001,4211,3222,2274,2275,3476,7812, # 6662 -7813,2764, 808,2606,3699,3369,4002,4212,3100,2532, 526,3370,3821,4213, 955,7814, # 6678 -1620,4214,2637,2427,7815,1429,3700,1669,1831, 994, 928,7816,3578,1260,7817,7818, # 6694 -7819,1948,2288, 741,2919,1626,4215,2729,2455, 867,1184, 362,3371,1392,7820,7821, # 6710 -4003,4216,1770,1736,3223,2920,4499,4500,1928,2698,1459,1158,7822,3050,3372,2877, # 6726 -1292,1929,2506,2842,3701,1985,1187,2071,2014,2607,4217,7823,2566,2507,2169,3702, # 6742 -2483,3299,7824,3703,4501,7825,7826, 666,1003,3005,1022,3579,4218,7827,4502,1813, # 6758 -2253, 574,3822,1603, 295,1535, 705,3823,4219, 283, 858, 417,7828,7829,3224,4503, # 6774 -4504,3051,1220,1889,1046,2276,2456,4004,1393,1599, 689,2567, 388,4220,7830,2484, # 6790 - 802,7831,2798,3824,2060,1405,2254,7832,4505,3825,2109,1052,1345,3225,1585,7833, # 6806 - 809,7834,7835,7836, 575,2730,3477, 956,1552,1469,1144,2323,7837,2324,1560,2457, # 6822 -3580,3226,4005, 616,2207,3155,2180,2289,7838,1832,7839,3478,4506,7840,1319,3704, # 6838 -3705,1211,3581,1023,3227,1293,2799,7841,7842,7843,3826, 607,2306,3827, 762,2878, # 6854 -1439,4221,1360,7844,1485,3052,7845,4507,1038,4222,1450,2061,2638,4223,1379,4508, # 6870 -2585,7846,7847,4224,1352,1414,2325,2921,1172,7848,7849,3828,3829,7850,1797,1451, # 6886 -7851,7852,7853,7854,2922,4006,4007,2485,2346, 411,4008,4009,3582,3300,3101,4509, # 6902 -1561,2664,1452,4010,1375,7855,7856, 47,2959, 316,7857,1406,1591,2923,3156,7858, # 6918 -1025,2141,3102,3157, 354,2731, 884,2224,4225,2407, 508,3706, 726,3583, 996,2428, # 6934 -3584, 729,7859, 392,2191,1453,4011,4510,3707,7860,7861,2458,3585,2608,1675,2800, # 6950 - 919,2347,2960,2348,1270,4511,4012, 73,7862,7863, 647,7864,3228,2843,2255,1550, # 6966 -1346,3006,7865,1332, 883,3479,7866,7867,7868,7869,3301,2765,7870,1212, 831,1347, # 6982 -4226,4512,2326,3830,1863,3053, 720,3831,4513,4514,3832,7871,4227,7872,7873,4515, # 6998 -7874,7875,1798,4516,3708,2609,4517,3586,1645,2371,7876,7877,2924, 669,2208,2665, # 7014 -2429,7878,2879,7879,7880,1028,3229,7881,4228,2408,7882,2256,1353,7883,7884,4518, # 7030 -3158, 518,7885,4013,7886,4229,1960,7887,2142,4230,7888,7889,3007,2349,2350,3833, # 7046 - 516,1833,1454,4014,2699,4231,4519,2225,2610,1971,1129,3587,7890,2766,7891,2961, # 7062 -1422, 577,1470,3008,1524,3373,7892,7893, 432,4232,3054,3480,7894,2586,1455,2508, # 7078 -2226,1972,1175,7895,1020,2732,4015,3481,4520,7896,2733,7897,1743,1361,3055,3482, # 7094 -2639,4016,4233,4521,2290, 895, 924,4234,2170, 331,2243,3056, 166,1627,3057,1098, # 7110 -7898,1232,2880,2227,3374,4522, 657, 403,1196,2372, 542,3709,3375,1600,4235,3483, # 7126 -7899,4523,2767,3230, 576, 530,1362,7900,4524,2533,2666,3710,4017,7901, 842,3834, # 7142 -7902,2801,2031,1014,4018, 213,2700,3376, 665, 621,4236,7903,3711,2925,2430,7904, # 7158 -2431,3302,3588,3377,7905,4237,2534,4238,4525,3589,1682,4239,3484,1380,7906, 724, # 7174 -2277, 600,1670,7907,1337,1233,4526,3103,2244,7908,1621,4527,7909, 651,4240,7910, # 7190 -1612,4241,2611,7911,2844,7912,2734,2307,3058,7913, 716,2459,3059, 174,1255,2701, # 7206 -4019,3590, 548,1320,1398, 728,4020,1574,7914,1890,1197,3060,4021,7915,3061,3062, # 7222 -3712,3591,3713, 747,7916, 635,4242,4528,7917,7918,7919,4243,7920,7921,4529,7922, # 7238 -3378,4530,2432, 451,7923,3714,2535,2072,4244,2735,4245,4022,7924,1764,4531,7925, # 7254 -4246, 350,7926,2278,2390,2486,7927,4247,4023,2245,1434,4024, 488,4532, 458,4248, # 7270 -4025,3715, 771,1330,2391,3835,2568,3159,2159,2409,1553,2667,3160,4249,7928,2487, # 7286 -2881,2612,1720,2702,4250,3379,4533,7929,2536,4251,7930,3231,4252,2768,7931,2015, # 7302 -2736,7932,1155,1017,3716,3836,7933,3303,2308, 201,1864,4253,1430,7934,4026,7935, # 7318 -7936,7937,7938,7939,4254,1604,7940, 414,1865, 371,2587,4534,4535,3485,2016,3104, # 7334 -4536,1708, 960,4255, 887, 389,2171,1536,1663,1721,7941,2228,4027,2351,2926,1580, # 7350 -7942,7943,7944,1744,7945,2537,4537,4538,7946,4539,7947,2073,7948,7949,3592,3380, # 7366 -2882,4256,7950,4257,2640,3381,2802, 673,2703,2460, 709,3486,4028,3593,4258,7951, # 7382 -1148, 502, 634,7952,7953,1204,4540,3594,1575,4541,2613,3717,7954,3718,3105, 948, # 7398 -3232, 121,1745,3837,1110,7955,4259,3063,2509,3009,4029,3719,1151,1771,3838,1488, # 7414 -4030,1986,7956,2433,3487,7957,7958,2093,7959,4260,3839,1213,1407,2803, 531,2737, # 7430 -2538,3233,1011,1537,7960,2769,4261,3106,1061,7961,3720,3721,1866,2883,7962,2017, # 7446 - 120,4262,4263,2062,3595,3234,2309,3840,2668,3382,1954,4542,7963,7964,3488,1047, # 7462 -2704,1266,7965,1368,4543,2845, 649,3383,3841,2539,2738,1102,2846,2669,7966,7967, # 7478 -1999,7968,1111,3596,2962,7969,2488,3842,3597,2804,1854,3384,3722,7970,7971,3385, # 7494 -2410,2884,3304,3235,3598,7972,2569,7973,3599,2805,4031,1460, 856,7974,3600,7975, # 7510 -2885,2963,7976,2886,3843,7977,4264, 632,2510, 875,3844,1697,3845,2291,7978,7979, # 7526 -4544,3010,1239, 580,4545,4265,7980, 914, 936,2074,1190,4032,1039,2123,7981,7982, # 7542 -7983,3386,1473,7984,1354,4266,3846,7985,2172,3064,4033, 915,3305,4267,4268,3306, # 7558 -1605,1834,7986,2739, 398,3601,4269,3847,4034, 328,1912,2847,4035,3848,1331,4270, # 7574 -3011, 937,4271,7987,3602,4036,4037,3387,2160,4546,3388, 524, 742, 538,3065,1012, # 7590 -7988,7989,3849,2461,7990, 658,1103, 225,3850,7991,7992,4547,7993,4548,7994,3236, # 7606 -1243,7995,4038, 963,2246,4549,7996,2705,3603,3161,7997,7998,2588,2327,7999,4550, # 7622 -8000,8001,8002,3489,3307, 957,3389,2540,2032,1930,2927,2462, 870,2018,3604,1746, # 7638 -2770,2771,2434,2463,8003,3851,8004,3723,3107,3724,3490,3390,3725,8005,1179,3066, # 7654 -8006,3162,2373,4272,3726,2541,3163,3108,2740,4039,8007,3391,1556,2542,2292, 977, # 7670 -2887,2033,4040,1205,3392,8008,1765,3393,3164,2124,1271,1689, 714,4551,3491,8009, # 7686 -2328,3852, 533,4273,3605,2181, 617,8010,2464,3308,3492,2310,8011,8012,3165,8013, # 7702 -8014,3853,1987, 618, 427,2641,3493,3394,8015,8016,1244,1690,8017,2806,4274,4552, # 7718 -8018,3494,8019,8020,2279,1576, 473,3606,4275,3395, 972,8021,3607,8022,3067,8023, # 7734 -8024,4553,4554,8025,3727,4041,4042,8026, 153,4555, 356,8027,1891,2888,4276,2143, # 7750 - 408, 803,2352,8028,3854,8029,4277,1646,2570,2511,4556,4557,3855,8030,3856,4278, # 7766 -8031,2411,3396, 752,8032,8033,1961,2964,8034, 746,3012,2465,8035,4279,3728, 698, # 7782 -4558,1892,4280,3608,2543,4559,3609,3857,8036,3166,3397,8037,1823,1302,4043,2706, # 7798 -3858,1973,4281,8038,4282,3167, 823,1303,1288,1236,2848,3495,4044,3398, 774,3859, # 7814 -8039,1581,4560,1304,2849,3860,4561,8040,2435,2161,1083,3237,4283,4045,4284, 344, # 7830 -1173, 288,2311, 454,1683,8041,8042,1461,4562,4046,2589,8043,8044,4563, 985, 894, # 7846 -8045,3399,3168,8046,1913,2928,3729,1988,8047,2110,1974,8048,4047,8049,2571,1194, # 7862 - 425,8050,4564,3169,1245,3730,4285,8051,8052,2850,8053, 636,4565,1855,3861, 760, # 7878 -1799,8054,4286,2209,1508,4566,4048,1893,1684,2293,8055,8056,8057,4287,4288,2210, # 7894 - 479,8058,8059, 832,8060,4049,2489,8061,2965,2490,3731, 990,3109, 627,1814,2642, # 7910 -4289,1582,4290,2125,2111,3496,4567,8062, 799,4291,3170,8063,4568,2112,1737,3013, # 7926 -1018, 543, 754,4292,3309,1676,4569,4570,4050,8064,1489,8065,3497,8066,2614,2889, # 7942 -4051,8067,8068,2966,8069,8070,8071,8072,3171,4571,4572,2182,1722,8073,3238,3239, # 7958 -1842,3610,1715, 481, 365,1975,1856,8074,8075,1962,2491,4573,8076,2126,3611,3240, # 7974 - 433,1894,2063,2075,8077, 602,2741,8078,8079,8080,8081,8082,3014,1628,3400,8083, # 7990 -3172,4574,4052,2890,4575,2512,8084,2544,2772,8085,8086,8087,3310,4576,2891,8088, # 8006 -4577,8089,2851,4578,4579,1221,2967,4053,2513,8090,8091,8092,1867,1989,8093,8094, # 8022 -8095,1895,8096,8097,4580,1896,4054, 318,8098,2094,4055,4293,8099,8100, 485,8101, # 8038 - 938,3862, 553,2670, 116,8102,3863,3612,8103,3498,2671,2773,3401,3311,2807,8104, # 8054 -3613,2929,4056,1747,2930,2968,8105,8106, 207,8107,8108,2672,4581,2514,8109,3015, # 8070 - 890,3614,3864,8110,1877,3732,3402,8111,2183,2353,3403,1652,8112,8113,8114, 941, # 8086 -2294, 208,3499,4057,2019, 330,4294,3865,2892,2492,3733,4295,8115,8116,8117,8118, # 8102 -#Everything below is of no interest for detection purpose -2515,1613,4582,8119,3312,3866,2516,8120,4058,8121,1637,4059,2466,4583,3867,8122, # 8118 -2493,3016,3734,8123,8124,2192,8125,8126,2162,8127,8128,8129,8130,8131,8132,8133, # 8134 -8134,8135,8136,8137,8138,8139,8140,8141,8142,8143,8144,8145,8146,8147,8148,8149, # 8150 -8150,8151,8152,8153,8154,8155,8156,8157,8158,8159,8160,8161,8162,8163,8164,8165, # 8166 -8166,8167,8168,8169,8170,8171,8172,8173,8174,8175,8176,8177,8178,8179,8180,8181, # 8182 -8182,8183,8184,8185,8186,8187,8188,8189,8190,8191,8192,8193,8194,8195,8196,8197, # 8198 -8198,8199,8200,8201,8202,8203,8204,8205,8206,8207,8208,8209,8210,8211,8212,8213, # 8214 -8214,8215,8216,8217,8218,8219,8220,8221,8222,8223,8224,8225,8226,8227,8228,8229, # 8230 -8230,8231,8232,8233,8234,8235,8236,8237,8238,8239,8240,8241,8242,8243,8244,8245, # 8246 -8246,8247,8248,8249,8250,8251,8252,8253,8254,8255,8256,8257,8258,8259,8260,8261, # 8262 -8262,8263,8264,8265,8266,8267,8268,8269,8270,8271,8272,8273,8274,8275,8276,8277, # 8278 -8278,8279,8280,8281,8282,8283,8284,8285,8286,8287,8288,8289,8290,8291,8292,8293, # 8294 -8294,8295,8296,8297,8298,8299,8300,8301,8302,8303,8304,8305,8306,8307,8308,8309, # 8310 -8310,8311,8312,8313,8314,8315,8316,8317,8318,8319,8320,8321,8322,8323,8324,8325, # 8326 -8326,8327,8328,8329,8330,8331,8332,8333,8334,8335,8336,8337,8338,8339,8340,8341, # 8342 -8342,8343,8344,8345,8346,8347,8348,8349,8350,8351,8352,8353,8354,8355,8356,8357, # 8358 -8358,8359,8360,8361,8362,8363,8364,8365,8366,8367,8368,8369,8370,8371,8372,8373, # 8374 -8374,8375,8376,8377,8378,8379,8380,8381,8382,8383,8384,8385,8386,8387,8388,8389, # 8390 -8390,8391,8392,8393,8394,8395,8396,8397,8398,8399,8400,8401,8402,8403,8404,8405, # 8406 -8406,8407,8408,8409,8410,8411,8412,8413,8414,8415,8416,8417,8418,8419,8420,8421, # 8422 -8422,8423,8424,8425,8426,8427,8428,8429,8430,8431,8432,8433,8434,8435,8436,8437, # 8438 -8438,8439,8440,8441,8442,8443,8444,8445,8446,8447,8448,8449,8450,8451,8452,8453, # 8454 -8454,8455,8456,8457,8458,8459,8460,8461,8462,8463,8464,8465,8466,8467,8468,8469, # 8470 -8470,8471,8472,8473,8474,8475,8476,8477,8478,8479,8480,8481,8482,8483,8484,8485, # 8486 -8486,8487,8488,8489,8490,8491,8492,8493,8494,8495,8496,8497,8498,8499,8500,8501, # 8502 -8502,8503,8504,8505,8506,8507,8508,8509,8510,8511,8512,8513,8514,8515,8516,8517, # 8518 -8518,8519,8520,8521,8522,8523,8524,8525,8526,8527,8528,8529,8530,8531,8532,8533, # 8534 -8534,8535,8536,8537,8538,8539,8540,8541,8542,8543,8544,8545,8546,8547,8548,8549, # 8550 -8550,8551,8552,8553,8554,8555,8556,8557,8558,8559,8560,8561,8562,8563,8564,8565, # 8566 -8566,8567,8568,8569,8570,8571,8572,8573,8574,8575,8576,8577,8578,8579,8580,8581, # 8582 -8582,8583,8584,8585,8586,8587,8588,8589,8590,8591,8592,8593,8594,8595,8596,8597, # 8598 -8598,8599,8600,8601,8602,8603,8604,8605,8606,8607,8608,8609,8610,8611,8612,8613, # 8614 -8614,8615,8616,8617,8618,8619,8620,8621,8622,8623,8624,8625,8626,8627,8628,8629, # 8630 -8630,8631,8632,8633,8634,8635,8636,8637,8638,8639,8640,8641,8642,8643,8644,8645, # 8646 -8646,8647,8648,8649,8650,8651,8652,8653,8654,8655,8656,8657,8658,8659,8660,8661, # 8662 -8662,8663,8664,8665,8666,8667,8668,8669,8670,8671,8672,8673,8674,8675,8676,8677, # 8678 -8678,8679,8680,8681,8682,8683,8684,8685,8686,8687,8688,8689,8690,8691,8692,8693, # 8694 -8694,8695,8696,8697,8698,8699,8700,8701,8702,8703,8704,8705,8706,8707,8708,8709, # 8710 -8710,8711,8712,8713,8714,8715,8716,8717,8718,8719,8720,8721,8722,8723,8724,8725, # 8726 -8726,8727,8728,8729,8730,8731,8732,8733,8734,8735,8736,8737,8738,8739,8740,8741) # 8742 +EUCTW_CHAR_TO_FREQ_ORDER = ( + 1,1800,1506, 255,1431, 198, 9, 82, 6,7310, 177, 202,3615,1256,2808, 110, # 2742 +3735, 33,3241, 261, 76, 44,2113, 16,2931,2184,1176, 659,3868, 26,3404,2643, # 2758 +1198,3869,3313,4060, 410,2211, 302, 590, 361,1963, 8, 204, 58,4296,7311,1931, # 2774 + 63,7312,7313, 317,1614, 75, 222, 159,4061,2412,1480,7314,3500,3068, 224,2809, # 2790 +3616, 3, 10,3870,1471, 29,2774,1135,2852,1939, 873, 130,3242,1123, 312,7315, # 2806 +4297,2051, 507, 252, 682,7316, 142,1914, 124, 206,2932, 34,3501,3173, 64, 604, # 2822 +7317,2494,1976,1977, 155,1990, 645, 641,1606,7318,3405, 337, 72, 406,7319, 80, # 2838 + 630, 238,3174,1509, 263, 939,1092,2644, 756,1440,1094,3406, 449, 69,2969, 591, # 2854 + 179,2095, 471, 115,2034,1843, 60, 50,2970, 134, 806,1868, 734,2035,3407, 180, # 2870 + 995,1607, 156, 537,2893, 688,7320, 319,1305, 779,2144, 514,2374, 298,4298, 359, # 2886 +2495, 90,2707,1338, 663, 11, 906,1099,2545, 20,2436, 182, 532,1716,7321, 732, # 2902 +1376,4062,1311,1420,3175, 25,2312,1056, 113, 399, 382,1949, 242,3408,2467, 529, # 2918 +3243, 475,1447,3617,7322, 117, 21, 656, 810,1297,2295,2329,3502,7323, 126,4063, # 2934 + 706, 456, 150, 613,4299, 71,1118,2036,4064, 145,3069, 85, 835, 486,2114,1246, # 2950 +1426, 428, 727,1285,1015, 800, 106, 623, 303,1281,7324,2127,2354, 347,3736, 221, # 2966 +3503,3110,7325,1955,1153,4065, 83, 296,1199,3070, 192, 624, 93,7326, 822,1897, # 2982 +2810,3111, 795,2064, 991,1554,1542,1592, 27, 43,2853, 859, 139,1456, 860,4300, # 2998 + 437, 712,3871, 164,2392,3112, 695, 211,3017,2096, 195,3872,1608,3504,3505,3618, # 3014 +3873, 234, 811,2971,2097,3874,2229,1441,3506,1615,2375, 668,2076,1638, 305, 228, # 3030 +1664,4301, 467, 415,7327, 262,2098,1593, 239, 108, 300, 200,1033, 512,1247,2077, # 3046 +7328,7329,2173,3176,3619,2673, 593, 845,1062,3244, 88,1723,2037,3875,1950, 212, # 3062 + 266, 152, 149, 468,1898,4066,4302, 77, 187,7330,3018, 37, 5,2972,7331,3876, # 3078 +7332,7333, 39,2517,4303,2894,3177,2078, 55, 148, 74,4304, 545, 483,1474,1029, # 3094 +1665, 217,1869,1531,3113,1104,2645,4067, 24, 172,3507, 900,3877,3508,3509,4305, # 3110 + 32,1408,2811,1312, 329, 487,2355,2247,2708, 784,2674, 4,3019,3314,1427,1788, # 3126 + 188, 109, 499,7334,3620,1717,1789, 888,1217,3020,4306,7335,3510,7336,3315,1520, # 3142 +3621,3878, 196,1034, 775,7337,7338, 929,1815, 249, 439, 38,7339,1063,7340, 794, # 3158 +3879,1435,2296, 46, 178,3245,2065,7341,2376,7342, 214,1709,4307, 804, 35, 707, # 3174 + 324,3622,1601,2546, 140, 459,4068,7343,7344,1365, 839, 272, 978,2257,2572,3409, # 3190 +2128,1363,3623,1423, 697, 100,3071, 48, 70,1231, 495,3114,2193,7345,1294,7346, # 3206 +2079, 462, 586,1042,3246, 853, 256, 988, 185,2377,3410,1698, 434,1084,7347,3411, # 3222 + 314,2615,2775,4308,2330,2331, 569,2280, 637,1816,2518, 757,1162,1878,1616,3412, # 3238 + 287,1577,2115, 768,4309,1671,2854,3511,2519,1321,3737, 909,2413,7348,4069, 933, # 3254 +3738,7349,2052,2356,1222,4310, 765,2414,1322, 786,4311,7350,1919,1462,1677,2895, # 3270 +1699,7351,4312,1424,2437,3115,3624,2590,3316,1774,1940,3413,3880,4070, 309,1369, # 3286 +1130,2812, 364,2230,1653,1299,3881,3512,3882,3883,2646, 525,1085,3021, 902,2000, # 3302 +1475, 964,4313, 421,1844,1415,1057,2281, 940,1364,3116, 376,4314,4315,1381, 7, # 3318 +2520, 983,2378, 336,1710,2675,1845, 321,3414, 559,1131,3022,2742,1808,1132,1313, # 3334 + 265,1481,1857,7352, 352,1203,2813,3247, 167,1089, 420,2814, 776, 792,1724,3513, # 3350 +4071,2438,3248,7353,4072,7354, 446, 229, 333,2743, 901,3739,1200,1557,4316,2647, # 3366 +1920, 395,2744,2676,3740,4073,1835, 125, 916,3178,2616,4317,7355,7356,3741,7357, # 3382 +7358,7359,4318,3117,3625,1133,2547,1757,3415,1510,2313,1409,3514,7360,2145, 438, # 3398 +2591,2896,2379,3317,1068, 958,3023, 461, 311,2855,2677,4074,1915,3179,4075,1978, # 3414 + 383, 750,2745,2617,4076, 274, 539, 385,1278,1442,7361,1154,1964, 384, 561, 210, # 3430 + 98,1295,2548,3515,7362,1711,2415,1482,3416,3884,2897,1257, 129,7363,3742, 642, # 3446 + 523,2776,2777,2648,7364, 141,2231,1333, 68, 176, 441, 876, 907,4077, 603,2592, # 3462 + 710, 171,3417, 404, 549, 18,3118,2393,1410,3626,1666,7365,3516,4319,2898,4320, # 3478 +7366,2973, 368,7367, 146, 366, 99, 871,3627,1543, 748, 807,1586,1185, 22,2258, # 3494 + 379,3743,3180,7368,3181, 505,1941,2618,1991,1382,2314,7369, 380,2357, 218, 702, # 3510 +1817,1248,3418,3024,3517,3318,3249,7370,2974,3628, 930,3250,3744,7371, 59,7372, # 3526 + 585, 601,4078, 497,3419,1112,1314,4321,1801,7373,1223,1472,2174,7374, 749,1836, # 3542 + 690,1899,3745,1772,3885,1476, 429,1043,1790,2232,2116, 917,4079, 447,1086,1629, # 3558 +7375, 556,7376,7377,2020,1654, 844,1090, 105, 550, 966,1758,2815,1008,1782, 686, # 3574 +1095,7378,2282, 793,1602,7379,3518,2593,4322,4080,2933,2297,4323,3746, 980,2496, # 3590 + 544, 353, 527,4324, 908,2678,2899,7380, 381,2619,1942,1348,7381,1341,1252, 560, # 3606 +3072,7382,3420,2856,7383,2053, 973, 886,2080, 143,4325,7384,7385, 157,3886, 496, # 3622 +4081, 57, 840, 540,2038,4326,4327,3421,2117,1445, 970,2259,1748,1965,2081,4082, # 3638 +3119,1234,1775,3251,2816,3629, 773,1206,2129,1066,2039,1326,3887,1738,1725,4083, # 3654 + 279,3120, 51,1544,2594, 423,1578,2130,2066, 173,4328,1879,7386,7387,1583, 264, # 3670 + 610,3630,4329,2439, 280, 154,7388,7389,7390,1739, 338,1282,3073, 693,2857,1411, # 3686 +1074,3747,2440,7391,4330,7392,7393,1240, 952,2394,7394,2900,1538,2679, 685,1483, # 3702 +4084,2468,1436, 953,4085,2054,4331, 671,2395, 79,4086,2441,3252, 608, 567,2680, # 3718 +3422,4087,4088,1691, 393,1261,1791,2396,7395,4332,7396,7397,7398,7399,1383,1672, # 3734 +3748,3182,1464, 522,1119, 661,1150, 216, 675,4333,3888,1432,3519, 609,4334,2681, # 3750 +2397,7400,7401,7402,4089,3025, 0,7403,2469, 315, 231,2442, 301,3319,4335,2380, # 3766 +7404, 233,4090,3631,1818,4336,4337,7405, 96,1776,1315,2082,7406, 257,7407,1809, # 3782 +3632,2709,1139,1819,4091,2021,1124,2163,2778,1777,2649,7408,3074, 363,1655,3183, # 3798 +7409,2975,7410,7411,7412,3889,1567,3890, 718, 103,3184, 849,1443, 341,3320,2934, # 3814 +1484,7413,1712, 127, 67, 339,4092,2398, 679,1412, 821,7414,7415, 834, 738, 351, # 3830 +2976,2146, 846, 235,1497,1880, 418,1992,3749,2710, 186,1100,2147,2746,3520,1545, # 3846 +1355,2935,2858,1377, 583,3891,4093,2573,2977,7416,1298,3633,1078,2549,3634,2358, # 3862 + 78,3750,3751, 267,1289,2099,2001,1594,4094, 348, 369,1274,2194,2175,1837,4338, # 3878 +1820,2817,3635,2747,2283,2002,4339,2936,2748, 144,3321, 882,4340,3892,2749,3423, # 3894 +4341,2901,7417,4095,1726, 320,7418,3893,3026, 788,2978,7419,2818,1773,1327,2859, # 3910 +3894,2819,7420,1306,4342,2003,1700,3752,3521,2359,2650, 787,2022, 506, 824,3636, # 3926 + 534, 323,4343,1044,3322,2023,1900, 946,3424,7421,1778,1500,1678,7422,1881,4344, # 3942 + 165, 243,4345,3637,2521, 123, 683,4096, 764,4346, 36,3895,1792, 589,2902, 816, # 3958 + 626,1667,3027,2233,1639,1555,1622,3753,3896,7423,3897,2860,1370,1228,1932, 891, # 3974 +2083,2903, 304,4097,7424, 292,2979,2711,3522, 691,2100,4098,1115,4347, 118, 662, # 3990 +7425, 611,1156, 854,2381,1316,2861, 2, 386, 515,2904,7426,7427,3253, 868,2234, # 4006 +1486, 855,2651, 785,2212,3028,7428,1040,3185,3523,7429,3121, 448,7430,1525,7431, # 4022 +2164,4348,7432,3754,7433,4099,2820,3524,3122, 503, 818,3898,3123,1568, 814, 676, # 4038 +1444, 306,1749,7434,3755,1416,1030, 197,1428, 805,2821,1501,4349,7435,7436,7437, # 4054 +1993,7438,4350,7439,7440,2195, 13,2779,3638,2980,3124,1229,1916,7441,3756,2131, # 4070 +7442,4100,4351,2399,3525,7443,2213,1511,1727,1120,7444,7445, 646,3757,2443, 307, # 4086 +7446,7447,1595,3186,7448,7449,7450,3639,1113,1356,3899,1465,2522,2523,7451, 519, # 4102 +7452, 128,2132, 92,2284,1979,7453,3900,1512, 342,3125,2196,7454,2780,2214,1980, # 4118 +3323,7455, 290,1656,1317, 789, 827,2360,7456,3758,4352, 562, 581,3901,7457, 401, # 4134 +4353,2248, 94,4354,1399,2781,7458,1463,2024,4355,3187,1943,7459, 828,1105,4101, # 4150 +1262,1394,7460,4102, 605,4356,7461,1783,2862,7462,2822, 819,2101, 578,2197,2937, # 4166 +7463,1502, 436,3254,4103,3255,2823,3902,2905,3425,3426,7464,2712,2315,7465,7466, # 4182 +2332,2067, 23,4357, 193, 826,3759,2102, 699,1630,4104,3075, 390,1793,1064,3526, # 4198 +7467,1579,3076,3077,1400,7468,4105,1838,1640,2863,7469,4358,4359, 137,4106, 598, # 4214 +3078,1966, 780, 104, 974,2938,7470, 278, 899, 253, 402, 572, 504, 493,1339,7471, # 4230 +3903,1275,4360,2574,2550,7472,3640,3029,3079,2249, 565,1334,2713, 863, 41,7473, # 4246 +7474,4361,7475,1657,2333, 19, 463,2750,4107, 606,7476,2981,3256,1087,2084,1323, # 4262 +2652,2982,7477,1631,1623,1750,4108,2682,7478,2864, 791,2714,2653,2334, 232,2416, # 4278 +7479,2983,1498,7480,2654,2620, 755,1366,3641,3257,3126,2025,1609, 119,1917,3427, # 4294 + 862,1026,4109,7481,3904,3760,4362,3905,4363,2260,1951,2470,7482,1125, 817,4110, # 4310 +4111,3906,1513,1766,2040,1487,4112,3030,3258,2824,3761,3127,7483,7484,1507,7485, # 4326 +2683, 733, 40,1632,1106,2865, 345,4113, 841,2524, 230,4364,2984,1846,3259,3428, # 4342 +7486,1263, 986,3429,7487, 735, 879, 254,1137, 857, 622,1300,1180,1388,1562,3907, # 4358 +3908,2939, 967,2751,2655,1349, 592,2133,1692,3324,2985,1994,4114,1679,3909,1901, # 4374 +2185,7488, 739,3642,2715,1296,1290,7489,4115,2198,2199,1921,1563,2595,2551,1870, # 4390 +2752,2986,7490, 435,7491, 343,1108, 596, 17,1751,4365,2235,3430,3643,7492,4366, # 4406 + 294,3527,2940,1693, 477, 979, 281,2041,3528, 643,2042,3644,2621,2782,2261,1031, # 4422 +2335,2134,2298,3529,4367, 367,1249,2552,7493,3530,7494,4368,1283,3325,2004, 240, # 4438 +1762,3326,4369,4370, 836,1069,3128, 474,7495,2148,2525, 268,3531,7496,3188,1521, # 4454 +1284,7497,1658,1546,4116,7498,3532,3533,7499,4117,3327,2684,1685,4118, 961,1673, # 4470 +2622, 190,2005,2200,3762,4371,4372,7500, 570,2497,3645,1490,7501,4373,2623,3260, # 4486 +1956,4374, 584,1514, 396,1045,1944,7502,4375,1967,2444,7503,7504,4376,3910, 619, # 4502 +7505,3129,3261, 215,2006,2783,2553,3189,4377,3190,4378, 763,4119,3763,4379,7506, # 4518 +7507,1957,1767,2941,3328,3646,1174, 452,1477,4380,3329,3130,7508,2825,1253,2382, # 4534 +2186,1091,2285,4120, 492,7509, 638,1169,1824,2135,1752,3911, 648, 926,1021,1324, # 4550 +4381, 520,4382, 997, 847,1007, 892,4383,3764,2262,1871,3647,7510,2400,1784,4384, # 4566 +1952,2942,3080,3191,1728,4121,2043,3648,4385,2007,1701,3131,1551, 30,2263,4122, # 4582 +7511,2026,4386,3534,7512, 501,7513,4123, 594,3431,2165,1821,3535,3432,3536,3192, # 4598 + 829,2826,4124,7514,1680,3132,1225,4125,7515,3262,4387,4126,3133,2336,7516,4388, # 4614 +4127,7517,3912,3913,7518,1847,2383,2596,3330,7519,4389, 374,3914, 652,4128,4129, # 4630 + 375,1140, 798,7520,7521,7522,2361,4390,2264, 546,1659, 138,3031,2445,4391,7523, # 4646 +2250, 612,1848, 910, 796,3765,1740,1371, 825,3766,3767,7524,2906,2554,7525, 692, # 4662 + 444,3032,2624, 801,4392,4130,7526,1491, 244,1053,3033,4131,4132, 340,7527,3915, # 4678 +1041,2987, 293,1168, 87,1357,7528,1539, 959,7529,2236, 721, 694,4133,3768, 219, # 4694 +1478, 644,1417,3331,2656,1413,1401,1335,1389,3916,7530,7531,2988,2362,3134,1825, # 4710 + 730,1515, 184,2827, 66,4393,7532,1660,2943, 246,3332, 378,1457, 226,3433, 975, # 4726 +3917,2944,1264,3537, 674, 696,7533, 163,7534,1141,2417,2166, 713,3538,3333,4394, # 4742 +3918,7535,7536,1186, 15,7537,1079,1070,7538,1522,3193,3539, 276,1050,2716, 758, # 4758 +1126, 653,2945,3263,7539,2337, 889,3540,3919,3081,2989, 903,1250,4395,3920,3434, # 4774 +3541,1342,1681,1718, 766,3264, 286, 89,2946,3649,7540,1713,7541,2597,3334,2990, # 4790 +7542,2947,2215,3194,2866,7543,4396,2498,2526, 181, 387,1075,3921, 731,2187,3335, # 4806 +7544,3265, 310, 313,3435,2299, 770,4134, 54,3034, 189,4397,3082,3769,3922,7545, # 4822 +1230,1617,1849, 355,3542,4135,4398,3336, 111,4136,3650,1350,3135,3436,3035,4137, # 4838 +2149,3266,3543,7546,2784,3923,3924,2991, 722,2008,7547,1071, 247,1207,2338,2471, # 4854 +1378,4399,2009, 864,1437,1214,4400, 373,3770,1142,2216, 667,4401, 442,2753,2555, # 4870 +3771,3925,1968,4138,3267,1839, 837, 170,1107, 934,1336,1882,7548,7549,2118,4139, # 4886 +2828, 743,1569,7550,4402,4140, 582,2384,1418,3437,7551,1802,7552, 357,1395,1729, # 4902 +3651,3268,2418,1564,2237,7553,3083,3772,1633,4403,1114,2085,4141,1532,7554, 482, # 4918 +2446,4404,7555,7556,1492, 833,1466,7557,2717,3544,1641,2829,7558,1526,1272,3652, # 4934 +4142,1686,1794, 416,2556,1902,1953,1803,7559,3773,2785,3774,1159,2316,7560,2867, # 4950 +4405,1610,1584,3036,2419,2754, 443,3269,1163,3136,7561,7562,3926,7563,4143,2499, # 4966 +3037,4406,3927,3137,2103,1647,3545,2010,1872,4144,7564,4145, 431,3438,7565, 250, # 4982 + 97, 81,4146,7566,1648,1850,1558, 160, 848,7567, 866, 740,1694,7568,2201,2830, # 4998 +3195,4147,4407,3653,1687, 950,2472, 426, 469,3196,3654,3655,3928,7569,7570,1188, # 5014 + 424,1995, 861,3546,4148,3775,2202,2685, 168,1235,3547,4149,7571,2086,1674,4408, # 5030 +3337,3270, 220,2557,1009,7572,3776, 670,2992, 332,1208, 717,7573,7574,3548,2447, # 5046 +3929,3338,7575, 513,7576,1209,2868,3339,3138,4409,1080,7577,7578,7579,7580,2527, # 5062 +3656,3549, 815,1587,3930,3931,7581,3550,3439,3777,1254,4410,1328,3038,1390,3932, # 5078 +1741,3933,3778,3934,7582, 236,3779,2448,3271,7583,7584,3657,3780,1273,3781,4411, # 5094 +7585, 308,7586,4412, 245,4413,1851,2473,1307,2575, 430, 715,2136,2449,7587, 270, # 5110 + 199,2869,3935,7588,3551,2718,1753, 761,1754, 725,1661,1840,4414,3440,3658,7589, # 5126 +7590, 587, 14,3272, 227,2598, 326, 480,2265, 943,2755,3552, 291, 650,1883,7591, # 5142 +1702,1226, 102,1547, 62,3441, 904,4415,3442,1164,4150,7592,7593,1224,1548,2756, # 5158 + 391, 498,1493,7594,1386,1419,7595,2055,1177,4416, 813, 880,1081,2363, 566,1145, # 5174 +4417,2286,1001,1035,2558,2599,2238, 394,1286,7596,7597,2068,7598, 86,1494,1730, # 5190 +3936, 491,1588, 745, 897,2948, 843,3340,3937,2757,2870,3273,1768, 998,2217,2069, # 5206 + 397,1826,1195,1969,3659,2993,3341, 284,7599,3782,2500,2137,2119,1903,7600,3938, # 5222 +2150,3939,4151,1036,3443,1904, 114,2559,4152, 209,1527,7601,7602,2949,2831,2625, # 5238 +2385,2719,3139, 812,2560,7603,3274,7604,1559, 737,1884,3660,1210, 885, 28,2686, # 5254 +3553,3783,7605,4153,1004,1779,4418,7606, 346,1981,2218,2687,4419,3784,1742, 797, # 5270 +1642,3940,1933,1072,1384,2151, 896,3941,3275,3661,3197,2871,3554,7607,2561,1958, # 5286 +4420,2450,1785,7608,7609,7610,3942,4154,1005,1308,3662,4155,2720,4421,4422,1528, # 5302 +2600, 161,1178,4156,1982, 987,4423,1101,4157, 631,3943,1157,3198,2420,1343,1241, # 5318 +1016,2239,2562, 372, 877,2339,2501,1160, 555,1934, 911,3944,7611, 466,1170, 169, # 5334 +1051,2907,2688,3663,2474,2994,1182,2011,2563,1251,2626,7612, 992,2340,3444,1540, # 5350 +2721,1201,2070,2401,1996,2475,7613,4424, 528,1922,2188,1503,1873,1570,2364,3342, # 5366 +3276,7614, 557,1073,7615,1827,3445,2087,2266,3140,3039,3084, 767,3085,2786,4425, # 5382 +1006,4158,4426,2341,1267,2176,3664,3199, 778,3945,3200,2722,1597,2657,7616,4427, # 5398 +7617,3446,7618,7619,7620,3277,2689,1433,3278, 131, 95,1504,3946, 723,4159,3141, # 5414 +1841,3555,2758,2189,3947,2027,2104,3665,7621,2995,3948,1218,7622,3343,3201,3949, # 5430 +4160,2576, 248,1634,3785, 912,7623,2832,3666,3040,3786, 654, 53,7624,2996,7625, # 5446 +1688,4428, 777,3447,1032,3950,1425,7626, 191, 820,2120,2833, 971,4429, 931,3202, # 5462 + 135, 664, 783,3787,1997, 772,2908,1935,3951,3788,4430,2909,3203, 282,2723, 640, # 5478 +1372,3448,1127, 922, 325,3344,7627,7628, 711,2044,7629,7630,3952,2219,2787,1936, # 5494 +3953,3345,2220,2251,3789,2300,7631,4431,3790,1258,3279,3954,3204,2138,2950,3955, # 5510 +3956,7632,2221, 258,3205,4432, 101,1227,7633,3280,1755,7634,1391,3281,7635,2910, # 5526 +2056, 893,7636,7637,7638,1402,4161,2342,7639,7640,3206,3556,7641,7642, 878,1325, # 5542 +1780,2788,4433, 259,1385,2577, 744,1183,2267,4434,7643,3957,2502,7644, 684,1024, # 5558 +4162,7645, 472,3557,3449,1165,3282,3958,3959, 322,2152, 881, 455,1695,1152,1340, # 5574 + 660, 554,2153,4435,1058,4436,4163, 830,1065,3346,3960,4437,1923,7646,1703,1918, # 5590 +7647, 932,2268, 122,7648,4438, 947, 677,7649,3791,2627, 297,1905,1924,2269,4439, # 5606 +2317,3283,7650,7651,4164,7652,4165, 84,4166, 112, 989,7653, 547,1059,3961, 701, # 5622 +3558,1019,7654,4167,7655,3450, 942, 639, 457,2301,2451, 993,2951, 407, 851, 494, # 5638 +4440,3347, 927,7656,1237,7657,2421,3348, 573,4168, 680, 921,2911,1279,1874, 285, # 5654 + 790,1448,1983, 719,2167,7658,7659,4441,3962,3963,1649,7660,1541, 563,7661,1077, # 5670 +7662,3349,3041,3451, 511,2997,3964,3965,3667,3966,1268,2564,3350,3207,4442,4443, # 5686 +7663, 535,1048,1276,1189,2912,2028,3142,1438,1373,2834,2952,1134,2012,7664,4169, # 5702 +1238,2578,3086,1259,7665, 700,7666,2953,3143,3668,4170,7667,4171,1146,1875,1906, # 5718 +4444,2601,3967, 781,2422, 132,1589, 203, 147, 273,2789,2402, 898,1786,2154,3968, # 5734 +3969,7668,3792,2790,7669,7670,4445,4446,7671,3208,7672,1635,3793, 965,7673,1804, # 5750 +2690,1516,3559,1121,1082,1329,3284,3970,1449,3794, 65,1128,2835,2913,2759,1590, # 5766 +3795,7674,7675, 12,2658, 45, 976,2579,3144,4447, 517,2528,1013,1037,3209,7676, # 5782 +3796,2836,7677,3797,7678,3452,7679,2602, 614,1998,2318,3798,3087,2724,2628,7680, # 5798 +2580,4172, 599,1269,7681,1810,3669,7682,2691,3088, 759,1060, 489,1805,3351,3285, # 5814 +1358,7683,7684,2386,1387,1215,2629,2252, 490,7685,7686,4173,1759,2387,2343,7687, # 5830 +4448,3799,1907,3971,2630,1806,3210,4449,3453,3286,2760,2344, 874,7688,7689,3454, # 5846 +3670,1858, 91,2914,3671,3042,3800,4450,7690,3145,3972,2659,7691,3455,1202,1403, # 5862 +3801,2954,2529,1517,2503,4451,3456,2504,7692,4452,7693,2692,1885,1495,1731,3973, # 5878 +2365,4453,7694,2029,7695,7696,3974,2693,1216, 237,2581,4174,2319,3975,3802,4454, # 5894 +4455,2694,3560,3457, 445,4456,7697,7698,7699,7700,2761, 61,3976,3672,1822,3977, # 5910 +7701, 687,2045, 935, 925, 405,2660, 703,1096,1859,2725,4457,3978,1876,1367,2695, # 5926 +3352, 918,2105,1781,2476, 334,3287,1611,1093,4458, 564,3146,3458,3673,3353, 945, # 5942 +2631,2057,4459,7702,1925, 872,4175,7703,3459,2696,3089, 349,4176,3674,3979,4460, # 5958 +3803,4177,3675,2155,3980,4461,4462,4178,4463,2403,2046, 782,3981, 400, 251,4179, # 5974 +1624,7704,7705, 277,3676, 299,1265, 476,1191,3804,2121,4180,4181,1109, 205,7706, # 5990 +2582,1000,2156,3561,1860,7707,7708,7709,4464,7710,4465,2565, 107,2477,2157,3982, # 6006 +3460,3147,7711,1533, 541,1301, 158, 753,4182,2872,3562,7712,1696, 370,1088,4183, # 6022 +4466,3563, 579, 327, 440, 162,2240, 269,1937,1374,3461, 968,3043, 56,1396,3090, # 6038 +2106,3288,3354,7713,1926,2158,4467,2998,7714,3564,7715,7716,3677,4468,2478,7717, # 6054 +2791,7718,1650,4469,7719,2603,7720,7721,3983,2661,3355,1149,3356,3984,3805,3985, # 6070 +7722,1076, 49,7723, 951,3211,3289,3290, 450,2837, 920,7724,1811,2792,2366,4184, # 6086 +1908,1138,2367,3806,3462,7725,3212,4470,1909,1147,1518,2423,4471,3807,7726,4472, # 6102 +2388,2604, 260,1795,3213,7727,7728,3808,3291, 708,7729,3565,1704,7730,3566,1351, # 6118 +1618,3357,2999,1886, 944,4185,3358,4186,3044,3359,4187,7731,3678, 422, 413,1714, # 6134 +3292, 500,2058,2345,4188,2479,7732,1344,1910, 954,7733,1668,7734,7735,3986,2404, # 6150 +4189,3567,3809,4190,7736,2302,1318,2505,3091, 133,3092,2873,4473, 629, 31,2838, # 6166 +2697,3810,4474, 850, 949,4475,3987,2955,1732,2088,4191,1496,1852,7737,3988, 620, # 6182 +3214, 981,1242,3679,3360,1619,3680,1643,3293,2139,2452,1970,1719,3463,2168,7738, # 6198 +3215,7739,7740,3361,1828,7741,1277,4476,1565,2047,7742,1636,3568,3093,7743, 869, # 6214 +2839, 655,3811,3812,3094,3989,3000,3813,1310,3569,4477,7744,7745,7746,1733, 558, # 6230 +4478,3681, 335,1549,3045,1756,4192,3682,1945,3464,1829,1291,1192, 470,2726,2107, # 6246 +2793, 913,1054,3990,7747,1027,7748,3046,3991,4479, 982,2662,3362,3148,3465,3216, # 6262 +3217,1946,2794,7749, 571,4480,7750,1830,7751,3570,2583,1523,2424,7752,2089, 984, # 6278 +4481,3683,1959,7753,3684, 852, 923,2795,3466,3685, 969,1519, 999,2048,2320,1705, # 6294 +7754,3095, 615,1662, 151, 597,3992,2405,2321,1049, 275,4482,3686,4193, 568,3687, # 6310 +3571,2480,4194,3688,7755,2425,2270, 409,3218,7756,1566,2874,3467,1002, 769,2840, # 6326 + 194,2090,3149,3689,2222,3294,4195, 628,1505,7757,7758,1763,2177,3001,3993, 521, # 6342 +1161,2584,1787,2203,2406,4483,3994,1625,4196,4197, 412, 42,3096, 464,7759,2632, # 6358 +4484,3363,1760,1571,2875,3468,2530,1219,2204,3814,2633,2140,2368,4485,4486,3295, # 6374 +1651,3364,3572,7760,7761,3573,2481,3469,7762,3690,7763,7764,2271,2091, 460,7765, # 6390 +4487,7766,3002, 962, 588,3574, 289,3219,2634,1116, 52,7767,3047,1796,7768,7769, # 6406 +7770,1467,7771,1598,1143,3691,4198,1984,1734,1067,4488,1280,3365, 465,4489,1572, # 6422 + 510,7772,1927,2241,1812,1644,3575,7773,4490,3692,7774,7775,2663,1573,1534,7776, # 6438 +7777,4199, 536,1807,1761,3470,3815,3150,2635,7778,7779,7780,4491,3471,2915,1911, # 6454 +2796,7781,3296,1122, 377,3220,7782, 360,7783,7784,4200,1529, 551,7785,2059,3693, # 6470 +1769,2426,7786,2916,4201,3297,3097,2322,2108,2030,4492,1404, 136,1468,1479, 672, # 6486 +1171,3221,2303, 271,3151,7787,2762,7788,2049, 678,2727, 865,1947,4493,7789,2013, # 6502 +3995,2956,7790,2728,2223,1397,3048,3694,4494,4495,1735,2917,3366,3576,7791,3816, # 6518 + 509,2841,2453,2876,3817,7792,7793,3152,3153,4496,4202,2531,4497,2304,1166,1010, # 6534 + 552, 681,1887,7794,7795,2957,2958,3996,1287,1596,1861,3154, 358, 453, 736, 175, # 6550 + 478,1117, 905,1167,1097,7796,1853,1530,7797,1706,7798,2178,3472,2287,3695,3473, # 6566 +3577,4203,2092,4204,7799,3367,1193,2482,4205,1458,2190,2205,1862,1888,1421,3298, # 6582 +2918,3049,2179,3474, 595,2122,7800,3997,7801,7802,4206,1707,2636, 223,3696,1359, # 6598 + 751,3098, 183,3475,7803,2797,3003, 419,2369, 633, 704,3818,2389, 241,7804,7805, # 6614 +7806, 838,3004,3697,2272,2763,2454,3819,1938,2050,3998,1309,3099,2242,1181,7807, # 6630 +1136,2206,3820,2370,1446,4207,2305,4498,7808,7809,4208,1055,2605, 484,3698,7810, # 6646 +3999, 625,4209,2273,3368,1499,4210,4000,7811,4001,4211,3222,2274,2275,3476,7812, # 6662 +7813,2764, 808,2606,3699,3369,4002,4212,3100,2532, 526,3370,3821,4213, 955,7814, # 6678 +1620,4214,2637,2427,7815,1429,3700,1669,1831, 994, 928,7816,3578,1260,7817,7818, # 6694 +7819,1948,2288, 741,2919,1626,4215,2729,2455, 867,1184, 362,3371,1392,7820,7821, # 6710 +4003,4216,1770,1736,3223,2920,4499,4500,1928,2698,1459,1158,7822,3050,3372,2877, # 6726 +1292,1929,2506,2842,3701,1985,1187,2071,2014,2607,4217,7823,2566,2507,2169,3702, # 6742 +2483,3299,7824,3703,4501,7825,7826, 666,1003,3005,1022,3579,4218,7827,4502,1813, # 6758 +2253, 574,3822,1603, 295,1535, 705,3823,4219, 283, 858, 417,7828,7829,3224,4503, # 6774 +4504,3051,1220,1889,1046,2276,2456,4004,1393,1599, 689,2567, 388,4220,7830,2484, # 6790 + 802,7831,2798,3824,2060,1405,2254,7832,4505,3825,2109,1052,1345,3225,1585,7833, # 6806 + 809,7834,7835,7836, 575,2730,3477, 956,1552,1469,1144,2323,7837,2324,1560,2457, # 6822 +3580,3226,4005, 616,2207,3155,2180,2289,7838,1832,7839,3478,4506,7840,1319,3704, # 6838 +3705,1211,3581,1023,3227,1293,2799,7841,7842,7843,3826, 607,2306,3827, 762,2878, # 6854 +1439,4221,1360,7844,1485,3052,7845,4507,1038,4222,1450,2061,2638,4223,1379,4508, # 6870 +2585,7846,7847,4224,1352,1414,2325,2921,1172,7848,7849,3828,3829,7850,1797,1451, # 6886 +7851,7852,7853,7854,2922,4006,4007,2485,2346, 411,4008,4009,3582,3300,3101,4509, # 6902 +1561,2664,1452,4010,1375,7855,7856, 47,2959, 316,7857,1406,1591,2923,3156,7858, # 6918 +1025,2141,3102,3157, 354,2731, 884,2224,4225,2407, 508,3706, 726,3583, 996,2428, # 6934 +3584, 729,7859, 392,2191,1453,4011,4510,3707,7860,7861,2458,3585,2608,1675,2800, # 6950 + 919,2347,2960,2348,1270,4511,4012, 73,7862,7863, 647,7864,3228,2843,2255,1550, # 6966 +1346,3006,7865,1332, 883,3479,7866,7867,7868,7869,3301,2765,7870,1212, 831,1347, # 6982 +4226,4512,2326,3830,1863,3053, 720,3831,4513,4514,3832,7871,4227,7872,7873,4515, # 6998 +7874,7875,1798,4516,3708,2609,4517,3586,1645,2371,7876,7877,2924, 669,2208,2665, # 7014 +2429,7878,2879,7879,7880,1028,3229,7881,4228,2408,7882,2256,1353,7883,7884,4518, # 7030 +3158, 518,7885,4013,7886,4229,1960,7887,2142,4230,7888,7889,3007,2349,2350,3833, # 7046 + 516,1833,1454,4014,2699,4231,4519,2225,2610,1971,1129,3587,7890,2766,7891,2961, # 7062 +1422, 577,1470,3008,1524,3373,7892,7893, 432,4232,3054,3480,7894,2586,1455,2508, # 7078 +2226,1972,1175,7895,1020,2732,4015,3481,4520,7896,2733,7897,1743,1361,3055,3482, # 7094 +2639,4016,4233,4521,2290, 895, 924,4234,2170, 331,2243,3056, 166,1627,3057,1098, # 7110 +7898,1232,2880,2227,3374,4522, 657, 403,1196,2372, 542,3709,3375,1600,4235,3483, # 7126 +7899,4523,2767,3230, 576, 530,1362,7900,4524,2533,2666,3710,4017,7901, 842,3834, # 7142 +7902,2801,2031,1014,4018, 213,2700,3376, 665, 621,4236,7903,3711,2925,2430,7904, # 7158 +2431,3302,3588,3377,7905,4237,2534,4238,4525,3589,1682,4239,3484,1380,7906, 724, # 7174 +2277, 600,1670,7907,1337,1233,4526,3103,2244,7908,1621,4527,7909, 651,4240,7910, # 7190 +1612,4241,2611,7911,2844,7912,2734,2307,3058,7913, 716,2459,3059, 174,1255,2701, # 7206 +4019,3590, 548,1320,1398, 728,4020,1574,7914,1890,1197,3060,4021,7915,3061,3062, # 7222 +3712,3591,3713, 747,7916, 635,4242,4528,7917,7918,7919,4243,7920,7921,4529,7922, # 7238 +3378,4530,2432, 451,7923,3714,2535,2072,4244,2735,4245,4022,7924,1764,4531,7925, # 7254 +4246, 350,7926,2278,2390,2486,7927,4247,4023,2245,1434,4024, 488,4532, 458,4248, # 7270 +4025,3715, 771,1330,2391,3835,2568,3159,2159,2409,1553,2667,3160,4249,7928,2487, # 7286 +2881,2612,1720,2702,4250,3379,4533,7929,2536,4251,7930,3231,4252,2768,7931,2015, # 7302 +2736,7932,1155,1017,3716,3836,7933,3303,2308, 201,1864,4253,1430,7934,4026,7935, # 7318 +7936,7937,7938,7939,4254,1604,7940, 414,1865, 371,2587,4534,4535,3485,2016,3104, # 7334 +4536,1708, 960,4255, 887, 389,2171,1536,1663,1721,7941,2228,4027,2351,2926,1580, # 7350 +7942,7943,7944,1744,7945,2537,4537,4538,7946,4539,7947,2073,7948,7949,3592,3380, # 7366 +2882,4256,7950,4257,2640,3381,2802, 673,2703,2460, 709,3486,4028,3593,4258,7951, # 7382 +1148, 502, 634,7952,7953,1204,4540,3594,1575,4541,2613,3717,7954,3718,3105, 948, # 7398 +3232, 121,1745,3837,1110,7955,4259,3063,2509,3009,4029,3719,1151,1771,3838,1488, # 7414 +4030,1986,7956,2433,3487,7957,7958,2093,7959,4260,3839,1213,1407,2803, 531,2737, # 7430 +2538,3233,1011,1537,7960,2769,4261,3106,1061,7961,3720,3721,1866,2883,7962,2017, # 7446 + 120,4262,4263,2062,3595,3234,2309,3840,2668,3382,1954,4542,7963,7964,3488,1047, # 7462 +2704,1266,7965,1368,4543,2845, 649,3383,3841,2539,2738,1102,2846,2669,7966,7967, # 7478 +1999,7968,1111,3596,2962,7969,2488,3842,3597,2804,1854,3384,3722,7970,7971,3385, # 7494 +2410,2884,3304,3235,3598,7972,2569,7973,3599,2805,4031,1460, 856,7974,3600,7975, # 7510 +2885,2963,7976,2886,3843,7977,4264, 632,2510, 875,3844,1697,3845,2291,7978,7979, # 7526 +4544,3010,1239, 580,4545,4265,7980, 914, 936,2074,1190,4032,1039,2123,7981,7982, # 7542 +7983,3386,1473,7984,1354,4266,3846,7985,2172,3064,4033, 915,3305,4267,4268,3306, # 7558 +1605,1834,7986,2739, 398,3601,4269,3847,4034, 328,1912,2847,4035,3848,1331,4270, # 7574 +3011, 937,4271,7987,3602,4036,4037,3387,2160,4546,3388, 524, 742, 538,3065,1012, # 7590 +7988,7989,3849,2461,7990, 658,1103, 225,3850,7991,7992,4547,7993,4548,7994,3236, # 7606 +1243,7995,4038, 963,2246,4549,7996,2705,3603,3161,7997,7998,2588,2327,7999,4550, # 7622 +8000,8001,8002,3489,3307, 957,3389,2540,2032,1930,2927,2462, 870,2018,3604,1746, # 7638 +2770,2771,2434,2463,8003,3851,8004,3723,3107,3724,3490,3390,3725,8005,1179,3066, # 7654 +8006,3162,2373,4272,3726,2541,3163,3108,2740,4039,8007,3391,1556,2542,2292, 977, # 7670 +2887,2033,4040,1205,3392,8008,1765,3393,3164,2124,1271,1689, 714,4551,3491,8009, # 7686 +2328,3852, 533,4273,3605,2181, 617,8010,2464,3308,3492,2310,8011,8012,3165,8013, # 7702 +8014,3853,1987, 618, 427,2641,3493,3394,8015,8016,1244,1690,8017,2806,4274,4552, # 7718 +8018,3494,8019,8020,2279,1576, 473,3606,4275,3395, 972,8021,3607,8022,3067,8023, # 7734 +8024,4553,4554,8025,3727,4041,4042,8026, 153,4555, 356,8027,1891,2888,4276,2143, # 7750 + 408, 803,2352,8028,3854,8029,4277,1646,2570,2511,4556,4557,3855,8030,3856,4278, # 7766 +8031,2411,3396, 752,8032,8033,1961,2964,8034, 746,3012,2465,8035,4279,3728, 698, # 7782 +4558,1892,4280,3608,2543,4559,3609,3857,8036,3166,3397,8037,1823,1302,4043,2706, # 7798 +3858,1973,4281,8038,4282,3167, 823,1303,1288,1236,2848,3495,4044,3398, 774,3859, # 7814 +8039,1581,4560,1304,2849,3860,4561,8040,2435,2161,1083,3237,4283,4045,4284, 344, # 7830 +1173, 288,2311, 454,1683,8041,8042,1461,4562,4046,2589,8043,8044,4563, 985, 894, # 7846 +8045,3399,3168,8046,1913,2928,3729,1988,8047,2110,1974,8048,4047,8049,2571,1194, # 7862 + 425,8050,4564,3169,1245,3730,4285,8051,8052,2850,8053, 636,4565,1855,3861, 760, # 7878 +1799,8054,4286,2209,1508,4566,4048,1893,1684,2293,8055,8056,8057,4287,4288,2210, # 7894 + 479,8058,8059, 832,8060,4049,2489,8061,2965,2490,3731, 990,3109, 627,1814,2642, # 7910 +4289,1582,4290,2125,2111,3496,4567,8062, 799,4291,3170,8063,4568,2112,1737,3013, # 7926 +1018, 543, 754,4292,3309,1676,4569,4570,4050,8064,1489,8065,3497,8066,2614,2889, # 7942 +4051,8067,8068,2966,8069,8070,8071,8072,3171,4571,4572,2182,1722,8073,3238,3239, # 7958 +1842,3610,1715, 481, 365,1975,1856,8074,8075,1962,2491,4573,8076,2126,3611,3240, # 7974 + 433,1894,2063,2075,8077, 602,2741,8078,8079,8080,8081,8082,3014,1628,3400,8083, # 7990 +3172,4574,4052,2890,4575,2512,8084,2544,2772,8085,8086,8087,3310,4576,2891,8088, # 8006 +4577,8089,2851,4578,4579,1221,2967,4053,2513,8090,8091,8092,1867,1989,8093,8094, # 8022 +8095,1895,8096,8097,4580,1896,4054, 318,8098,2094,4055,4293,8099,8100, 485,8101, # 8038 + 938,3862, 553,2670, 116,8102,3863,3612,8103,3498,2671,2773,3401,3311,2807,8104, # 8054 +3613,2929,4056,1747,2930,2968,8105,8106, 207,8107,8108,2672,4581,2514,8109,3015, # 8070 + 890,3614,3864,8110,1877,3732,3402,8111,2183,2353,3403,1652,8112,8113,8114, 941, # 8086 +2294, 208,3499,4057,2019, 330,4294,3865,2892,2492,3733,4295,8115,8116,8117,8118, # 8102 +) -# flake8: noqa diff --git a/venv/Lib/site-packages/requests/packages/chardet/euctwprober.py b/venv/Lib/site-packages/chardet/euctwprober.py similarity index 82% rename from venv/Lib/site-packages/requests/packages/chardet/euctwprober.py rename to venv/Lib/site-packages/chardet/euctwprober.py index fe652fe37..35669cc4d 100644 --- a/venv/Lib/site-packages/requests/packages/chardet/euctwprober.py +++ b/venv/Lib/site-packages/chardet/euctwprober.py @@ -13,12 +13,12 @@ # modify it under the terms of the GNU Lesser General Public # License as published by the Free Software Foundation; either # version 2.1 of the License, or (at your option) any later version. -# +# # This library 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 # Lesser General Public License for more details. -# +# # You should have received a copy of the GNU Lesser General Public # License along with this library; if not, write to the Free Software # Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA @@ -28,14 +28,19 @@ from .mbcharsetprober import MultiByteCharSetProber from .codingstatemachine import CodingStateMachine from .chardistribution import EUCTWDistributionAnalysis -from .mbcssm import EUCTWSMModel +from .mbcssm import EUCTW_SM_MODEL class EUCTWProber(MultiByteCharSetProber): def __init__(self): - MultiByteCharSetProber.__init__(self) - self._mCodingSM = CodingStateMachine(EUCTWSMModel) - self._mDistributionAnalyzer = EUCTWDistributionAnalysis() + super(EUCTWProber, self).__init__() + self.coding_sm = CodingStateMachine(EUCTW_SM_MODEL) + self.distribution_analyzer = EUCTWDistributionAnalysis() self.reset() - def get_charset_name(self): + @property + def charset_name(self): return "EUC-TW" + + @property + def language(self): + return "Taiwan" diff --git a/venv/Lib/site-packages/requests/packages/chardet/gb2312freq.py b/venv/Lib/site-packages/chardet/gb2312freq.py similarity index 57% rename from venv/Lib/site-packages/requests/packages/chardet/gb2312freq.py rename to venv/Lib/site-packages/chardet/gb2312freq.py index 1238f510f..697837bd9 100644 --- a/venv/Lib/site-packages/requests/packages/chardet/gb2312freq.py +++ b/venv/Lib/site-packages/chardet/gb2312freq.py @@ -43,7 +43,7 @@ GB2312_TYPICAL_DISTRIBUTION_RATIO = 0.9 GB2312_TABLE_SIZE = 3760 -GB2312CharToFreqOrder = ( +GB2312_CHAR_TO_FREQ_ORDER = ( 1671, 749,1443,2364,3924,3807,2330,3921,1704,3463,2691,1511,1515, 572,3191,2205, 2361, 224,2558, 479,1711, 963,3162, 440,4060,1905,2966,2947,3580,2647,3961,3842, 2204, 869,4207, 970,2678,5626,2944,2956,1479,4048, 514,3595, 588,1346,2820,3409, @@ -278,195 +278,6 @@ GB2312CharToFreqOrder = ( 1718,1717,2655,3453,3143,4465, 161,2889,2980,2009,1421, 56,1908,1640,2387,2232, 1917,1874,2477,4921, 148, 83,3438, 592,4245,2882,1822,1055, 741, 115,1496,1624, 381,1638,4592,1020, 516,3214, 458, 947,4575,1432, 211,1514,2926,1865,2142, 189, - 852,1221,1400,1486, 882,2299,4036, 351, 28,1122, 700,6479,6480,6481,6482,6483, # last 512 -#Everything below is of no interest for detection purpose -5508,6484,3900,3414,3974,4441,4024,3537,4037,5628,5099,3633,6485,3148,6486,3636, -5509,3257,5510,5973,5445,5872,4941,4403,3174,4627,5873,6276,2286,4230,5446,5874, -5122,6102,6103,4162,5447,5123,5323,4849,6277,3980,3851,5066,4246,5774,5067,6278, -3001,2807,5695,3346,5775,5974,5158,5448,6487,5975,5976,5776,3598,6279,5696,4806, -4211,4154,6280,6488,6489,6490,6281,4212,5037,3374,4171,6491,4562,4807,4722,4827, -5977,6104,4532,4079,5159,5324,5160,4404,3858,5359,5875,3975,4288,4610,3486,4512, -5325,3893,5360,6282,6283,5560,2522,4231,5978,5186,5449,2569,3878,6284,5401,3578, -4415,6285,4656,5124,5979,2506,4247,4449,3219,3417,4334,4969,4329,6492,4576,4828, -4172,4416,4829,5402,6286,3927,3852,5361,4369,4830,4477,4867,5876,4173,6493,6105, -4657,6287,6106,5877,5450,6494,4155,4868,5451,3700,5629,4384,6288,6289,5878,3189, -4881,6107,6290,6495,4513,6496,4692,4515,4723,5100,3356,6497,6291,3810,4080,5561, -3570,4430,5980,6498,4355,5697,6499,4724,6108,6109,3764,4050,5038,5879,4093,3226, -6292,5068,5217,4693,3342,5630,3504,4831,4377,4466,4309,5698,4431,5777,6293,5778, -4272,3706,6110,5326,3752,4676,5327,4273,5403,4767,5631,6500,5699,5880,3475,5039, -6294,5562,5125,4348,4301,4482,4068,5126,4593,5700,3380,3462,5981,5563,3824,5404, -4970,5511,3825,4738,6295,6501,5452,4516,6111,5881,5564,6502,6296,5982,6503,4213, -4163,3454,6504,6112,4009,4450,6113,4658,6297,6114,3035,6505,6115,3995,4904,4739, -4563,4942,4110,5040,3661,3928,5362,3674,6506,5292,3612,4791,5565,4149,5983,5328, -5259,5021,4725,4577,4564,4517,4364,6298,5405,4578,5260,4594,4156,4157,5453,3592, -3491,6507,5127,5512,4709,4922,5984,5701,4726,4289,6508,4015,6116,5128,4628,3424, -4241,5779,6299,4905,6509,6510,5454,5702,5780,6300,4365,4923,3971,6511,5161,3270, -3158,5985,4100, 867,5129,5703,6117,5363,3695,3301,5513,4467,6118,6512,5455,4232, -4242,4629,6513,3959,4478,6514,5514,5329,5986,4850,5162,5566,3846,4694,6119,5456, -4869,5781,3779,6301,5704,5987,5515,4710,6302,5882,6120,4392,5364,5705,6515,6121, -6516,6517,3736,5988,5457,5989,4695,2457,5883,4551,5782,6303,6304,6305,5130,4971, -6122,5163,6123,4870,3263,5365,3150,4871,6518,6306,5783,5069,5706,3513,3498,4409, -5330,5632,5366,5458,5459,3991,5990,4502,3324,5991,5784,3696,4518,5633,4119,6519, -4630,5634,4417,5707,4832,5992,3418,6124,5993,5567,4768,5218,6520,4595,3458,5367, -6125,5635,6126,4202,6521,4740,4924,6307,3981,4069,4385,6308,3883,2675,4051,3834, -4302,4483,5568,5994,4972,4101,5368,6309,5164,5884,3922,6127,6522,6523,5261,5460, -5187,4164,5219,3538,5516,4111,3524,5995,6310,6311,5369,3181,3386,2484,5188,3464, -5569,3627,5708,6524,5406,5165,4677,4492,6312,4872,4851,5885,4468,5996,6313,5709, -5710,6128,2470,5886,6314,5293,4882,5785,3325,5461,5101,6129,5711,5786,6525,4906, -6526,6527,4418,5887,5712,4808,2907,3701,5713,5888,6528,3765,5636,5331,6529,6530, -3593,5889,3637,4943,3692,5714,5787,4925,6315,6130,5462,4405,6131,6132,6316,5262, -6531,6532,5715,3859,5716,5070,4696,5102,3929,5788,3987,4792,5997,6533,6534,3920, -4809,5000,5998,6535,2974,5370,6317,5189,5263,5717,3826,6536,3953,5001,4883,3190, -5463,5890,4973,5999,4741,6133,6134,3607,5570,6000,4711,3362,3630,4552,5041,6318, -6001,2950,2953,5637,4646,5371,4944,6002,2044,4120,3429,6319,6537,5103,4833,6538, -6539,4884,4647,3884,6003,6004,4758,3835,5220,5789,4565,5407,6540,6135,5294,4697, -4852,6320,6321,3206,4907,6541,6322,4945,6542,6136,6543,6323,6005,4631,3519,6544, -5891,6545,5464,3784,5221,6546,5571,4659,6547,6324,6137,5190,6548,3853,6549,4016, -4834,3954,6138,5332,3827,4017,3210,3546,4469,5408,5718,3505,4648,5790,5131,5638, -5791,5465,4727,4318,6325,6326,5792,4553,4010,4698,3439,4974,3638,4335,3085,6006, -5104,5042,5166,5892,5572,6327,4356,4519,5222,5573,5333,5793,5043,6550,5639,5071, -4503,6328,6139,6551,6140,3914,3901,5372,6007,5640,4728,4793,3976,3836,4885,6552, -4127,6553,4451,4102,5002,6554,3686,5105,6555,5191,5072,5295,4611,5794,5296,6556, -5893,5264,5894,4975,5466,5265,4699,4976,4370,4056,3492,5044,4886,6557,5795,4432, -4769,4357,5467,3940,4660,4290,6141,4484,4770,4661,3992,6329,4025,4662,5022,4632, -4835,4070,5297,4663,4596,5574,5132,5409,5895,6142,4504,5192,4664,5796,5896,3885, -5575,5797,5023,4810,5798,3732,5223,4712,5298,4084,5334,5468,6143,4052,4053,4336, -4977,4794,6558,5335,4908,5576,5224,4233,5024,4128,5469,5225,4873,6008,5045,4729, -4742,4633,3675,4597,6559,5897,5133,5577,5003,5641,5719,6330,6560,3017,2382,3854, -4406,4811,6331,4393,3964,4946,6561,2420,3722,6562,4926,4378,3247,1736,4442,6332, -5134,6333,5226,3996,2918,5470,4319,4003,4598,4743,4744,4485,3785,3902,5167,5004, -5373,4394,5898,6144,4874,1793,3997,6334,4085,4214,5106,5642,4909,5799,6009,4419, -4189,3330,5899,4165,4420,5299,5720,5227,3347,6145,4081,6335,2876,3930,6146,3293, -3786,3910,3998,5900,5300,5578,2840,6563,5901,5579,6147,3531,5374,6564,6565,5580, -4759,5375,6566,6148,3559,5643,6336,6010,5517,6337,6338,5721,5902,3873,6011,6339, -6567,5518,3868,3649,5722,6568,4771,4947,6569,6149,4812,6570,2853,5471,6340,6341, -5644,4795,6342,6012,5723,6343,5724,6013,4349,6344,3160,6150,5193,4599,4514,4493, -5168,4320,6345,4927,3666,4745,5169,5903,5005,4928,6346,5725,6014,4730,4203,5046, -4948,3395,5170,6015,4150,6016,5726,5519,6347,5047,3550,6151,6348,4197,4310,5904, -6571,5581,2965,6152,4978,3960,4291,5135,6572,5301,5727,4129,4026,5905,4853,5728, -5472,6153,6349,4533,2700,4505,5336,4678,3583,5073,2994,4486,3043,4554,5520,6350, -6017,5800,4487,6351,3931,4103,5376,6352,4011,4321,4311,4190,5136,6018,3988,3233, -4350,5906,5645,4198,6573,5107,3432,4191,3435,5582,6574,4139,5410,6353,5411,3944, -5583,5074,3198,6575,6354,4358,6576,5302,4600,5584,5194,5412,6577,6578,5585,5413, -5303,4248,5414,3879,4433,6579,4479,5025,4854,5415,6355,4760,4772,3683,2978,4700, -3797,4452,3965,3932,3721,4910,5801,6580,5195,3551,5907,3221,3471,3029,6019,3999, -5908,5909,5266,5267,3444,3023,3828,3170,4796,5646,4979,4259,6356,5647,5337,3694, -6357,5648,5338,4520,4322,5802,3031,3759,4071,6020,5586,4836,4386,5048,6581,3571, -4679,4174,4949,6154,4813,3787,3402,3822,3958,3215,3552,5268,4387,3933,4950,4359, -6021,5910,5075,3579,6358,4234,4566,5521,6359,3613,5049,6022,5911,3375,3702,3178, -4911,5339,4521,6582,6583,4395,3087,3811,5377,6023,6360,6155,4027,5171,5649,4421, -4249,2804,6584,2270,6585,4000,4235,3045,6156,5137,5729,4140,4312,3886,6361,4330, -6157,4215,6158,3500,3676,4929,4331,3713,4930,5912,4265,3776,3368,5587,4470,4855, -3038,4980,3631,6159,6160,4132,4680,6161,6362,3923,4379,5588,4255,6586,4121,6587, -6363,4649,6364,3288,4773,4774,6162,6024,6365,3543,6588,4274,3107,3737,5050,5803, -4797,4522,5589,5051,5730,3714,4887,5378,4001,4523,6163,5026,5522,4701,4175,2791, -3760,6589,5473,4224,4133,3847,4814,4815,4775,3259,5416,6590,2738,6164,6025,5304, -3733,5076,5650,4816,5590,6591,6165,6592,3934,5269,6593,3396,5340,6594,5804,3445, -3602,4042,4488,5731,5732,3525,5591,4601,5196,6166,6026,5172,3642,4612,3202,4506, -4798,6366,3818,5108,4303,5138,5139,4776,3332,4304,2915,3415,4434,5077,5109,4856, -2879,5305,4817,6595,5913,3104,3144,3903,4634,5341,3133,5110,5651,5805,6167,4057, -5592,2945,4371,5593,6596,3474,4182,6367,6597,6168,4507,4279,6598,2822,6599,4777, -4713,5594,3829,6169,3887,5417,6170,3653,5474,6368,4216,2971,5228,3790,4579,6369, -5733,6600,6601,4951,4746,4555,6602,5418,5475,6027,3400,4665,5806,6171,4799,6028, -5052,6172,3343,4800,4747,5006,6370,4556,4217,5476,4396,5229,5379,5477,3839,5914, -5652,5807,4714,3068,4635,5808,6173,5342,4192,5078,5419,5523,5734,6174,4557,6175, -4602,6371,6176,6603,5809,6372,5735,4260,3869,5111,5230,6029,5112,6177,3126,4681, -5524,5915,2706,3563,4748,3130,6178,4018,5525,6604,6605,5478,4012,4837,6606,4534, -4193,5810,4857,3615,5479,6030,4082,3697,3539,4086,5270,3662,4508,4931,5916,4912, -5811,5027,3888,6607,4397,3527,3302,3798,2775,2921,2637,3966,4122,4388,4028,4054, -1633,4858,5079,3024,5007,3982,3412,5736,6608,3426,3236,5595,3030,6179,3427,3336, -3279,3110,6373,3874,3039,5080,5917,5140,4489,3119,6374,5812,3405,4494,6031,4666, -4141,6180,4166,6032,5813,4981,6609,5081,4422,4982,4112,3915,5653,3296,3983,6375, -4266,4410,5654,6610,6181,3436,5082,6611,5380,6033,3819,5596,4535,5231,5306,5113, -6612,4952,5918,4275,3113,6613,6376,6182,6183,5814,3073,4731,4838,5008,3831,6614, -4888,3090,3848,4280,5526,5232,3014,5655,5009,5737,5420,5527,6615,5815,5343,5173, -5381,4818,6616,3151,4953,6617,5738,2796,3204,4360,2989,4281,5739,5174,5421,5197, -3132,5141,3849,5142,5528,5083,3799,3904,4839,5480,2880,4495,3448,6377,6184,5271, -5919,3771,3193,6034,6035,5920,5010,6036,5597,6037,6378,6038,3106,5422,6618,5423, -5424,4142,6619,4889,5084,4890,4313,5740,6620,3437,5175,5307,5816,4199,5198,5529, -5817,5199,5656,4913,5028,5344,3850,6185,2955,5272,5011,5818,4567,4580,5029,5921, -3616,5233,6621,6622,6186,4176,6039,6379,6380,3352,5200,5273,2908,5598,5234,3837, -5308,6623,6624,5819,4496,4323,5309,5201,6625,6626,4983,3194,3838,4167,5530,5922, -5274,6381,6382,3860,3861,5599,3333,4292,4509,6383,3553,5481,5820,5531,4778,6187, -3955,3956,4324,4389,4218,3945,4325,3397,2681,5923,4779,5085,4019,5482,4891,5382, -5383,6040,4682,3425,5275,4094,6627,5310,3015,5483,5657,4398,5924,3168,4819,6628, -5925,6629,5532,4932,4613,6041,6630,4636,6384,4780,4204,5658,4423,5821,3989,4683, -5822,6385,4954,6631,5345,6188,5425,5012,5384,3894,6386,4490,4104,6632,5741,5053, -6633,5823,5926,5659,5660,5927,6634,5235,5742,5824,4840,4933,4820,6387,4859,5928, -4955,6388,4143,3584,5825,5346,5013,6635,5661,6389,5014,5484,5743,4337,5176,5662, -6390,2836,6391,3268,6392,6636,6042,5236,6637,4158,6638,5744,5663,4471,5347,3663, -4123,5143,4293,3895,6639,6640,5311,5929,5826,3800,6189,6393,6190,5664,5348,3554, -3594,4749,4603,6641,5385,4801,6043,5827,4183,6642,5312,5426,4761,6394,5665,6191, -4715,2669,6643,6644,5533,3185,5427,5086,5930,5931,5386,6192,6044,6645,4781,4013, -5745,4282,4435,5534,4390,4267,6045,5746,4984,6046,2743,6193,3501,4087,5485,5932, -5428,4184,4095,5747,4061,5054,3058,3862,5933,5600,6646,5144,3618,6395,3131,5055, -5313,6396,4650,4956,3855,6194,3896,5202,4985,4029,4225,6195,6647,5828,5486,5829, -3589,3002,6648,6397,4782,5276,6649,6196,6650,4105,3803,4043,5237,5830,6398,4096, -3643,6399,3528,6651,4453,3315,4637,6652,3984,6197,5535,3182,3339,6653,3096,2660, -6400,6654,3449,5934,4250,4236,6047,6401,5831,6655,5487,3753,4062,5832,6198,6199, -6656,3766,6657,3403,4667,6048,6658,4338,2897,5833,3880,2797,3780,4326,6659,5748, -5015,6660,5387,4351,5601,4411,6661,3654,4424,5935,4339,4072,5277,4568,5536,6402, -6662,5238,6663,5349,5203,6200,5204,6201,5145,4536,5016,5056,4762,5834,4399,4957, -6202,6403,5666,5749,6664,4340,6665,5936,5177,5667,6666,6667,3459,4668,6404,6668, -6669,4543,6203,6670,4276,6405,4480,5537,6671,4614,5205,5668,6672,3348,2193,4763, -6406,6204,5937,5602,4177,5669,3419,6673,4020,6205,4443,4569,5388,3715,3639,6407, -6049,4058,6206,6674,5938,4544,6050,4185,4294,4841,4651,4615,5488,6207,6408,6051, -5178,3241,3509,5835,6208,4958,5836,4341,5489,5278,6209,2823,5538,5350,5206,5429, -6675,4638,4875,4073,3516,4684,4914,4860,5939,5603,5389,6052,5057,3237,5490,3791, -6676,6409,6677,4821,4915,4106,5351,5058,4243,5539,4244,5604,4842,4916,5239,3028, -3716,5837,5114,5605,5390,5940,5430,6210,4332,6678,5540,4732,3667,3840,6053,4305, -3408,5670,5541,6410,2744,5240,5750,6679,3234,5606,6680,5607,5671,3608,4283,4159, -4400,5352,4783,6681,6411,6682,4491,4802,6211,6412,5941,6413,6414,5542,5751,6683, -4669,3734,5942,6684,6415,5943,5059,3328,4670,4144,4268,6685,6686,6687,6688,4372, -3603,6689,5944,5491,4373,3440,6416,5543,4784,4822,5608,3792,4616,5838,5672,3514, -5391,6417,4892,6690,4639,6691,6054,5673,5839,6055,6692,6056,5392,6212,4038,5544, -5674,4497,6057,6693,5840,4284,5675,4021,4545,5609,6418,4454,6419,6213,4113,4472, -5314,3738,5087,5279,4074,5610,4959,4063,3179,4750,6058,6420,6214,3476,4498,4716, -5431,4960,4685,6215,5241,6694,6421,6216,6695,5841,5945,6422,3748,5946,5179,3905, -5752,5545,5947,4374,6217,4455,6423,4412,6218,4803,5353,6696,3832,5280,6219,4327, -4702,6220,6221,6059,4652,5432,6424,3749,4751,6425,5753,4986,5393,4917,5948,5030, -5754,4861,4733,6426,4703,6697,6222,4671,5949,4546,4961,5180,6223,5031,3316,5281, -6698,4862,4295,4934,5207,3644,6427,5842,5950,6428,6429,4570,5843,5282,6430,6224, -5088,3239,6060,6699,5844,5755,6061,6431,2701,5546,6432,5115,5676,4039,3993,3327, -4752,4425,5315,6433,3941,6434,5677,4617,4604,3074,4581,6225,5433,6435,6226,6062, -4823,5756,5116,6227,3717,5678,4717,5845,6436,5679,5846,6063,5847,6064,3977,3354, -6437,3863,5117,6228,5547,5394,4499,4524,6229,4605,6230,4306,4500,6700,5951,6065, -3693,5952,5089,4366,4918,6701,6231,5548,6232,6702,6438,4704,5434,6703,6704,5953, -4168,6705,5680,3420,6706,5242,4407,6066,3812,5757,5090,5954,4672,4525,3481,5681, -4618,5395,5354,5316,5955,6439,4962,6707,4526,6440,3465,4673,6067,6441,5682,6708, -5435,5492,5758,5683,4619,4571,4674,4804,4893,4686,5493,4753,6233,6068,4269,6442, -6234,5032,4705,5146,5243,5208,5848,6235,6443,4963,5033,4640,4226,6236,5849,3387, -6444,6445,4436,4437,5850,4843,5494,4785,4894,6709,4361,6710,5091,5956,3331,6237, -4987,5549,6069,6711,4342,3517,4473,5317,6070,6712,6071,4706,6446,5017,5355,6713, -6714,4988,5436,6447,4734,5759,6715,4735,4547,4456,4754,6448,5851,6449,6450,3547, -5852,5318,6451,6452,5092,4205,6716,6238,4620,4219,5611,6239,6072,4481,5760,5957, -5958,4059,6240,6453,4227,4537,6241,5761,4030,4186,5244,5209,3761,4457,4876,3337, -5495,5181,6242,5959,5319,5612,5684,5853,3493,5854,6073,4169,5613,5147,4895,6074, -5210,6717,5182,6718,3830,6243,2798,3841,6075,6244,5855,5614,3604,4606,5496,5685, -5118,5356,6719,6454,5960,5357,5961,6720,4145,3935,4621,5119,5962,4261,6721,6455, -4786,5963,4375,4582,6245,6246,6247,6076,5437,4877,5856,3376,4380,6248,4160,6722, -5148,6456,5211,6457,6723,4718,6458,6724,6249,5358,4044,3297,6459,6250,5857,5615, -5497,5245,6460,5498,6725,6251,6252,5550,3793,5499,2959,5396,6461,6462,4572,5093, -5500,5964,3806,4146,6463,4426,5762,5858,6077,6253,4755,3967,4220,5965,6254,4989, -5501,6464,4352,6726,6078,4764,2290,5246,3906,5438,5283,3767,4964,2861,5763,5094, -6255,6256,4622,5616,5859,5860,4707,6727,4285,4708,4824,5617,6257,5551,4787,5212, -4965,4935,4687,6465,6728,6466,5686,6079,3494,4413,2995,5247,5966,5618,6729,5967, -5764,5765,5687,5502,6730,6731,6080,5397,6467,4990,6258,6732,4538,5060,5619,6733, -4719,5688,5439,5018,5149,5284,5503,6734,6081,4607,6259,5120,3645,5861,4583,6260, -4584,4675,5620,4098,5440,6261,4863,2379,3306,4585,5552,5689,4586,5285,6735,4864, -6736,5286,6082,6737,4623,3010,4788,4381,4558,5621,4587,4896,3698,3161,5248,4353, -4045,6262,3754,5183,4588,6738,6263,6739,6740,5622,3936,6741,6468,6742,6264,5095, -6469,4991,5968,6743,4992,6744,6083,4897,6745,4256,5766,4307,3108,3968,4444,5287, -3889,4343,6084,4510,6085,4559,6086,4898,5969,6746,5623,5061,4919,5249,5250,5504, -5441,6265,5320,4878,3242,5862,5251,3428,6087,6747,4237,5624,5442,6266,5553,4539, -6748,2585,3533,5398,4262,6088,5150,4736,4438,6089,6267,5505,4966,6749,6268,6750, -6269,5288,5554,3650,6090,6091,4624,6092,5690,6751,5863,4270,5691,4277,5555,5864, -6752,5692,4720,4865,6470,5151,4688,4825,6753,3094,6754,6471,3235,4653,6755,5213, -5399,6756,3201,4589,5865,4967,6472,5866,6473,5019,3016,6757,5321,4756,3957,4573, -6093,4993,5767,4721,6474,6758,5625,6759,4458,6475,6270,6760,5556,4994,5214,5252, -6271,3875,5768,6094,5034,5506,4376,5769,6761,2120,6476,5253,5770,6762,5771,5970, -3990,5971,5557,5558,5772,6477,6095,2787,4641,5972,5121,6096,6097,6272,6763,3703, -5867,5507,6273,4206,6274,4789,6098,6764,3619,3646,3833,3804,2394,3788,4936,3978, -4866,4899,6099,6100,5559,6478,6765,3599,5868,6101,5869,5870,6275,6766,4527,6767) + 852,1221,1400,1486, 882,2299,4036, 351, 28,1122, 700,6479,6480,6481,6482,6483, #last 512 +) -# flake8: noqa diff --git a/venv/Lib/site-packages/requests/packages/chardet/gb2312prober.py b/venv/Lib/site-packages/chardet/gb2312prober.py similarity index 81% rename from venv/Lib/site-packages/requests/packages/chardet/gb2312prober.py rename to venv/Lib/site-packages/chardet/gb2312prober.py index 0325a2d86..8446d2dd9 100644 --- a/venv/Lib/site-packages/requests/packages/chardet/gb2312prober.py +++ b/venv/Lib/site-packages/chardet/gb2312prober.py @@ -13,12 +13,12 @@ # modify it under the terms of the GNU Lesser General Public # License as published by the Free Software Foundation; either # version 2.1 of the License, or (at your option) any later version. -# +# # This library 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 # Lesser General Public License for more details. -# +# # You should have received a copy of the GNU Lesser General Public # License along with this library; if not, write to the Free Software # Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA @@ -28,14 +28,19 @@ from .mbcharsetprober import MultiByteCharSetProber from .codingstatemachine import CodingStateMachine from .chardistribution import GB2312DistributionAnalysis -from .mbcssm import GB2312SMModel +from .mbcssm import GB2312_SM_MODEL class GB2312Prober(MultiByteCharSetProber): def __init__(self): - MultiByteCharSetProber.__init__(self) - self._mCodingSM = CodingStateMachine(GB2312SMModel) - self._mDistributionAnalyzer = GB2312DistributionAnalysis() + super(GB2312Prober, self).__init__() + self.coding_sm = CodingStateMachine(GB2312_SM_MODEL) + self.distribution_analyzer = GB2312DistributionAnalysis() self.reset() - def get_charset_name(self): + @property + def charset_name(self): return "GB2312" + + @property + def language(self): + return "Chinese" diff --git a/venv/Lib/site-packages/requests/packages/chardet/hebrewprober.py b/venv/Lib/site-packages/chardet/hebrewprober.py similarity index 76% rename from venv/Lib/site-packages/requests/packages/chardet/hebrewprober.py rename to venv/Lib/site-packages/chardet/hebrewprober.py index ba225c5ef..b0e1bf492 100644 --- a/venv/Lib/site-packages/requests/packages/chardet/hebrewprober.py +++ b/venv/Lib/site-packages/chardet/hebrewprober.py @@ -26,8 +26,7 @@ ######################### END LICENSE BLOCK ######################### from .charsetprober import CharSetProber -from .constants import eNotMe, eDetecting -from .compat import wrap_ord +from .enums import ProbingState # This prober doesn't actually recognize a language or a charset. # It is a helper prober for the use of the Hebrew model probers @@ -126,56 +125,59 @@ from .compat import wrap_ord # model probers scores. The answer is returned in the form of the name of the # charset identified, either "windows-1255" or "ISO-8859-8". -# windows-1255 / ISO-8859-8 code points of interest -FINAL_KAF = 0xea -NORMAL_KAF = 0xeb -FINAL_MEM = 0xed -NORMAL_MEM = 0xee -FINAL_NUN = 0xef -NORMAL_NUN = 0xf0 -FINAL_PE = 0xf3 -NORMAL_PE = 0xf4 -FINAL_TSADI = 0xf5 -NORMAL_TSADI = 0xf6 - -# Minimum Visual vs Logical final letter score difference. -# If the difference is below this, don't rely solely on the final letter score -# distance. -MIN_FINAL_CHAR_DISTANCE = 5 - -# Minimum Visual vs Logical model score difference. -# If the difference is below this, don't rely at all on the model score -# distance. -MIN_MODEL_DISTANCE = 0.01 - -VISUAL_HEBREW_NAME = "ISO-8859-8" -LOGICAL_HEBREW_NAME = "windows-1255" - - class HebrewProber(CharSetProber): + # windows-1255 / ISO-8859-8 code points of interest + FINAL_KAF = 0xea + NORMAL_KAF = 0xeb + FINAL_MEM = 0xed + NORMAL_MEM = 0xee + FINAL_NUN = 0xef + NORMAL_NUN = 0xf0 + FINAL_PE = 0xf3 + NORMAL_PE = 0xf4 + FINAL_TSADI = 0xf5 + NORMAL_TSADI = 0xf6 + + # Minimum Visual vs Logical final letter score difference. + # If the difference is below this, don't rely solely on the final letter score + # distance. + MIN_FINAL_CHAR_DISTANCE = 5 + + # Minimum Visual vs Logical model score difference. + # If the difference is below this, don't rely at all on the model score + # distance. + MIN_MODEL_DISTANCE = 0.01 + + VISUAL_HEBREW_NAME = "ISO-8859-8" + LOGICAL_HEBREW_NAME = "windows-1255" + def __init__(self): - CharSetProber.__init__(self) - self._mLogicalProber = None - self._mVisualProber = None + super(HebrewProber, self).__init__() + self._final_char_logical_score = None + self._final_char_visual_score = None + self._prev = None + self._before_prev = None + self._logical_prober = None + self._visual_prober = None self.reset() def reset(self): - self._mFinalCharLogicalScore = 0 - self._mFinalCharVisualScore = 0 + self._final_char_logical_score = 0 + self._final_char_visual_score = 0 # The two last characters seen in the previous buffer, # mPrev and mBeforePrev are initialized to space in order to simulate # a word delimiter at the beginning of the data - self._mPrev = ' ' - self._mBeforePrev = ' ' + self._prev = ' ' + self._before_prev = ' ' # These probers are owned by the group prober. def set_model_probers(self, logicalProber, visualProber): - self._mLogicalProber = logicalProber - self._mVisualProber = visualProber + self._logical_prober = logicalProber + self._visual_prober = visualProber def is_final(self, c): - return wrap_ord(c) in [FINAL_KAF, FINAL_MEM, FINAL_NUN, FINAL_PE, - FINAL_TSADI] + return c in [self.FINAL_KAF, self.FINAL_MEM, self.FINAL_NUN, + self.FINAL_PE, self.FINAL_TSADI] def is_non_final(self, c): # The normal Tsadi is not a good Non-Final letter due to words like @@ -188,9 +190,10 @@ class HebrewProber(CharSetProber): # for example legally end with a Non-Final Pe or Kaf. However, the # benefit of these letters as Non-Final letters outweighs the damage # since these words are quite rare. - return wrap_ord(c) in [NORMAL_KAF, NORMAL_MEM, NORMAL_NUN, NORMAL_PE] + return c in [self.NORMAL_KAF, self.NORMAL_MEM, + self.NORMAL_NUN, self.NORMAL_PE] - def feed(self, aBuf): + def feed(self, byte_str): # Final letter analysis for logical-visual decision. # Look for evidence that the received buffer is either logical Hebrew # or visual Hebrew. @@ -217,67 +220,73 @@ class HebrewProber(CharSetProber): # We automatically filter out all 7-bit characters (replace them with # spaces) so the word boundary detection works properly. [MAP] - if self.get_state() == eNotMe: + if self.state == ProbingState.NOT_ME: # Both model probers say it's not them. No reason to continue. - return eNotMe + return ProbingState.NOT_ME - aBuf = self.filter_high_bit_only(aBuf) + byte_str = self.filter_high_byte_only(byte_str) - for cur in aBuf: + for cur in byte_str: if cur == ' ': # We stand on a space - a word just ended - if self._mBeforePrev != ' ': - # next-to-last char was not a space so self._mPrev is not a + if self._before_prev != ' ': + # next-to-last char was not a space so self._prev is not a # 1 letter word - if self.is_final(self._mPrev): + if self.is_final(self._prev): # case (1) [-2:not space][-1:final letter][cur:space] - self._mFinalCharLogicalScore += 1 - elif self.is_non_final(self._mPrev): + self._final_char_logical_score += 1 + elif self.is_non_final(self._prev): # case (2) [-2:not space][-1:Non-Final letter][ # cur:space] - self._mFinalCharVisualScore += 1 + self._final_char_visual_score += 1 else: # Not standing on a space - if ((self._mBeforePrev == ' ') and - (self.is_final(self._mPrev)) and (cur != ' ')): + if ((self._before_prev == ' ') and + (self.is_final(self._prev)) and (cur != ' ')): # case (3) [-2:space][-1:final letter][cur:not space] - self._mFinalCharVisualScore += 1 - self._mBeforePrev = self._mPrev - self._mPrev = cur + self._final_char_visual_score += 1 + self._before_prev = self._prev + self._prev = cur # Forever detecting, till the end or until both model probers return - # eNotMe (handled above) - return eDetecting + # ProbingState.NOT_ME (handled above) + return ProbingState.DETECTING - def get_charset_name(self): + @property + def charset_name(self): # Make the decision: is it Logical or Visual? # If the final letter score distance is dominant enough, rely on it. - finalsub = self._mFinalCharLogicalScore - self._mFinalCharVisualScore - if finalsub >= MIN_FINAL_CHAR_DISTANCE: - return LOGICAL_HEBREW_NAME - if finalsub <= -MIN_FINAL_CHAR_DISTANCE: - return VISUAL_HEBREW_NAME + finalsub = self._final_char_logical_score - self._final_char_visual_score + if finalsub >= self.MIN_FINAL_CHAR_DISTANCE: + return self.LOGICAL_HEBREW_NAME + if finalsub <= -self.MIN_FINAL_CHAR_DISTANCE: + return self.VISUAL_HEBREW_NAME # It's not dominant enough, try to rely on the model scores instead. - modelsub = (self._mLogicalProber.get_confidence() - - self._mVisualProber.get_confidence()) - if modelsub > MIN_MODEL_DISTANCE: - return LOGICAL_HEBREW_NAME - if modelsub < -MIN_MODEL_DISTANCE: - return VISUAL_HEBREW_NAME + modelsub = (self._logical_prober.get_confidence() + - self._visual_prober.get_confidence()) + if modelsub > self.MIN_MODEL_DISTANCE: + return self.LOGICAL_HEBREW_NAME + if modelsub < -self.MIN_MODEL_DISTANCE: + return self.VISUAL_HEBREW_NAME # Still no good, back to final letter distance, maybe it'll save the # day. if finalsub < 0.0: - return VISUAL_HEBREW_NAME + return self.VISUAL_HEBREW_NAME # (finalsub > 0 - Logical) or (don't know what to do) default to # Logical. - return LOGICAL_HEBREW_NAME + return self.LOGICAL_HEBREW_NAME - def get_state(self): + @property + def language(self): + return 'Hebrew' + + @property + def state(self): # Remain active as long as any of the model probers are active. - if (self._mLogicalProber.get_state() == eNotMe) and \ - (self._mVisualProber.get_state() == eNotMe): - return eNotMe - return eDetecting + if (self._logical_prober.state == ProbingState.NOT_ME) and \ + (self._visual_prober.state == ProbingState.NOT_ME): + return ProbingState.NOT_ME + return ProbingState.DETECTING diff --git a/venv/Lib/site-packages/requests/packages/chardet/jisfreq.py b/venv/Lib/site-packages/chardet/jisfreq.py similarity index 54% rename from venv/Lib/site-packages/requests/packages/chardet/jisfreq.py rename to venv/Lib/site-packages/chardet/jisfreq.py index 064345b08..83fc082b5 100644 --- a/venv/Lib/site-packages/requests/packages/chardet/jisfreq.py +++ b/venv/Lib/site-packages/chardet/jisfreq.py @@ -46,7 +46,7 @@ JIS_TYPICAL_DISTRIBUTION_RATIO = 3.0 # Char to FreqOrder table , JIS_TABLE_SIZE = 4368 -JISCharToFreqOrder = ( +JIS_CHAR_TO_FREQ_ORDER = ( 40, 1, 6, 182, 152, 180, 295,2127, 285, 381,3295,4304,3068,4606,3165,3510, # 16 3511,1822,2785,4607,1193,2226,5070,4608, 171,2996,1247, 18, 179,5071, 856,1661, # 32 1262,5072, 619, 127,3431,3512,3230,1899,1700, 232, 228,1294,1298, 284, 283,2041, # 48 @@ -320,250 +320,6 @@ JISCharToFreqOrder = ( 2413,2477,1216,2725,2159, 334,3840,1328,3624,2921,1525,4132, 564,1056, 891,4363, # 4336 1444,1698,2385,2251,3729,1365,2281,2235,1717,6188, 864,3841,2515, 444, 527,2767, # 4352 2922,3625, 544, 461,6189, 566, 209,2437,3398,2098,1065,2068,3331,3626,3257,2137, # 4368 #last 512 -#Everything below is of no interest for detection purpose -2138,2122,3730,2888,1995,1820,1044,6190,6191,6192,6193,6194,6195,6196,6197,6198, # 4384 -6199,6200,6201,6202,6203,6204,6205,4670,6206,6207,6208,6209,6210,6211,6212,6213, # 4400 -6214,6215,6216,6217,6218,6219,6220,6221,6222,6223,6224,6225,6226,6227,6228,6229, # 4416 -6230,6231,6232,6233,6234,6235,6236,6237,3187,6238,6239,3969,6240,6241,6242,6243, # 4432 -6244,4671,6245,6246,4672,6247,6248,4133,6249,6250,4364,6251,2923,2556,2613,4673, # 4448 -4365,3970,6252,6253,6254,6255,4674,6256,6257,6258,2768,2353,4366,4675,4676,3188, # 4464 -4367,3463,6259,4134,4677,4678,6260,2267,6261,3842,3332,4368,3543,6262,6263,6264, # 4480 -3013,1954,1928,4135,4679,6265,6266,2478,3091,6267,4680,4369,6268,6269,1699,6270, # 4496 -3544,4136,4681,6271,4137,6272,4370,2804,6273,6274,2593,3971,3972,4682,6275,2236, # 4512 -4683,6276,6277,4684,6278,6279,4138,3973,4685,6280,6281,3258,6282,6283,6284,6285, # 4528 -3974,4686,2841,3975,6286,6287,3545,6288,6289,4139,4687,4140,6290,4141,6291,4142, # 4544 -6292,6293,3333,6294,6295,6296,4371,6297,3399,6298,6299,4372,3976,6300,6301,6302, # 4560 -4373,6303,6304,3843,3731,6305,4688,4374,6306,6307,3259,2294,6308,3732,2530,4143, # 4576 -6309,4689,6310,6311,6312,3048,6313,6314,4690,3733,2237,6315,6316,2282,3334,6317, # 4592 -6318,3844,6319,6320,4691,6321,3400,4692,6322,4693,6323,3049,6324,4375,6325,3977, # 4608 -6326,6327,6328,3546,6329,4694,3335,6330,4695,4696,6331,6332,6333,6334,4376,3978, # 4624 -6335,4697,3979,4144,6336,3980,4698,6337,6338,6339,6340,6341,4699,4700,4701,6342, # 4640 -6343,4702,6344,6345,4703,6346,6347,4704,6348,4705,4706,3135,6349,4707,6350,4708, # 4656 -6351,4377,6352,4709,3734,4145,6353,2506,4710,3189,6354,3050,4711,3981,6355,3547, # 4672 -3014,4146,4378,3735,2651,3845,3260,3136,2224,1986,6356,3401,6357,4712,2594,3627, # 4688 -3137,2573,3736,3982,4713,3628,4714,4715,2682,3629,4716,6358,3630,4379,3631,6359, # 4704 -6360,6361,3983,6362,6363,6364,6365,4147,3846,4717,6366,6367,3737,2842,6368,4718, # 4720 -2628,6369,3261,6370,2386,6371,6372,3738,3984,4719,3464,4720,3402,6373,2924,3336, # 4736 -4148,2866,6374,2805,3262,4380,2704,2069,2531,3138,2806,2984,6375,2769,6376,4721, # 4752 -4722,3403,6377,6378,3548,6379,6380,2705,3092,1979,4149,2629,3337,2889,6381,3338, # 4768 -4150,2557,3339,4381,6382,3190,3263,3739,6383,4151,4723,4152,2558,2574,3404,3191, # 4784 -6384,6385,4153,6386,4724,4382,6387,6388,4383,6389,6390,4154,6391,4725,3985,6392, # 4800 -3847,4155,6393,6394,6395,6396,6397,3465,6398,4384,6399,6400,6401,6402,6403,6404, # 4816 -4156,6405,6406,6407,6408,2123,6409,6410,2326,3192,4726,6411,6412,6413,6414,4385, # 4832 -4157,6415,6416,4158,6417,3093,3848,6418,3986,6419,6420,3849,6421,6422,6423,4159, # 4848 -6424,6425,4160,6426,3740,6427,6428,6429,6430,3987,6431,4727,6432,2238,6433,6434, # 4864 -4386,3988,6435,6436,3632,6437,6438,2843,6439,6440,6441,6442,3633,6443,2958,6444, # 4880 -6445,3466,6446,2364,4387,3850,6447,4388,2959,3340,6448,3851,6449,4728,6450,6451, # 4896 -3264,4729,6452,3193,6453,4389,4390,2706,3341,4730,6454,3139,6455,3194,6456,3051, # 4912 -2124,3852,1602,4391,4161,3853,1158,3854,4162,3989,4392,3990,4731,4732,4393,2040, # 4928 -4163,4394,3265,6457,2807,3467,3855,6458,6459,6460,3991,3468,4733,4734,6461,3140, # 4944 -2960,6462,4735,6463,6464,6465,6466,4736,4737,4738,4739,6467,6468,4164,2403,3856, # 4960 -6469,6470,2770,2844,6471,4740,6472,6473,6474,6475,6476,6477,6478,3195,6479,4741, # 4976 -4395,6480,2867,6481,4742,2808,6482,2493,4165,6483,6484,6485,6486,2295,4743,6487, # 4992 -6488,6489,3634,6490,6491,6492,6493,6494,6495,6496,2985,4744,6497,6498,4745,6499, # 5008 -6500,2925,3141,4166,6501,6502,4746,6503,6504,4747,6505,6506,6507,2890,6508,6509, # 5024 -6510,6511,6512,6513,6514,6515,6516,6517,6518,6519,3469,4167,6520,6521,6522,4748, # 5040 -4396,3741,4397,4749,4398,3342,2125,4750,6523,4751,4752,4753,3052,6524,2961,4168, # 5056 -6525,4754,6526,4755,4399,2926,4169,6527,3857,6528,4400,4170,6529,4171,6530,6531, # 5072 -2595,6532,6533,6534,6535,3635,6536,6537,6538,6539,6540,6541,6542,4756,6543,6544, # 5088 -6545,6546,6547,6548,4401,6549,6550,6551,6552,4402,3405,4757,4403,6553,6554,6555, # 5104 -4172,3742,6556,6557,6558,3992,3636,6559,6560,3053,2726,6561,3549,4173,3054,4404, # 5120 -6562,6563,3993,4405,3266,3550,2809,4406,6564,6565,6566,4758,4759,6567,3743,6568, # 5136 -4760,3744,4761,3470,6569,6570,6571,4407,6572,3745,4174,6573,4175,2810,4176,3196, # 5152 -4762,6574,4177,6575,6576,2494,2891,3551,6577,6578,3471,6579,4408,6580,3015,3197, # 5168 -6581,3343,2532,3994,3858,6582,3094,3406,4409,6583,2892,4178,4763,4410,3016,4411, # 5184 -6584,3995,3142,3017,2683,6585,4179,6586,6587,4764,4412,6588,6589,4413,6590,2986, # 5200 -6591,2962,3552,6592,2963,3472,6593,6594,4180,4765,6595,6596,2225,3267,4414,6597, # 5216 -3407,3637,4766,6598,6599,3198,6600,4415,6601,3859,3199,6602,3473,4767,2811,4416, # 5232 -1856,3268,3200,2575,3996,3997,3201,4417,6603,3095,2927,6604,3143,6605,2268,6606, # 5248 -3998,3860,3096,2771,6607,6608,3638,2495,4768,6609,3861,6610,3269,2745,4769,4181, # 5264 -3553,6611,2845,3270,6612,6613,6614,3862,6615,6616,4770,4771,6617,3474,3999,4418, # 5280 -4419,6618,3639,3344,6619,4772,4182,6620,2126,6621,6622,6623,4420,4773,6624,3018, # 5296 -6625,4774,3554,6626,4183,2025,3746,6627,4184,2707,6628,4421,4422,3097,1775,4185, # 5312 -3555,6629,6630,2868,6631,6632,4423,6633,6634,4424,2414,2533,2928,6635,4186,2387, # 5328 -6636,4775,6637,4187,6638,1891,4425,3202,3203,6639,6640,4776,6641,3345,6642,6643, # 5344 -3640,6644,3475,3346,3641,4000,6645,3144,6646,3098,2812,4188,3642,3204,6647,3863, # 5360 -3476,6648,3864,6649,4426,4001,6650,6651,6652,2576,6653,4189,4777,6654,6655,6656, # 5376 -2846,6657,3477,3205,4002,6658,4003,6659,3347,2252,6660,6661,6662,4778,6663,6664, # 5392 -6665,6666,6667,6668,6669,4779,4780,2048,6670,3478,3099,6671,3556,3747,4004,6672, # 5408 -6673,6674,3145,4005,3748,6675,6676,6677,6678,6679,3408,6680,6681,6682,6683,3206, # 5424 -3207,6684,6685,4781,4427,6686,4782,4783,4784,6687,6688,6689,4190,6690,6691,3479, # 5440 -6692,2746,6693,4428,6694,6695,6696,6697,6698,6699,4785,6700,6701,3208,2727,6702, # 5456 -3146,6703,6704,3409,2196,6705,4429,6706,6707,6708,2534,1996,6709,6710,6711,2747, # 5472 -6712,6713,6714,4786,3643,6715,4430,4431,6716,3557,6717,4432,4433,6718,6719,6720, # 5488 -6721,3749,6722,4006,4787,6723,6724,3644,4788,4434,6725,6726,4789,2772,6727,6728, # 5504 -6729,6730,6731,2708,3865,2813,4435,6732,6733,4790,4791,3480,6734,6735,6736,6737, # 5520 -4436,3348,6738,3410,4007,6739,6740,4008,6741,6742,4792,3411,4191,6743,6744,6745, # 5536 -6746,6747,3866,6748,3750,6749,6750,6751,6752,6753,6754,6755,3867,6756,4009,6757, # 5552 -4793,4794,6758,2814,2987,6759,6760,6761,4437,6762,6763,6764,6765,3645,6766,6767, # 5568 -3481,4192,6768,3751,6769,6770,2174,6771,3868,3752,6772,6773,6774,4193,4795,4438, # 5584 -3558,4796,4439,6775,4797,6776,6777,4798,6778,4799,3559,4800,6779,6780,6781,3482, # 5600 -6782,2893,6783,6784,4194,4801,4010,6785,6786,4440,6787,4011,6788,6789,6790,6791, # 5616 -6792,6793,4802,6794,6795,6796,4012,6797,6798,6799,6800,3349,4803,3483,6801,4804, # 5632 -4195,6802,4013,6803,6804,4196,6805,4014,4015,6806,2847,3271,2848,6807,3484,6808, # 5648 -6809,6810,4441,6811,4442,4197,4443,3272,4805,6812,3412,4016,1579,6813,6814,4017, # 5664 -6815,3869,6816,2964,6817,4806,6818,6819,4018,3646,6820,6821,4807,4019,4020,6822, # 5680 -6823,3560,6824,6825,4021,4444,6826,4198,6827,6828,4445,6829,6830,4199,4808,6831, # 5696 -6832,6833,3870,3019,2458,6834,3753,3413,3350,6835,4809,3871,4810,3561,4446,6836, # 5712 -6837,4447,4811,4812,6838,2459,4448,6839,4449,6840,6841,4022,3872,6842,4813,4814, # 5728 -6843,6844,4815,4200,4201,4202,6845,4023,6846,6847,4450,3562,3873,6848,6849,4816, # 5744 -4817,6850,4451,4818,2139,6851,3563,6852,6853,3351,6854,6855,3352,4024,2709,3414, # 5760 -4203,4452,6856,4204,6857,6858,3874,3875,6859,6860,4819,6861,6862,6863,6864,4453, # 5776 -3647,6865,6866,4820,6867,6868,6869,6870,4454,6871,2869,6872,6873,4821,6874,3754, # 5792 -6875,4822,4205,6876,6877,6878,3648,4206,4455,6879,4823,6880,4824,3876,6881,3055, # 5808 -4207,6882,3415,6883,6884,6885,4208,4209,6886,4210,3353,6887,3354,3564,3209,3485, # 5824 -2652,6888,2728,6889,3210,3755,6890,4025,4456,6891,4825,6892,6893,6894,6895,4211, # 5840 -6896,6897,6898,4826,6899,6900,4212,6901,4827,6902,2773,3565,6903,4828,6904,6905, # 5856 -6906,6907,3649,3650,6908,2849,3566,6909,3567,3100,6910,6911,6912,6913,6914,6915, # 5872 -4026,6916,3355,4829,3056,4457,3756,6917,3651,6918,4213,3652,2870,6919,4458,6920, # 5888 -2438,6921,6922,3757,2774,4830,6923,3356,4831,4832,6924,4833,4459,3653,2507,6925, # 5904 -4834,2535,6926,6927,3273,4027,3147,6928,3568,6929,6930,6931,4460,6932,3877,4461, # 5920 -2729,3654,6933,6934,6935,6936,2175,4835,2630,4214,4028,4462,4836,4215,6937,3148, # 5936 -4216,4463,4837,4838,4217,6938,6939,2850,4839,6940,4464,6941,6942,6943,4840,6944, # 5952 -4218,3274,4465,6945,6946,2710,6947,4841,4466,6948,6949,2894,6950,6951,4842,6952, # 5968 -4219,3057,2871,6953,6954,6955,6956,4467,6957,2711,6958,6959,6960,3275,3101,4843, # 5984 -6961,3357,3569,6962,4844,6963,6964,4468,4845,3570,6965,3102,4846,3758,6966,4847, # 6000 -3878,4848,4849,4029,6967,2929,3879,4850,4851,6968,6969,1733,6970,4220,6971,6972, # 6016 -6973,6974,6975,6976,4852,6977,6978,6979,6980,6981,6982,3759,6983,6984,6985,3486, # 6032 -3487,6986,3488,3416,6987,6988,6989,6990,6991,6992,6993,6994,6995,6996,6997,4853, # 6048 -6998,6999,4030,7000,7001,3211,7002,7003,4221,7004,7005,3571,4031,7006,3572,7007, # 6064 -2614,4854,2577,7008,7009,2965,3655,3656,4855,2775,3489,3880,4222,4856,3881,4032, # 6080 -3882,3657,2730,3490,4857,7010,3149,7011,4469,4858,2496,3491,4859,2283,7012,7013, # 6096 -7014,2365,4860,4470,7015,7016,3760,7017,7018,4223,1917,7019,7020,7021,4471,7022, # 6112 -2776,4472,7023,7024,7025,7026,4033,7027,3573,4224,4861,4034,4862,7028,7029,1929, # 6128 -3883,4035,7030,4473,3058,7031,2536,3761,3884,7032,4036,7033,2966,2895,1968,4474, # 6144 -3276,4225,3417,3492,4226,2105,7034,7035,1754,2596,3762,4227,4863,4475,3763,4864, # 6160 -3764,2615,2777,3103,3765,3658,3418,4865,2296,3766,2815,7036,7037,7038,3574,2872, # 6176 -3277,4476,7039,4037,4477,7040,7041,4038,7042,7043,7044,7045,7046,7047,2537,7048, # 6192 -7049,7050,7051,7052,7053,7054,4478,7055,7056,3767,3659,4228,3575,7057,7058,4229, # 6208 -7059,7060,7061,3660,7062,3212,7063,3885,4039,2460,7064,7065,7066,7067,7068,7069, # 6224 -7070,7071,7072,7073,7074,4866,3768,4867,7075,7076,7077,7078,4868,3358,3278,2653, # 6240 -7079,7080,4479,3886,7081,7082,4869,7083,7084,7085,7086,7087,7088,2538,7089,7090, # 6256 -7091,4040,3150,3769,4870,4041,2896,3359,4230,2930,7092,3279,7093,2967,4480,3213, # 6272 -4481,3661,7094,7095,7096,7097,7098,7099,7100,7101,7102,2461,3770,7103,7104,4231, # 6288 -3151,7105,7106,7107,4042,3662,7108,7109,4871,3663,4872,4043,3059,7110,7111,7112, # 6304 -3493,2988,7113,4873,7114,7115,7116,3771,4874,7117,7118,4232,4875,7119,3576,2336, # 6320 -4876,7120,4233,3419,4044,4877,4878,4482,4483,4879,4484,4234,7121,3772,4880,1045, # 6336 -3280,3664,4881,4882,7122,7123,7124,7125,4883,7126,2778,7127,4485,4486,7128,4884, # 6352 -3214,3887,7129,7130,3215,7131,4885,4045,7132,7133,4046,7134,7135,7136,7137,7138, # 6368 -7139,7140,7141,7142,7143,4235,7144,4886,7145,7146,7147,4887,7148,7149,7150,4487, # 6384 -4047,4488,7151,7152,4888,4048,2989,3888,7153,3665,7154,4049,7155,7156,7157,7158, # 6400 -7159,7160,2931,4889,4890,4489,7161,2631,3889,4236,2779,7162,7163,4891,7164,3060, # 6416 -7165,1672,4892,7166,4893,4237,3281,4894,7167,7168,3666,7169,3494,7170,7171,4050, # 6432 -7172,7173,3104,3360,3420,4490,4051,2684,4052,7174,4053,7175,7176,7177,2253,4054, # 6448 -7178,7179,4895,7180,3152,3890,3153,4491,3216,7181,7182,7183,2968,4238,4492,4055, # 6464 -7184,2990,7185,2479,7186,7187,4493,7188,7189,7190,7191,7192,4896,7193,4897,2969, # 6480 -4494,4898,7194,3495,7195,7196,4899,4495,7197,3105,2731,7198,4900,7199,7200,7201, # 6496 -4056,7202,3361,7203,7204,4496,4901,4902,7205,4497,7206,7207,2315,4903,7208,4904, # 6512 -7209,4905,2851,7210,7211,3577,7212,3578,4906,7213,4057,3667,4907,7214,4058,2354, # 6528 -3891,2376,3217,3773,7215,7216,7217,7218,7219,4498,7220,4908,3282,2685,7221,3496, # 6544 -4909,2632,3154,4910,7222,2337,7223,4911,7224,7225,7226,4912,4913,3283,4239,4499, # 6560 -7227,2816,7228,7229,7230,7231,7232,7233,7234,4914,4500,4501,7235,7236,7237,2686, # 6576 -7238,4915,7239,2897,4502,7240,4503,7241,2516,7242,4504,3362,3218,7243,7244,7245, # 6592 -4916,7246,7247,4505,3363,7248,7249,7250,7251,3774,4506,7252,7253,4917,7254,7255, # 6608 -3284,2991,4918,4919,3219,3892,4920,3106,3497,4921,7256,7257,7258,4922,7259,4923, # 6624 -3364,4507,4508,4059,7260,4240,3498,7261,7262,4924,7263,2992,3893,4060,3220,7264, # 6640 -7265,7266,7267,7268,7269,4509,3775,7270,2817,7271,4061,4925,4510,3776,7272,4241, # 6656 -4511,3285,7273,7274,3499,7275,7276,7277,4062,4512,4926,7278,3107,3894,7279,7280, # 6672 -4927,7281,4513,7282,7283,3668,7284,7285,4242,4514,4243,7286,2058,4515,4928,4929, # 6688 -4516,7287,3286,4244,7288,4517,7289,7290,7291,3669,7292,7293,4930,4931,4932,2355, # 6704 -4933,7294,2633,4518,7295,4245,7296,7297,4519,7298,7299,4520,4521,4934,7300,4246, # 6720 -4522,7301,7302,7303,3579,7304,4247,4935,7305,4936,7306,7307,7308,7309,3777,7310, # 6736 -4523,7311,7312,7313,4248,3580,7314,4524,3778,4249,7315,3581,7316,3287,7317,3221, # 6752 -7318,4937,7319,7320,7321,7322,7323,7324,4938,4939,7325,4525,7326,7327,7328,4063, # 6768 -7329,7330,4940,7331,7332,4941,7333,4526,7334,3500,2780,1741,4942,2026,1742,7335, # 6784 -7336,3582,4527,2388,7337,7338,7339,4528,7340,4250,4943,7341,7342,7343,4944,7344, # 6800 -7345,7346,3020,7347,4945,7348,7349,7350,7351,3895,7352,3896,4064,3897,7353,7354, # 6816 -7355,4251,7356,7357,3898,7358,3779,7359,3780,3288,7360,7361,4529,7362,4946,4530, # 6832 -2027,7363,3899,4531,4947,3222,3583,7364,4948,7365,7366,7367,7368,4949,3501,4950, # 6848 -3781,4951,4532,7369,2517,4952,4252,4953,3155,7370,4954,4955,4253,2518,4533,7371, # 6864 -7372,2712,4254,7373,7374,7375,3670,4956,3671,7376,2389,3502,4065,7377,2338,7378, # 6880 -7379,7380,7381,3061,7382,4957,7383,7384,7385,7386,4958,4534,7387,7388,2993,7389, # 6896 -3062,7390,4959,7391,7392,7393,4960,3108,4961,7394,4535,7395,4962,3421,4536,7396, # 6912 -4963,7397,4964,1857,7398,4965,7399,7400,2176,3584,4966,7401,7402,3422,4537,3900, # 6928 -3585,7403,3782,7404,2852,7405,7406,7407,4538,3783,2654,3423,4967,4539,7408,3784, # 6944 -3586,2853,4540,4541,7409,3901,7410,3902,7411,7412,3785,3109,2327,3903,7413,7414, # 6960 -2970,4066,2932,7415,7416,7417,3904,3672,3424,7418,4542,4543,4544,7419,4968,7420, # 6976 -7421,4255,7422,7423,7424,7425,7426,4067,7427,3673,3365,4545,7428,3110,2559,3674, # 6992 -7429,7430,3156,7431,7432,3503,7433,3425,4546,7434,3063,2873,7435,3223,4969,4547, # 7008 -4548,2898,4256,4068,7436,4069,3587,3786,2933,3787,4257,4970,4971,3788,7437,4972, # 7024 -3064,7438,4549,7439,7440,7441,7442,7443,4973,3905,7444,2874,7445,7446,7447,7448, # 7040 -3021,7449,4550,3906,3588,4974,7450,7451,3789,3675,7452,2578,7453,4070,7454,7455, # 7056 -7456,4258,3676,7457,4975,7458,4976,4259,3790,3504,2634,4977,3677,4551,4260,7459, # 7072 -7460,7461,7462,3907,4261,4978,7463,7464,7465,7466,4979,4980,7467,7468,2213,4262, # 7088 -7469,7470,7471,3678,4981,7472,2439,7473,4263,3224,3289,7474,3908,2415,4982,7475, # 7104 -4264,7476,4983,2655,7477,7478,2732,4552,2854,2875,7479,7480,4265,7481,4553,4984, # 7120 -7482,7483,4266,7484,3679,3366,3680,2818,2781,2782,3367,3589,4554,3065,7485,4071, # 7136 -2899,7486,7487,3157,2462,4072,4555,4073,4985,4986,3111,4267,2687,3368,4556,4074, # 7152 -3791,4268,7488,3909,2783,7489,2656,1962,3158,4557,4987,1963,3159,3160,7490,3112, # 7168 -4988,4989,3022,4990,4991,3792,2855,7491,7492,2971,4558,7493,7494,4992,7495,7496, # 7184 -7497,7498,4993,7499,3426,4559,4994,7500,3681,4560,4269,4270,3910,7501,4075,4995, # 7200 -4271,7502,7503,4076,7504,4996,7505,3225,4997,4272,4077,2819,3023,7506,7507,2733, # 7216 -4561,7508,4562,7509,3369,3793,7510,3590,2508,7511,7512,4273,3113,2994,2616,7513, # 7232 -7514,7515,7516,7517,7518,2820,3911,4078,2748,7519,7520,4563,4998,7521,7522,7523, # 7248 -7524,4999,4274,7525,4564,3682,2239,4079,4565,7526,7527,7528,7529,5000,7530,7531, # 7264 -5001,4275,3794,7532,7533,7534,3066,5002,4566,3161,7535,7536,4080,7537,3162,7538, # 7280 -7539,4567,7540,7541,7542,7543,7544,7545,5003,7546,4568,7547,7548,7549,7550,7551, # 7296 -7552,7553,7554,7555,7556,5004,7557,7558,7559,5005,7560,3795,7561,4569,7562,7563, # 7312 -7564,2821,3796,4276,4277,4081,7565,2876,7566,5006,7567,7568,2900,7569,3797,3912, # 7328 -7570,7571,7572,4278,7573,7574,7575,5007,7576,7577,5008,7578,7579,4279,2934,7580, # 7344 -7581,5009,7582,4570,7583,4280,7584,7585,7586,4571,4572,3913,7587,4573,3505,7588, # 7360 -5010,7589,7590,7591,7592,3798,4574,7593,7594,5011,7595,4281,7596,7597,7598,4282, # 7376 -5012,7599,7600,5013,3163,7601,5014,7602,3914,7603,7604,2734,4575,4576,4577,7605, # 7392 -7606,7607,7608,7609,3506,5015,4578,7610,4082,7611,2822,2901,2579,3683,3024,4579, # 7408 -3507,7612,4580,7613,3226,3799,5016,7614,7615,7616,7617,7618,7619,7620,2995,3290, # 7424 -7621,4083,7622,5017,7623,7624,7625,7626,7627,4581,3915,7628,3291,7629,5018,7630, # 7440 -7631,7632,7633,4084,7634,7635,3427,3800,7636,7637,4582,7638,5019,4583,5020,7639, # 7456 -3916,7640,3801,5021,4584,4283,7641,7642,3428,3591,2269,7643,2617,7644,4585,3592, # 7472 -7645,4586,2902,7646,7647,3227,5022,7648,4587,7649,4284,7650,7651,7652,4588,2284, # 7488 -7653,5023,7654,7655,7656,4589,5024,3802,7657,7658,5025,3508,4590,7659,7660,7661, # 7504 -1969,5026,7662,7663,3684,1821,2688,7664,2028,2509,4285,7665,2823,1841,7666,2689, # 7520 -3114,7667,3917,4085,2160,5027,5028,2972,7668,5029,7669,7670,7671,3593,4086,7672, # 7536 -4591,4087,5030,3803,7673,7674,7675,7676,7677,7678,7679,4286,2366,4592,4593,3067, # 7552 -2328,7680,7681,4594,3594,3918,2029,4287,7682,5031,3919,3370,4288,4595,2856,7683, # 7568 -3509,7684,7685,5032,5033,7686,7687,3804,2784,7688,7689,7690,7691,3371,7692,7693, # 7584 -2877,5034,7694,7695,3920,4289,4088,7696,7697,7698,5035,7699,5036,4290,5037,5038, # 7600 -5039,7700,7701,7702,5040,5041,3228,7703,1760,7704,5042,3229,4596,2106,4089,7705, # 7616 -4597,2824,5043,2107,3372,7706,4291,4090,5044,7707,4091,7708,5045,3025,3805,4598, # 7632 -4292,4293,4294,3373,7709,4599,7710,5046,7711,7712,5047,5048,3806,7713,7714,7715, # 7648 -5049,7716,7717,7718,7719,4600,5050,7720,7721,7722,5051,7723,4295,3429,7724,7725, # 7664 -7726,7727,3921,7728,3292,5052,4092,7729,7730,7731,7732,7733,7734,7735,5053,5054, # 7680 -7736,7737,7738,7739,3922,3685,7740,7741,7742,7743,2635,5055,7744,5056,4601,7745, # 7696 -7746,2560,7747,7748,7749,7750,3923,7751,7752,7753,7754,7755,4296,2903,7756,7757, # 7712 -7758,7759,7760,3924,7761,5057,4297,7762,7763,5058,4298,7764,4093,7765,7766,5059, # 7728 -3925,7767,7768,7769,7770,7771,7772,7773,7774,7775,7776,3595,7777,4299,5060,4094, # 7744 -7778,3293,5061,7779,7780,4300,7781,7782,4602,7783,3596,7784,7785,3430,2367,7786, # 7760 -3164,5062,5063,4301,7787,7788,4095,5064,5065,7789,3374,3115,7790,7791,7792,7793, # 7776 -7794,7795,7796,3597,4603,7797,7798,3686,3116,3807,5066,7799,7800,5067,7801,7802, # 7792 -4604,4302,5068,4303,4096,7803,7804,3294,7805,7806,5069,4605,2690,7807,3026,7808, # 7808 -7809,7810,7811,7812,7813,7814,7815,7816,7817,7818,7819,7820,7821,7822,7823,7824, # 7824 -7825,7826,7827,7828,7829,7830,7831,7832,7833,7834,7835,7836,7837,7838,7839,7840, # 7840 -7841,7842,7843,7844,7845,7846,7847,7848,7849,7850,7851,7852,7853,7854,7855,7856, # 7856 -7857,7858,7859,7860,7861,7862,7863,7864,7865,7866,7867,7868,7869,7870,7871,7872, # 7872 -7873,7874,7875,7876,7877,7878,7879,7880,7881,7882,7883,7884,7885,7886,7887,7888, # 7888 -7889,7890,7891,7892,7893,7894,7895,7896,7897,7898,7899,7900,7901,7902,7903,7904, # 7904 -7905,7906,7907,7908,7909,7910,7911,7912,7913,7914,7915,7916,7917,7918,7919,7920, # 7920 -7921,7922,7923,7924,3926,7925,7926,7927,7928,7929,7930,7931,7932,7933,7934,7935, # 7936 -7936,7937,7938,7939,7940,7941,7942,7943,7944,7945,7946,7947,7948,7949,7950,7951, # 7952 -7952,7953,7954,7955,7956,7957,7958,7959,7960,7961,7962,7963,7964,7965,7966,7967, # 7968 -7968,7969,7970,7971,7972,7973,7974,7975,7976,7977,7978,7979,7980,7981,7982,7983, # 7984 -7984,7985,7986,7987,7988,7989,7990,7991,7992,7993,7994,7995,7996,7997,7998,7999, # 8000 -8000,8001,8002,8003,8004,8005,8006,8007,8008,8009,8010,8011,8012,8013,8014,8015, # 8016 -8016,8017,8018,8019,8020,8021,8022,8023,8024,8025,8026,8027,8028,8029,8030,8031, # 8032 -8032,8033,8034,8035,8036,8037,8038,8039,8040,8041,8042,8043,8044,8045,8046,8047, # 8048 -8048,8049,8050,8051,8052,8053,8054,8055,8056,8057,8058,8059,8060,8061,8062,8063, # 8064 -8064,8065,8066,8067,8068,8069,8070,8071,8072,8073,8074,8075,8076,8077,8078,8079, # 8080 -8080,8081,8082,8083,8084,8085,8086,8087,8088,8089,8090,8091,8092,8093,8094,8095, # 8096 -8096,8097,8098,8099,8100,8101,8102,8103,8104,8105,8106,8107,8108,8109,8110,8111, # 8112 -8112,8113,8114,8115,8116,8117,8118,8119,8120,8121,8122,8123,8124,8125,8126,8127, # 8128 -8128,8129,8130,8131,8132,8133,8134,8135,8136,8137,8138,8139,8140,8141,8142,8143, # 8144 -8144,8145,8146,8147,8148,8149,8150,8151,8152,8153,8154,8155,8156,8157,8158,8159, # 8160 -8160,8161,8162,8163,8164,8165,8166,8167,8168,8169,8170,8171,8172,8173,8174,8175, # 8176 -8176,8177,8178,8179,8180,8181,8182,8183,8184,8185,8186,8187,8188,8189,8190,8191, # 8192 -8192,8193,8194,8195,8196,8197,8198,8199,8200,8201,8202,8203,8204,8205,8206,8207, # 8208 -8208,8209,8210,8211,8212,8213,8214,8215,8216,8217,8218,8219,8220,8221,8222,8223, # 8224 -8224,8225,8226,8227,8228,8229,8230,8231,8232,8233,8234,8235,8236,8237,8238,8239, # 8240 -8240,8241,8242,8243,8244,8245,8246,8247,8248,8249,8250,8251,8252,8253,8254,8255, # 8256 -8256,8257,8258,8259,8260,8261,8262,8263,8264,8265,8266,8267,8268,8269,8270,8271) # 8272 +) + -# flake8: noqa diff --git a/venv/Lib/site-packages/requests/packages/chardet/jpcntx.py b/venv/Lib/site-packages/chardet/jpcntx.py similarity index 87% rename from venv/Lib/site-packages/requests/packages/chardet/jpcntx.py rename to venv/Lib/site-packages/chardet/jpcntx.py index 59aeb6a87..20044e4bc 100644 --- a/venv/Lib/site-packages/requests/packages/chardet/jpcntx.py +++ b/venv/Lib/site-packages/chardet/jpcntx.py @@ -25,13 +25,6 @@ # 02110-1301 USA ######################### END LICENSE BLOCK ######################### -from .compat import wrap_ord - -NUM_OF_CATEGORY = 6 -DONT_KNOW = -1 -ENOUGH_REL_THRESHOLD = 100 -MAX_REL_THRESHOLD = 1000 -MINIMUM_DATA_THRESHOLD = 4 # This is hiragana 2-char sequence table, the number in each cell represents its frequency category jp2CharContext = ( @@ -120,24 +113,35 @@ jp2CharContext = ( (0,4,0,3,0,3,0,3,0,3,5,5,3,3,3,3,4,3,4,3,3,3,4,4,4,3,3,3,3,4,3,5,3,3,1,3,2,4,5,5,5,5,4,3,4,5,5,3,2,2,3,3,3,3,2,3,3,1,2,3,2,4,3,3,3,4,0,4,0,2,0,4,3,2,2,1,2,0,3,0,0,4,1), ) -class JapaneseContextAnalysis: +class JapaneseContextAnalysis(object): + NUM_OF_CATEGORY = 6 + DONT_KNOW = -1 + ENOUGH_REL_THRESHOLD = 100 + MAX_REL_THRESHOLD = 1000 + MINIMUM_DATA_THRESHOLD = 4 + def __init__(self): + self._total_rel = None + self._rel_sample = None + self._need_to_skip_char_num = None + self._last_char_order = None + self._done = None self.reset() def reset(self): - self._mTotalRel = 0 # total sequence received - # category counters, each interger counts sequence in its category - self._mRelSample = [0] * NUM_OF_CATEGORY + self._total_rel = 0 # total sequence received + # category counters, each integer counts sequence in its category + self._rel_sample = [0] * self.NUM_OF_CATEGORY # if last byte in current buffer is not the last byte of a character, # we need to know how many bytes to skip in next buffer - self._mNeedToSkipCharNum = 0 - self._mLastCharOrder = -1 # The order of previous char + self._need_to_skip_char_num = 0 + self._last_char_order = -1 # The order of previous char # If this flag is set to True, detection is done and conclusion has # been made - self._mDone = False + self._done = False - def feed(self, aBuf, aLen): - if self._mDone: + def feed(self, byte_str, num_bytes): + if self._done: return # The buffer we got is byte oriented, and a character may span in more than one @@ -147,81 +151,83 @@ class JapaneseContextAnalysis: # well and analyse the character once it is complete, but since a # character will not make much difference, by simply skipping # this character will simply our logic and improve performance. - i = self._mNeedToSkipCharNum - while i < aLen: - order, charLen = self.get_order(aBuf[i:i + 2]) - i += charLen - if i > aLen: - self._mNeedToSkipCharNum = i - aLen - self._mLastCharOrder = -1 + i = self._need_to_skip_char_num + while i < num_bytes: + order, char_len = self.get_order(byte_str[i:i + 2]) + i += char_len + if i > num_bytes: + self._need_to_skip_char_num = i - num_bytes + self._last_char_order = -1 else: - if (order != -1) and (self._mLastCharOrder != -1): - self._mTotalRel += 1 - if self._mTotalRel > MAX_REL_THRESHOLD: - self._mDone = True + if (order != -1) and (self._last_char_order != -1): + self._total_rel += 1 + if self._total_rel > self.MAX_REL_THRESHOLD: + self._done = True break - self._mRelSample[jp2CharContext[self._mLastCharOrder][order]] += 1 - self._mLastCharOrder = order + self._rel_sample[jp2CharContext[self._last_char_order][order]] += 1 + self._last_char_order = order def got_enough_data(self): - return self._mTotalRel > ENOUGH_REL_THRESHOLD + return self._total_rel > self.ENOUGH_REL_THRESHOLD def get_confidence(self): # This is just one way to calculate confidence. It works well for me. - if self._mTotalRel > MINIMUM_DATA_THRESHOLD: - return (self._mTotalRel - self._mRelSample[0]) / self._mTotalRel + if self._total_rel > self.MINIMUM_DATA_THRESHOLD: + return (self._total_rel - self._rel_sample[0]) / self._total_rel else: - return DONT_KNOW + return self.DONT_KNOW - def get_order(self, aBuf): + def get_order(self, byte_str): return -1, 1 class SJISContextAnalysis(JapaneseContextAnalysis): def __init__(self): - self.charset_name = "SHIFT_JIS" + super(SJISContextAnalysis, self).__init__() + self._charset_name = "SHIFT_JIS" - def get_charset_name(self): - return self.charset_name + @property + def charset_name(self): + return self._charset_name - def get_order(self, aBuf): - if not aBuf: + def get_order(self, byte_str): + if not byte_str: return -1, 1 # find out current char's byte length - first_char = wrap_ord(aBuf[0]) - if ((0x81 <= first_char <= 0x9F) or (0xE0 <= first_char <= 0xFC)): - charLen = 2 + first_char = byte_str[0] + if (0x81 <= first_char <= 0x9F) or (0xE0 <= first_char <= 0xFC): + char_len = 2 if (first_char == 0x87) or (0xFA <= first_char <= 0xFC): - self.charset_name = "CP932" + self._charset_name = "CP932" else: - charLen = 1 + char_len = 1 # return its order if it is hiragana - if len(aBuf) > 1: - second_char = wrap_ord(aBuf[1]) + if len(byte_str) > 1: + second_char = byte_str[1] if (first_char == 202) and (0x9F <= second_char <= 0xF1): - return second_char - 0x9F, charLen + return second_char - 0x9F, char_len - return -1, charLen + return -1, char_len class EUCJPContextAnalysis(JapaneseContextAnalysis): - def get_order(self, aBuf): - if not aBuf: + def get_order(self, byte_str): + if not byte_str: return -1, 1 # find out current char's byte length - first_char = wrap_ord(aBuf[0]) + first_char = byte_str[0] if (first_char == 0x8E) or (0xA1 <= first_char <= 0xFE): - charLen = 2 + char_len = 2 elif first_char == 0x8F: - charLen = 3 + char_len = 3 else: - charLen = 1 + char_len = 1 # return its order if it is hiragana - if len(aBuf) > 1: - second_char = wrap_ord(aBuf[1]) + if len(byte_str) > 1: + second_char = byte_str[1] if (first_char == 0xA4) and (0xA1 <= second_char <= 0xF3): - return second_char - 0xA1, charLen + return second_char - 0xA1, char_len + + return -1, char_len - return -1, charLen -# flake8: noqa diff --git a/venv/Lib/site-packages/requests/packages/chardet/langbulgarianmodel.py b/venv/Lib/site-packages/chardet/langbulgarianmodel.py similarity index 96% rename from venv/Lib/site-packages/requests/packages/chardet/langbulgarianmodel.py rename to venv/Lib/site-packages/chardet/langbulgarianmodel.py index e5788fc64..2aa4fb2e2 100644 --- a/venv/Lib/site-packages/requests/packages/chardet/langbulgarianmodel.py +++ b/venv/Lib/site-packages/chardet/langbulgarianmodel.py @@ -210,20 +210,19 @@ BulgarianLangModel = ( ) Latin5BulgarianModel = { - 'charToOrderMap': Latin5_BulgarianCharToOrderMap, - 'precedenceMatrix': BulgarianLangModel, - 'mTypicalPositiveRatio': 0.969392, - 'keepEnglishLetter': False, - 'charsetName': "ISO-8859-5" + 'char_to_order_map': Latin5_BulgarianCharToOrderMap, + 'precedence_matrix': BulgarianLangModel, + 'typical_positive_ratio': 0.969392, + 'keep_english_letter': False, + 'charset_name': "ISO-8859-5", + 'language': 'Bulgairan', } Win1251BulgarianModel = { - 'charToOrderMap': win1251BulgarianCharToOrderMap, - 'precedenceMatrix': BulgarianLangModel, - 'mTypicalPositiveRatio': 0.969392, - 'keepEnglishLetter': False, - 'charsetName': "windows-1251" + 'char_to_order_map': win1251BulgarianCharToOrderMap, + 'precedence_matrix': BulgarianLangModel, + 'typical_positive_ratio': 0.969392, + 'keep_english_letter': False, + 'charset_name': "windows-1251", + 'language': 'Bulgarian', } - - -# flake8: noqa diff --git a/venv/Lib/site-packages/requests/packages/chardet/langcyrillicmodel.py b/venv/Lib/site-packages/chardet/langcyrillicmodel.py similarity index 91% rename from venv/Lib/site-packages/requests/packages/chardet/langcyrillicmodel.py rename to venv/Lib/site-packages/chardet/langcyrillicmodel.py index a86f54bd5..e5f9a1fd1 100644 --- a/venv/Lib/site-packages/requests/packages/chardet/langcyrillicmodel.py +++ b/venv/Lib/site-packages/chardet/langcyrillicmodel.py @@ -27,7 +27,7 @@ # KOI8-R language model # Character Mapping Table: -KOI8R_CharToOrderMap = ( +KOI8R_char_to_order_map = ( 255,255,255,255,255,255,255,255,255,255,254,255,255,254,255,255, # 00 255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, # 10 253,253,253,253,253,253,253,253,253,253,253,253,253,253,253,253, # 20 @@ -46,7 +46,7 @@ KOI8R_CharToOrderMap = ( 35, 43, 45, 32, 40, 52, 56, 33, 61, 62, 51, 57, 47, 63, 50, 70, # f0 ) -win1251_CharToOrderMap = ( +win1251_char_to_order_map = ( 255,255,255,255,255,255,255,255,255,255,254,255,255,254,255,255, # 00 255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, # 10 253,253,253,253,253,253,253,253,253,253,253,253,253,253,253,253, # 20 @@ -65,7 +65,7 @@ win1251_CharToOrderMap = ( 9, 7, 6, 14, 39, 26, 28, 22, 25, 29, 54, 18, 17, 30, 27, 16, ) -latin5_CharToOrderMap = ( +latin5_char_to_order_map = ( 255,255,255,255,255,255,255,255,255,255,254,255,255,254,255,255, # 00 255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, # 10 253,253,253,253,253,253,253,253,253,253,253,253,253,253,253,253, # 20 @@ -84,7 +84,7 @@ latin5_CharToOrderMap = ( 239, 68,240,241,242,243,244,245,246,247,248,249,250,251,252,255, ) -macCyrillic_CharToOrderMap = ( +macCyrillic_char_to_order_map = ( 255,255,255,255,255,255,255,255,255,255,254,255,255,254,255,255, # 00 255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, # 10 253,253,253,253,253,253,253,253,253,253,253,253,253,253,253,253, # 20 @@ -103,7 +103,7 @@ macCyrillic_CharToOrderMap = ( 9, 7, 6, 14, 39, 26, 28, 22, 25, 29, 54, 18, 17, 30, 27,255, ) -IBM855_CharToOrderMap = ( +IBM855_char_to_order_map = ( 255,255,255,255,255,255,255,255,255,255,254,255,255,254,255,255, # 00 255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, # 10 253,253,253,253,253,253,253,253,253,253,253,253,253,253,253,253, # 20 @@ -122,7 +122,7 @@ IBM855_CharToOrderMap = ( 250, 18, 62, 20, 51, 25, 57, 30, 47, 29, 63, 22, 50,251,252,255, ) -IBM866_CharToOrderMap = ( +IBM866_char_to_order_map = ( 255,255,255,255,255,255,255,255,255,255,254,255,255,254,255,255, # 00 255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, # 10 253,253,253,253,253,253,253,253,253,253,253,253,253,253,253,253, # 20 @@ -279,51 +279,55 @@ RussianLangModel = ( ) Koi8rModel = { - 'charToOrderMap': KOI8R_CharToOrderMap, - 'precedenceMatrix': RussianLangModel, - 'mTypicalPositiveRatio': 0.976601, - 'keepEnglishLetter': False, - 'charsetName': "KOI8-R" + 'char_to_order_map': KOI8R_char_to_order_map, + 'precedence_matrix': RussianLangModel, + 'typical_positive_ratio': 0.976601, + 'keep_english_letter': False, + 'charset_name': "KOI8-R", + 'language': 'Russian', } Win1251CyrillicModel = { - 'charToOrderMap': win1251_CharToOrderMap, - 'precedenceMatrix': RussianLangModel, - 'mTypicalPositiveRatio': 0.976601, - 'keepEnglishLetter': False, - 'charsetName': "windows-1251" + 'char_to_order_map': win1251_char_to_order_map, + 'precedence_matrix': RussianLangModel, + 'typical_positive_ratio': 0.976601, + 'keep_english_letter': False, + 'charset_name': "windows-1251", + 'language': 'Russian', } Latin5CyrillicModel = { - 'charToOrderMap': latin5_CharToOrderMap, - 'precedenceMatrix': RussianLangModel, - 'mTypicalPositiveRatio': 0.976601, - 'keepEnglishLetter': False, - 'charsetName': "ISO-8859-5" + 'char_to_order_map': latin5_char_to_order_map, + 'precedence_matrix': RussianLangModel, + 'typical_positive_ratio': 0.976601, + 'keep_english_letter': False, + 'charset_name': "ISO-8859-5", + 'language': 'Russian', } MacCyrillicModel = { - 'charToOrderMap': macCyrillic_CharToOrderMap, - 'precedenceMatrix': RussianLangModel, - 'mTypicalPositiveRatio': 0.976601, - 'keepEnglishLetter': False, - 'charsetName': "MacCyrillic" -}; + 'char_to_order_map': macCyrillic_char_to_order_map, + 'precedence_matrix': RussianLangModel, + 'typical_positive_ratio': 0.976601, + 'keep_english_letter': False, + 'charset_name': "MacCyrillic", + 'language': 'Russian', +} Ibm866Model = { - 'charToOrderMap': IBM866_CharToOrderMap, - 'precedenceMatrix': RussianLangModel, - 'mTypicalPositiveRatio': 0.976601, - 'keepEnglishLetter': False, - 'charsetName': "IBM866" + 'char_to_order_map': IBM866_char_to_order_map, + 'precedence_matrix': RussianLangModel, + 'typical_positive_ratio': 0.976601, + 'keep_english_letter': False, + 'charset_name': "IBM866", + 'language': 'Russian', } Ibm855Model = { - 'charToOrderMap': IBM855_CharToOrderMap, - 'precedenceMatrix': RussianLangModel, - 'mTypicalPositiveRatio': 0.976601, - 'keepEnglishLetter': False, - 'charsetName': "IBM855" + 'char_to_order_map': IBM855_char_to_order_map, + 'precedence_matrix': RussianLangModel, + 'typical_positive_ratio': 0.976601, + 'keep_english_letter': False, + 'charset_name': "IBM855", + 'language': 'Russian', } - -# flake8: noqa diff --git a/venv/Lib/site-packages/requests/packages/chardet/langgreekmodel.py b/venv/Lib/site-packages/chardet/langgreekmodel.py similarity index 96% rename from venv/Lib/site-packages/requests/packages/chardet/langgreekmodel.py rename to venv/Lib/site-packages/chardet/langgreekmodel.py index ddb583765..533222166 100644 --- a/venv/Lib/site-packages/requests/packages/chardet/langgreekmodel.py +++ b/venv/Lib/site-packages/chardet/langgreekmodel.py @@ -31,7 +31,7 @@ # 252: 0 - 9 # Character Mapping Table: -Latin7_CharToOrderMap = ( +Latin7_char_to_order_map = ( 255,255,255,255,255,255,255,255,255,255,254,255,255,254,255,255, # 00 255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, # 10 253,253,253,253,253,253,253,253,253,253,253,253,253,253,253,253, # 20 @@ -50,7 +50,7 @@ Latin7_CharToOrderMap = ( 9, 8, 14, 7, 2, 12, 28, 23, 42, 24, 64, 75, 19, 26, 27,253, # f0 ) -win1253_CharToOrderMap = ( +win1253_char_to_order_map = ( 255,255,255,255,255,255,255,255,255,255,254,255,255,254,255,255, # 00 255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, # 10 253,253,253,253,253,253,253,253,253,253,253,253,253,253,253,253, # 20 @@ -207,19 +207,19 @@ GreekLangModel = ( ) Latin7GreekModel = { - 'charToOrderMap': Latin7_CharToOrderMap, - 'precedenceMatrix': GreekLangModel, - 'mTypicalPositiveRatio': 0.982851, - 'keepEnglishLetter': False, - 'charsetName': "ISO-8859-7" + 'char_to_order_map': Latin7_char_to_order_map, + 'precedence_matrix': GreekLangModel, + 'typical_positive_ratio': 0.982851, + 'keep_english_letter': False, + 'charset_name': "ISO-8859-7", + 'language': 'Greek', } Win1253GreekModel = { - 'charToOrderMap': win1253_CharToOrderMap, - 'precedenceMatrix': GreekLangModel, - 'mTypicalPositiveRatio': 0.982851, - 'keepEnglishLetter': False, - 'charsetName': "windows-1253" + 'char_to_order_map': win1253_char_to_order_map, + 'precedence_matrix': GreekLangModel, + 'typical_positive_ratio': 0.982851, + 'keep_english_letter': False, + 'charset_name': "windows-1253", + 'language': 'Greek', } - -# flake8: noqa diff --git a/venv/Lib/site-packages/requests/packages/chardet/langhebrewmodel.py b/venv/Lib/site-packages/chardet/langhebrewmodel.py similarity index 97% rename from venv/Lib/site-packages/requests/packages/chardet/langhebrewmodel.py rename to venv/Lib/site-packages/chardet/langhebrewmodel.py index 75f2bc7fe..58f4c875e 100644 --- a/venv/Lib/site-packages/requests/packages/chardet/langhebrewmodel.py +++ b/venv/Lib/site-packages/chardet/langhebrewmodel.py @@ -34,7 +34,7 @@ # Windows-1255 language model # Character Mapping Table: -win1255_CharToOrderMap = ( +WIN1255_CHAR_TO_ORDER_MAP = ( 255,255,255,255,255,255,255,255,255,255,254,255,255,254,255,255, # 00 255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, # 10 253,253,253,253,253,253,253,253,253,253,253,253,253,253,253,253, # 20 @@ -59,7 +59,7 @@ win1255_CharToOrderMap = ( # first 1024 sequences: 1.5981% # rest sequences: 0.087% # negative sequences: 0.0015% -HebrewLangModel = ( +HEBREW_LANG_MODEL = ( 0,3,3,3,3,3,3,3,3,3,3,2,3,3,3,3,3,3,3,3,3,3,3,2,3,2,1,2,0,1,0,0, 3,0,3,1,0,0,1,3,2,0,1,1,2,0,2,2,2,1,1,1,1,2,1,1,1,2,0,0,2,2,0,1, 3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,2,2,2,2, @@ -191,11 +191,10 @@ HebrewLangModel = ( ) Win1255HebrewModel = { - 'charToOrderMap': win1255_CharToOrderMap, - 'precedenceMatrix': HebrewLangModel, - 'mTypicalPositiveRatio': 0.984004, - 'keepEnglishLetter': False, - 'charsetName': "windows-1255" + 'char_to_order_map': WIN1255_CHAR_TO_ORDER_MAP, + 'precedence_matrix': HEBREW_LANG_MODEL, + 'typical_positive_ratio': 0.984004, + 'keep_english_letter': False, + 'charset_name': "windows-1255", + 'language': 'Hebrew', } - -# flake8: noqa diff --git a/venv/Lib/site-packages/requests/packages/chardet/langhungarianmodel.py b/venv/Lib/site-packages/chardet/langhungarianmodel.py similarity index 96% rename from venv/Lib/site-packages/requests/packages/chardet/langhungarianmodel.py rename to venv/Lib/site-packages/chardet/langhungarianmodel.py index 49d2f0fe7..bb7c095e1 100644 --- a/venv/Lib/site-packages/requests/packages/chardet/langhungarianmodel.py +++ b/venv/Lib/site-packages/chardet/langhungarianmodel.py @@ -207,19 +207,19 @@ HungarianLangModel = ( ) Latin2HungarianModel = { - 'charToOrderMap': Latin2_HungarianCharToOrderMap, - 'precedenceMatrix': HungarianLangModel, - 'mTypicalPositiveRatio': 0.947368, - 'keepEnglishLetter': True, - 'charsetName': "ISO-8859-2" + 'char_to_order_map': Latin2_HungarianCharToOrderMap, + 'precedence_matrix': HungarianLangModel, + 'typical_positive_ratio': 0.947368, + 'keep_english_letter': True, + 'charset_name': "ISO-8859-2", + 'language': 'Hungarian', } Win1250HungarianModel = { - 'charToOrderMap': win1250HungarianCharToOrderMap, - 'precedenceMatrix': HungarianLangModel, - 'mTypicalPositiveRatio': 0.947368, - 'keepEnglishLetter': True, - 'charsetName': "windows-1250" + 'char_to_order_map': win1250HungarianCharToOrderMap, + 'precedence_matrix': HungarianLangModel, + 'typical_positive_ratio': 0.947368, + 'keep_english_letter': True, + 'charset_name': "windows-1250", + 'language': 'Hungarian', } - -# flake8: noqa diff --git a/venv/Lib/site-packages/requests/packages/chardet/langthaimodel.py b/venv/Lib/site-packages/chardet/langthaimodel.py similarity index 98% rename from venv/Lib/site-packages/requests/packages/chardet/langthaimodel.py rename to venv/Lib/site-packages/chardet/langthaimodel.py index 0508b1b1a..15f94c2df 100644 --- a/venv/Lib/site-packages/requests/packages/chardet/langthaimodel.py +++ b/venv/Lib/site-packages/chardet/langthaimodel.py @@ -190,11 +190,10 @@ ThaiLangModel = ( ) TIS620ThaiModel = { - 'charToOrderMap': TIS620CharToOrderMap, - 'precedenceMatrix': ThaiLangModel, - 'mTypicalPositiveRatio': 0.926386, - 'keepEnglishLetter': False, - 'charsetName': "TIS-620" + 'char_to_order_map': TIS620CharToOrderMap, + 'precedence_matrix': ThaiLangModel, + 'typical_positive_ratio': 0.926386, + 'keep_english_letter': False, + 'charset_name': "TIS-620", + 'language': 'Thai', } - -# flake8: noqa diff --git a/venv/Lib/site-packages/chardet/langturkishmodel.py b/venv/Lib/site-packages/chardet/langturkishmodel.py new file mode 100644 index 000000000..a427a4573 --- /dev/null +++ b/venv/Lib/site-packages/chardet/langturkishmodel.py @@ -0,0 +1,193 @@ +# -*- coding: utf-8 -*- +######################## BEGIN LICENSE BLOCK ######################## +# The Original Code is Mozilla Communicator client code. +# +# The Initial Developer of the Original Code is +# Netscape Communications Corporation. +# Portions created by the Initial Developer are Copyright (C) 1998 +# the Initial Developer. All Rights Reserved. +# +# Contributor(s): +# Mark Pilgrim - port to Python +# Özgür Baskın - Turkish Language Model +# +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; either +# version 2.1 of the License, or (at your option) any later version. +# +# This library 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 +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this library; if not, write to the Free Software +# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA +# 02110-1301 USA +######################### END LICENSE BLOCK ######################### + +# 255: Control characters that usually does not exist in any text +# 254: Carriage/Return +# 253: symbol (punctuation) that does not belong to word +# 252: 0 - 9 + +# Character Mapping Table: +Latin5_TurkishCharToOrderMap = ( +255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, +255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, +255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, +255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, +255, 23, 37, 47, 39, 29, 52, 36, 45, 53, 60, 16, 49, 20, 46, 42, + 48, 69, 44, 35, 31, 51, 38, 62, 65, 43, 56,255,255,255,255,255, +255, 1, 21, 28, 12, 2, 18, 27, 25, 3, 24, 10, 5, 13, 4, 15, + 26, 64, 7, 8, 9, 14, 32, 57, 58, 11, 22,255,255,255,255,255, +180,179,178,177,176,175,174,173,172,171,170,169,168,167,166,165, +164,163,162,161,160,159,101,158,157,156,155,154,153,152,151,106, +150,149,148,147,146,145,144,100,143,142,141,140,139,138,137,136, + 94, 80, 93,135,105,134,133, 63,132,131,130,129,128,127,126,125, +124,104, 73, 99, 79, 85,123, 54,122, 98, 92,121,120, 91,103,119, + 68,118,117, 97,116,115, 50, 90,114,113,112,111, 55, 41, 40, 86, + 89, 70, 59, 78, 71, 82, 88, 33, 77, 66, 84, 83,110, 75, 61, 96, + 30, 67,109, 74, 87,102, 34, 95, 81,108, 76, 72, 17, 6, 19,107, +) + +TurkishLangModel = ( +3,2,3,3,3,1,3,3,3,3,3,3,3,3,2,1,1,3,3,1,3,3,0,3,3,3,3,3,0,3,1,3, +3,2,1,0,0,1,1,0,0,0,1,0,0,1,1,1,1,0,0,0,0,0,0,0,2,2,0,0,1,0,0,1, +3,2,2,3,3,0,3,3,3,3,3,3,3,2,3,1,0,3,3,1,3,3,0,3,3,3,3,3,0,3,0,3, +3,1,1,0,1,0,1,0,0,0,0,0,0,1,1,1,1,0,0,0,0,0,0,0,2,2,0,0,0,1,0,1, +3,3,2,3,3,0,3,3,3,3,3,3,3,2,3,1,1,3,3,0,3,3,1,2,3,3,3,3,0,3,0,3, +3,1,1,0,0,0,1,0,0,0,0,1,1,0,1,2,1,0,0,0,1,0,0,0,0,2,0,0,0,0,0,1, +3,3,3,3,3,3,2,3,3,3,3,3,3,3,3,1,3,3,2,0,3,2,1,2,2,1,3,3,0,0,0,2, +2,2,0,1,0,0,1,0,0,1,1,0,0,0,0,0,0,0,0,0,0,0,0,1,0,1,1,0,1,0,0,1, +3,3,3,2,3,3,1,2,3,3,3,3,3,3,3,1,3,2,1,0,3,2,0,1,2,3,3,2,1,0,0,2, +2,1,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,2,0,2,0,0,0, +1,0,1,3,3,1,3,3,3,3,3,3,3,1,2,0,0,2,3,0,2,3,0,0,2,2,2,3,0,3,0,1, +2,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,0,3,3,3,0,3,2,0,2,3,2,3,3,1,0,0,2, +3,2,0,0,1,0,0,0,0,0,0,2,0,0,1,0,0,0,0,0,0,0,0,0,1,1,1,0,2,0,0,1, +3,3,3,2,3,3,2,3,3,3,3,2,3,3,3,0,3,3,0,0,2,1,0,0,2,3,2,2,0,0,0,2, +2,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,0,0,0,1,0,1,0,2,0,0,1, +3,3,3,2,3,3,3,3,3,3,3,2,3,3,3,0,3,2,0,1,3,2,1,1,3,2,3,2,1,0,0,2, +2,2,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,1,0,0,0,0,0, +3,3,3,2,3,3,3,3,3,3,3,2,3,3,3,0,3,2,2,0,2,3,0,0,2,2,2,2,0,0,0,2, +3,3,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,2,0,1,0,0,0, +3,3,3,3,3,3,3,2,2,2,2,3,2,3,3,0,3,3,1,1,2,2,0,0,2,2,3,2,0,0,1,3, +0,3,1,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,1,0,0,0,0,1, +3,3,3,2,3,3,3,2,1,2,2,3,2,3,3,0,3,2,0,0,1,1,0,1,1,2,1,2,0,0,0,1, +0,3,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,1,0,1,0,1,0,0,0, +3,3,3,2,3,3,2,3,2,2,2,3,3,3,3,1,3,1,1,0,3,2,1,1,3,3,2,3,1,0,0,1, +1,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,2,0,0,1, +3,2,2,3,3,0,3,3,3,3,3,3,3,2,2,1,0,3,3,1,3,3,0,1,3,3,2,3,0,3,0,3, +2,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0, +2,2,2,3,3,0,3,3,3,3,3,3,3,3,3,0,0,3,2,0,3,3,0,3,2,3,3,3,0,3,1,3, +2,0,0,0,0,0,0,0,0,0,0,1,0,1,2,0,1,0,0,0,0,0,0,0,2,2,0,0,1,0,0,1, +3,3,3,1,2,3,3,1,0,0,1,0,0,3,3,2,3,0,0,2,0,0,2,0,2,0,0,0,2,0,2,0, +0,3,1,0,1,0,0,0,2,2,1,0,1,1,2,1,2,2,2,0,2,1,1,0,0,0,2,0,0,0,0,0, +1,2,1,3,3,0,3,3,3,3,3,2,3,0,0,0,0,2,3,0,2,3,1,0,2,3,1,3,0,3,0,2, +3,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +3,3,3,1,3,3,2,2,3,2,2,0,1,2,3,0,1,2,1,0,1,0,0,0,1,0,2,2,0,0,0,1, +1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,1,1,0,0,1,0,0,0, +3,3,3,1,3,3,1,1,3,3,1,1,3,3,1,0,2,1,2,0,2,1,0,0,1,1,2,1,0,0,0,2, +2,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +3,3,3,1,0,2,1,3,0,0,2,0,0,3,3,0,3,0,0,1,0,1,2,0,0,1,1,2,2,0,1,0, +0,1,2,1,1,0,1,0,1,1,1,1,1,0,1,1,1,2,2,1,2,0,1,0,0,0,0,0,0,1,0,0, +3,3,3,2,3,2,3,3,0,2,2,2,3,3,3,0,3,0,0,0,2,2,0,1,2,1,1,1,0,0,0,1, +0,3,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0, +3,3,3,3,3,3,2,1,2,2,3,3,3,3,2,0,2,0,0,0,2,2,0,0,2,1,3,3,0,0,1,1, +1,1,0,0,1,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,1,0,0,0, +1,1,2,3,3,0,3,3,3,3,3,3,2,2,0,2,0,2,3,2,3,2,2,2,2,2,2,2,1,3,2,3, +2,0,2,1,2,2,2,2,1,1,2,2,1,2,2,1,2,0,0,2,1,1,0,2,1,0,0,1,0,0,0,1, +2,3,3,1,1,1,0,1,1,1,2,3,2,1,1,0,0,0,0,0,0,0,0,0,0,1,0,1,0,0,0,0, +0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +3,3,3,2,2,2,3,2,3,2,2,1,3,3,3,0,2,1,2,0,2,1,0,0,1,1,1,1,1,0,0,1, +2,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,1,0,2,0,1,0,0,0, +3,3,3,2,3,3,3,3,3,2,3,1,2,3,3,1,2,0,0,0,0,0,0,0,3,2,1,1,0,0,0,0, +2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0, +3,3,3,2,2,3,3,2,1,1,1,1,1,3,3,0,3,1,0,0,1,1,0,0,3,1,2,1,0,0,0,0, +0,3,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0, +3,3,3,2,2,3,2,2,2,3,2,1,1,3,3,0,3,0,0,0,0,1,0,0,3,1,1,2,0,0,0,1, +1,0,0,1,0,0,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1, +1,1,1,3,3,0,3,3,3,3,3,2,2,2,1,2,0,2,1,2,2,1,1,0,1,2,2,2,2,2,2,2, +0,0,2,1,2,1,2,1,0,1,1,3,1,2,1,1,2,0,0,2,0,1,0,1,0,1,0,0,0,1,0,1, +3,3,3,1,3,3,3,0,1,1,0,2,2,3,1,0,3,0,0,0,1,0,0,0,1,0,0,1,0,1,0,0, +1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +3,3,2,0,0,2,2,1,0,0,1,0,0,3,3,1,3,0,0,1,1,0,2,0,3,0,0,0,2,0,1,1, +0,1,2,0,1,2,2,0,2,2,2,2,1,0,2,1,1,0,2,0,2,1,2,0,0,0,0,0,0,0,0,0, +3,3,3,1,3,2,3,2,0,2,2,2,1,3,2,0,2,1,2,0,1,2,0,0,1,0,2,2,0,0,0,2, +1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,0,1,0,0,0, +3,3,3,0,3,3,1,1,2,3,1,0,3,2,3,0,3,0,0,0,1,0,0,0,1,0,1,0,0,0,0,0, +1,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,3,3,0,3,3,2,3,3,2,2,0,0,0,0,1,2,0,1,3,0,0,0,3,1,1,0,3,0,2, +2,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +3,3,3,1,2,2,1,0,3,1,1,1,1,3,3,2,3,0,0,1,0,1,2,0,2,2,0,2,2,0,2,1, +0,2,2,1,1,1,1,0,2,1,1,0,1,1,1,1,2,1,2,1,2,0,1,0,1,0,0,0,0,0,0,0, +3,3,3,0,1,1,3,0,0,1,1,0,0,2,2,0,3,0,0,1,1,0,1,0,0,0,0,0,2,0,0,0, +0,3,1,0,1,0,1,0,2,0,0,1,0,1,0,1,1,1,2,1,1,0,2,0,0,0,0,0,0,0,0,0, +3,3,3,0,2,0,2,0,1,1,1,0,0,3,3,0,2,0,0,1,0,0,2,1,1,0,1,0,1,0,1,0, +0,2,0,1,2,0,2,0,2,1,1,0,1,0,2,1,1,0,2,1,1,0,1,0,0,0,1,1,0,0,0,0, +3,2,3,0,1,0,0,0,0,0,0,0,0,1,2,0,1,0,0,1,0,0,1,0,0,0,0,0,2,0,0,0, +0,0,1,1,0,0,1,0,1,0,0,1,0,0,0,2,1,0,1,0,2,0,0,0,0,0,0,0,0,0,0,0, +3,3,3,0,0,2,3,0,0,1,0,1,0,2,3,2,3,0,0,1,3,0,2,1,0,0,0,0,2,0,1,0, +0,2,1,0,0,1,1,0,2,1,0,0,1,0,0,1,1,0,1,1,2,0,1,0,0,0,0,1,0,0,0,0, +3,2,2,0,0,1,1,0,0,0,0,0,0,3,1,1,1,0,0,0,0,0,1,0,0,0,0,0,2,0,1,0, +0,1,0,0,0,0,0,0,1,0,0,0,0,0,0,0,1,0,0,0,1,0,1,0,0,0,0,0,0,0,0,0, +0,0,0,3,3,0,2,3,2,2,1,2,2,1,1,2,0,1,3,2,2,2,0,0,2,2,0,0,0,1,2,1, +3,0,2,1,1,0,1,1,1,0,1,2,2,2,1,1,2,0,0,0,0,1,0,1,1,0,0,0,0,0,0,0, +0,1,1,2,3,0,3,3,3,2,2,2,2,1,0,1,0,1,0,1,2,2,0,0,2,2,1,3,1,1,2,1, +0,0,1,1,2,0,1,1,0,0,1,2,0,2,1,1,2,0,0,1,0,0,0,1,0,1,0,1,0,0,0,0, +3,3,2,0,0,3,1,0,0,0,0,0,0,3,2,1,2,0,0,1,0,0,2,0,0,0,0,0,2,0,1,0, +0,2,1,1,0,0,1,0,1,2,0,0,1,1,0,0,2,1,1,1,1,0,2,0,0,0,0,0,0,0,0,0, +3,3,2,0,0,1,0,0,0,0,1,0,0,3,3,2,2,0,0,1,0,0,2,0,1,0,0,0,2,0,1,0, +0,0,1,1,0,0,2,0,2,1,0,0,1,1,2,1,2,0,2,1,2,1,1,1,0,0,1,1,0,0,0,0, +3,3,2,0,0,2,2,0,0,0,1,1,0,2,2,1,3,1,0,1,0,1,2,0,0,0,0,0,1,0,1,0, +0,1,1,0,0,0,0,0,1,0,0,1,0,0,0,1,1,0,1,0,1,0,0,0,0,0,0,0,0,0,0,0, +3,3,3,2,0,0,0,1,0,0,1,0,0,2,3,1,2,0,0,1,0,0,2,0,0,0,1,0,2,0,2,0, +0,1,1,2,2,1,2,0,2,1,1,0,0,1,1,0,1,1,1,1,2,1,1,0,0,0,0,0,0,0,0,0, +3,3,3,0,2,1,2,1,0,0,1,1,0,3,3,1,2,0,0,1,0,0,2,0,2,0,1,1,2,0,0,0, +0,0,1,1,1,1,2,0,1,1,0,1,1,1,1,0,0,0,1,1,1,0,1,0,0,0,1,0,0,0,0,0, +3,3,3,0,2,2,3,2,0,0,1,0,0,2,3,1,0,0,0,0,0,0,2,0,2,0,0,0,2,0,0,0, +0,1,1,0,0,0,1,0,0,1,0,1,1,0,1,0,1,1,1,0,1,0,0,0,0,0,0,0,0,0,0,0, +3,2,3,0,0,0,0,0,0,0,1,0,0,2,2,2,2,0,0,1,0,0,2,0,0,0,0,0,2,0,1,0, +0,0,2,1,1,0,1,0,2,1,1,0,0,1,1,2,1,0,2,0,2,0,1,0,0,0,2,0,0,0,0,0, +0,0,0,2,2,0,2,1,1,1,1,2,2,0,0,1,0,1,0,0,1,3,0,0,0,0,1,0,0,2,1,0, +0,0,1,0,1,0,0,0,0,0,2,1,0,1,0,0,0,0,0,0,0,0,0,2,0,0,0,0,0,0,0,0, +2,0,0,2,3,0,2,3,1,2,2,0,2,0,0,2,0,2,1,1,1,2,1,0,0,1,2,1,1,2,1,0, +1,0,2,0,1,0,1,1,0,0,2,2,1,2,1,1,2,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0, +3,3,3,0,2,1,2,0,0,0,1,0,0,3,2,0,1,0,0,1,0,0,2,0,0,0,1,2,1,0,1,0, +0,0,0,0,1,0,1,0,0,1,0,0,0,0,1,0,1,0,1,1,1,0,1,0,0,0,0,0,0,0,0,0, +0,0,0,2,2,0,2,2,1,1,0,1,1,1,1,1,0,0,1,2,1,1,1,0,1,0,0,0,1,1,1,1, +0,0,2,1,0,1,1,1,0,1,1,2,1,2,1,1,2,0,1,1,2,1,0,2,0,0,0,0,0,0,0,0, +3,2,2,0,0,2,0,0,0,0,0,0,0,2,2,0,2,0,0,1,0,0,2,0,0,0,0,0,2,0,0,0, +0,2,1,0,0,0,0,0,1,0,0,0,0,0,0,0,1,0,0,0,1,0,1,0,0,0,0,0,0,0,0,0, +0,0,0,3,2,0,2,2,0,1,1,0,1,0,0,1,0,0,0,1,0,1,0,0,0,0,0,1,0,0,0,0, +2,0,1,0,1,0,1,1,0,0,1,2,0,1,0,1,1,0,0,1,0,1,0,2,0,0,0,0,0,0,0,0, +2,2,2,0,1,1,0,0,0,1,0,0,0,1,2,0,1,0,0,1,0,0,1,0,0,0,0,1,2,0,1,0, +0,0,1,0,0,0,1,0,0,1,0,0,0,0,0,0,1,0,1,0,2,0,0,0,0,0,0,0,0,0,0,0, +2,2,2,2,1,0,1,1,1,0,0,0,0,1,2,0,0,1,0,0,0,1,0,0,1,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,0,0,0,0,0,0,0, +1,1,2,0,1,0,0,0,1,0,1,0,0,0,1,0,0,1,0,0,0,0,0,0,0,1,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,2,0,0,0,0,0,1, +0,0,1,2,2,0,2,1,2,1,1,2,2,0,0,0,0,1,0,0,1,1,0,0,2,0,0,0,0,1,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0, +2,2,2,0,0,0,1,0,0,0,0,0,0,2,2,1,1,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0, +0,0,0,0,1,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,1,1,0,0,0,1,0,0,0,1,0,0,0,0,0,0,0,1,1,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +2,2,2,0,1,0,1,0,0,0,0,0,0,1,1,0,0,0,0,0,0,0,1,0,1,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,1,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,1,0,0,0,0,0,0,0,0,0,0,2,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +) + +Latin5TurkishModel = { + 'char_to_order_map': Latin5_TurkishCharToOrderMap, + 'precedence_matrix': TurkishLangModel, + 'typical_positive_ratio': 0.970290, + 'keep_english_letter': True, + 'charset_name': "ISO-8859-9", + 'language': 'Turkish', +} diff --git a/venv/Lib/site-packages/requests/packages/chardet/latin1prober.py b/venv/Lib/site-packages/chardet/latin1prober.py similarity index 81% rename from venv/Lib/site-packages/requests/packages/chardet/latin1prober.py rename to venv/Lib/site-packages/chardet/latin1prober.py index eef357354..7d1e8c20f 100644 --- a/venv/Lib/site-packages/requests/packages/chardet/latin1prober.py +++ b/venv/Lib/site-packages/chardet/latin1prober.py @@ -27,8 +27,7 @@ ######################### END LICENSE BLOCK ######################### from .charsetprober import CharSetProber -from .constants import eNotMe -from .compat import wrap_ord +from .enums import ProbingState FREQ_CAT_NUM = 4 @@ -82,7 +81,7 @@ Latin1_CharToClass = ( # 2 : normal # 3 : very likely Latin1ClassModel = ( - # UDF OTH ASC ASS ACV ACO ASV ASO +# UDF OTH ASC ASS ACV ACO ASV ASO 0, 0, 0, 0, 0, 0, 0, 0, # UDF 0, 3, 3, 3, 3, 3, 3, 3, # OTH 0, 3, 3, 3, 3, 3, 3, 3, # ASC @@ -96,40 +95,47 @@ Latin1ClassModel = ( class Latin1Prober(CharSetProber): def __init__(self): - CharSetProber.__init__(self) + super(Latin1Prober, self).__init__() + self._last_char_class = None + self._freq_counter = None self.reset() def reset(self): - self._mLastCharClass = OTH - self._mFreqCounter = [0] * FREQ_CAT_NUM + self._last_char_class = OTH + self._freq_counter = [0] * FREQ_CAT_NUM CharSetProber.reset(self) - def get_charset_name(self): - return "windows-1252" + @property + def charset_name(self): + return "ISO-8859-1" - def feed(self, aBuf): - aBuf = self.filter_with_english_letters(aBuf) - for c in aBuf: - charClass = Latin1_CharToClass[wrap_ord(c)] - freq = Latin1ClassModel[(self._mLastCharClass * CLASS_NUM) - + charClass] + @property + def language(self): + return "" + + def feed(self, byte_str): + byte_str = self.filter_with_english_letters(byte_str) + for c in byte_str: + char_class = Latin1_CharToClass[c] + freq = Latin1ClassModel[(self._last_char_class * CLASS_NUM) + + char_class] if freq == 0: - self._mState = eNotMe + self._state = ProbingState.NOT_ME break - self._mFreqCounter[freq] += 1 - self._mLastCharClass = charClass + self._freq_counter[freq] += 1 + self._last_char_class = char_class - return self.get_state() + return self.state def get_confidence(self): - if self.get_state() == eNotMe: + if self.state == ProbingState.NOT_ME: return 0.01 - total = sum(self._mFreqCounter) + total = sum(self._freq_counter) if total < 0.01: confidence = 0.0 else: - confidence = ((self._mFreqCounter[3] - self._mFreqCounter[1] * 20.0) + confidence = ((self._freq_counter[3] - self._freq_counter[1] * 20.0) / total) if confidence < 0.0: confidence = 0.0 diff --git a/venv/Lib/site-packages/chardet/mbcharsetprober.py b/venv/Lib/site-packages/chardet/mbcharsetprober.py new file mode 100644 index 000000000..6256ecfd1 --- /dev/null +++ b/venv/Lib/site-packages/chardet/mbcharsetprober.py @@ -0,0 +1,91 @@ +######################## BEGIN LICENSE BLOCK ######################## +# The Original Code is Mozilla Universal charset detector code. +# +# The Initial Developer of the Original Code is +# Netscape Communications Corporation. +# Portions created by the Initial Developer are Copyright (C) 2001 +# the Initial Developer. All Rights Reserved. +# +# Contributor(s): +# Mark Pilgrim - port to Python +# Shy Shalom - original C code +# Proofpoint, Inc. +# +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; either +# version 2.1 of the License, or (at your option) any later version. +# +# This library 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 +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this library; if not, write to the Free Software +# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA +# 02110-1301 USA +######################### END LICENSE BLOCK ######################### + +from .charsetprober import CharSetProber +from .enums import ProbingState, MachineState + + +class MultiByteCharSetProber(CharSetProber): + """ + MultiByteCharSetProber + """ + + def __init__(self, lang_filter=None): + super(MultiByteCharSetProber, self).__init__(lang_filter=lang_filter) + self.distribution_analyzer = None + self.coding_sm = None + self._last_char = [0, 0] + + def reset(self): + super(MultiByteCharSetProber, self).reset() + if self.coding_sm: + self.coding_sm.reset() + if self.distribution_analyzer: + self.distribution_analyzer.reset() + self._last_char = [0, 0] + + @property + def charset_name(self): + raise NotImplementedError + + @property + def language(self): + raise NotImplementedError + + def feed(self, byte_str): + for i in range(len(byte_str)): + coding_state = self.coding_sm.next_state(byte_str[i]) + if coding_state == MachineState.ERROR: + self.logger.debug('%s %s prober hit error at byte %s', + self.charset_name, self.language, i) + self._state = ProbingState.NOT_ME + break + elif coding_state == MachineState.ITS_ME: + self._state = ProbingState.FOUND_IT + break + elif coding_state == MachineState.START: + char_len = self.coding_sm.get_current_charlen() + if i == 0: + self._last_char[1] = byte_str[0] + self.distribution_analyzer.feed(self._last_char, char_len) + else: + self.distribution_analyzer.feed(byte_str[i - 1:i + 1], + char_len) + + self._last_char[0] = byte_str[-1] + + if self.state == ProbingState.DETECTING: + if (self.distribution_analyzer.got_enough_data() and + (self.get_confidence() > self.SHORTCUT_THRESHOLD)): + self._state = ProbingState.FOUND_IT + + return self.state + + def get_confidence(self): + return self.distribution_analyzer.get_confidence() diff --git a/venv/Lib/site-packages/requests/packages/chardet/mbcsgroupprober.py b/venv/Lib/site-packages/chardet/mbcsgroupprober.py similarity index 93% rename from venv/Lib/site-packages/requests/packages/chardet/mbcsgroupprober.py rename to venv/Lib/site-packages/chardet/mbcsgroupprober.py index 03c9dcf3e..530abe75e 100644 --- a/venv/Lib/site-packages/requests/packages/chardet/mbcsgroupprober.py +++ b/venv/Lib/site-packages/chardet/mbcsgroupprober.py @@ -39,9 +39,9 @@ from .euctwprober import EUCTWProber class MBCSGroupProber(CharSetGroupProber): - def __init__(self): - CharSetGroupProber.__init__(self) - self._mProbers = [ + def __init__(self, lang_filter=None): + super(MBCSGroupProber, self).__init__(lang_filter=lang_filter) + self.probers = [ UTF8Prober(), SJISProber(), EUCJPProber(), diff --git a/venv/Lib/site-packages/chardet/mbcssm.py b/venv/Lib/site-packages/chardet/mbcssm.py new file mode 100644 index 000000000..8360d0f28 --- /dev/null +++ b/venv/Lib/site-packages/chardet/mbcssm.py @@ -0,0 +1,572 @@ +######################## BEGIN LICENSE BLOCK ######################## +# The Original Code is mozilla.org code. +# +# The Initial Developer of the Original Code is +# Netscape Communications Corporation. +# Portions created by the Initial Developer are Copyright (C) 1998 +# the Initial Developer. All Rights Reserved. +# +# Contributor(s): +# Mark Pilgrim - port to Python +# +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; either +# version 2.1 of the License, or (at your option) any later version. +# +# This library 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 +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this library; if not, write to the Free Software +# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA +# 02110-1301 USA +######################### END LICENSE BLOCK ######################### + +from .enums import MachineState + +# BIG5 + +BIG5_CLS = ( + 1,1,1,1,1,1,1,1, # 00 - 07 #allow 0x00 as legal value + 1,1,1,1,1,1,0,0, # 08 - 0f + 1,1,1,1,1,1,1,1, # 10 - 17 + 1,1,1,0,1,1,1,1, # 18 - 1f + 1,1,1,1,1,1,1,1, # 20 - 27 + 1,1,1,1,1,1,1,1, # 28 - 2f + 1,1,1,1,1,1,1,1, # 30 - 37 + 1,1,1,1,1,1,1,1, # 38 - 3f + 2,2,2,2,2,2,2,2, # 40 - 47 + 2,2,2,2,2,2,2,2, # 48 - 4f + 2,2,2,2,2,2,2,2, # 50 - 57 + 2,2,2,2,2,2,2,2, # 58 - 5f + 2,2,2,2,2,2,2,2, # 60 - 67 + 2,2,2,2,2,2,2,2, # 68 - 6f + 2,2,2,2,2,2,2,2, # 70 - 77 + 2,2,2,2,2,2,2,1, # 78 - 7f + 4,4,4,4,4,4,4,4, # 80 - 87 + 4,4,4,4,4,4,4,4, # 88 - 8f + 4,4,4,4,4,4,4,4, # 90 - 97 + 4,4,4,4,4,4,4,4, # 98 - 9f + 4,3,3,3,3,3,3,3, # a0 - a7 + 3,3,3,3,3,3,3,3, # a8 - af + 3,3,3,3,3,3,3,3, # b0 - b7 + 3,3,3,3,3,3,3,3, # b8 - bf + 3,3,3,3,3,3,3,3, # c0 - c7 + 3,3,3,3,3,3,3,3, # c8 - cf + 3,3,3,3,3,3,3,3, # d0 - d7 + 3,3,3,3,3,3,3,3, # d8 - df + 3,3,3,3,3,3,3,3, # e0 - e7 + 3,3,3,3,3,3,3,3, # e8 - ef + 3,3,3,3,3,3,3,3, # f0 - f7 + 3,3,3,3,3,3,3,0 # f8 - ff +) + +BIG5_ST = ( + MachineState.ERROR,MachineState.START,MachineState.START, 3,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,#00-07 + MachineState.ERROR,MachineState.ERROR,MachineState.ITS_ME,MachineState.ITS_ME,MachineState.ITS_ME,MachineState.ITS_ME,MachineState.ITS_ME,MachineState.ERROR,#08-0f + MachineState.ERROR,MachineState.START,MachineState.START,MachineState.START,MachineState.START,MachineState.START,MachineState.START,MachineState.START#10-17 +) + +BIG5_CHAR_LEN_TABLE = (0, 1, 1, 2, 0) + +BIG5_SM_MODEL = {'class_table': BIG5_CLS, + 'class_factor': 5, + 'state_table': BIG5_ST, + 'char_len_table': BIG5_CHAR_LEN_TABLE, + 'name': 'Big5'} + +# CP949 + +CP949_CLS = ( + 1,1,1,1,1,1,1,1, 1,1,1,1,1,1,0,0, # 00 - 0f + 1,1,1,1,1,1,1,1, 1,1,1,0,1,1,1,1, # 10 - 1f + 1,1,1,1,1,1,1,1, 1,1,1,1,1,1,1,1, # 20 - 2f + 1,1,1,1,1,1,1,1, 1,1,1,1,1,1,1,1, # 30 - 3f + 1,4,4,4,4,4,4,4, 4,4,4,4,4,4,4,4, # 40 - 4f + 4,4,5,5,5,5,5,5, 5,5,5,1,1,1,1,1, # 50 - 5f + 1,5,5,5,5,5,5,5, 5,5,5,5,5,5,5,5, # 60 - 6f + 5,5,5,5,5,5,5,5, 5,5,5,1,1,1,1,1, # 70 - 7f + 0,6,6,6,6,6,6,6, 6,6,6,6,6,6,6,6, # 80 - 8f + 6,6,6,6,6,6,6,6, 6,6,6,6,6,6,6,6, # 90 - 9f + 6,7,7,7,7,7,7,7, 7,7,7,7,7,8,8,8, # a0 - af + 7,7,7,7,7,7,7,7, 7,7,7,7,7,7,7,7, # b0 - bf + 7,7,7,7,7,7,9,2, 2,3,2,2,2,2,2,2, # c0 - cf + 2,2,2,2,2,2,2,2, 2,2,2,2,2,2,2,2, # d0 - df + 2,2,2,2,2,2,2,2, 2,2,2,2,2,2,2,2, # e0 - ef + 2,2,2,2,2,2,2,2, 2,2,2,2,2,2,2,0, # f0 - ff +) + +CP949_ST = ( +#cls= 0 1 2 3 4 5 6 7 8 9 # previous state = + MachineState.ERROR,MachineState.START, 3,MachineState.ERROR,MachineState.START,MachineState.START, 4, 5,MachineState.ERROR, 6, # MachineState.START + MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR, # MachineState.ERROR + MachineState.ITS_ME,MachineState.ITS_ME,MachineState.ITS_ME,MachineState.ITS_ME,MachineState.ITS_ME,MachineState.ITS_ME,MachineState.ITS_ME,MachineState.ITS_ME,MachineState.ITS_ME,MachineState.ITS_ME, # MachineState.ITS_ME + MachineState.ERROR,MachineState.ERROR,MachineState.START,MachineState.START,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.START,MachineState.START,MachineState.START, # 3 + MachineState.ERROR,MachineState.ERROR,MachineState.START,MachineState.START,MachineState.START,MachineState.START,MachineState.START,MachineState.START,MachineState.START,MachineState.START, # 4 + MachineState.ERROR,MachineState.START,MachineState.START,MachineState.START,MachineState.START,MachineState.START,MachineState.START,MachineState.START,MachineState.START,MachineState.START, # 5 + MachineState.ERROR,MachineState.START,MachineState.START,MachineState.START,MachineState.START,MachineState.ERROR,MachineState.ERROR,MachineState.START,MachineState.START,MachineState.START, # 6 +) + +CP949_CHAR_LEN_TABLE = (0, 1, 2, 0, 1, 1, 2, 2, 0, 2) + +CP949_SM_MODEL = {'class_table': CP949_CLS, + 'class_factor': 10, + 'state_table': CP949_ST, + 'char_len_table': CP949_CHAR_LEN_TABLE, + 'name': 'CP949'} + +# EUC-JP + +EUCJP_CLS = ( + 4,4,4,4,4,4,4,4, # 00 - 07 + 4,4,4,4,4,4,5,5, # 08 - 0f + 4,4,4,4,4,4,4,4, # 10 - 17 + 4,4,4,5,4,4,4,4, # 18 - 1f + 4,4,4,4,4,4,4,4, # 20 - 27 + 4,4,4,4,4,4,4,4, # 28 - 2f + 4,4,4,4,4,4,4,4, # 30 - 37 + 4,4,4,4,4,4,4,4, # 38 - 3f + 4,4,4,4,4,4,4,4, # 40 - 47 + 4,4,4,4,4,4,4,4, # 48 - 4f + 4,4,4,4,4,4,4,4, # 50 - 57 + 4,4,4,4,4,4,4,4, # 58 - 5f + 4,4,4,4,4,4,4,4, # 60 - 67 + 4,4,4,4,4,4,4,4, # 68 - 6f + 4,4,4,4,4,4,4,4, # 70 - 77 + 4,4,4,4,4,4,4,4, # 78 - 7f + 5,5,5,5,5,5,5,5, # 80 - 87 + 5,5,5,5,5,5,1,3, # 88 - 8f + 5,5,5,5,5,5,5,5, # 90 - 97 + 5,5,5,5,5,5,5,5, # 98 - 9f + 5,2,2,2,2,2,2,2, # a0 - a7 + 2,2,2,2,2,2,2,2, # a8 - af + 2,2,2,2,2,2,2,2, # b0 - b7 + 2,2,2,2,2,2,2,2, # b8 - bf + 2,2,2,2,2,2,2,2, # c0 - c7 + 2,2,2,2,2,2,2,2, # c8 - cf + 2,2,2,2,2,2,2,2, # d0 - d7 + 2,2,2,2,2,2,2,2, # d8 - df + 0,0,0,0,0,0,0,0, # e0 - e7 + 0,0,0,0,0,0,0,0, # e8 - ef + 0,0,0,0,0,0,0,0, # f0 - f7 + 0,0,0,0,0,0,0,5 # f8 - ff +) + +EUCJP_ST = ( + 3, 4, 3, 5,MachineState.START,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,#00-07 + MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ITS_ME,MachineState.ITS_ME,MachineState.ITS_ME,MachineState.ITS_ME,#08-0f + MachineState.ITS_ME,MachineState.ITS_ME,MachineState.START,MachineState.ERROR,MachineState.START,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,#10-17 + MachineState.ERROR,MachineState.ERROR,MachineState.START,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR, 3,MachineState.ERROR,#18-1f + 3,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.START,MachineState.START,MachineState.START,MachineState.START#20-27 +) + +EUCJP_CHAR_LEN_TABLE = (2, 2, 2, 3, 1, 0) + +EUCJP_SM_MODEL = {'class_table': EUCJP_CLS, + 'class_factor': 6, + 'state_table': EUCJP_ST, + 'char_len_table': EUCJP_CHAR_LEN_TABLE, + 'name': 'EUC-JP'} + +# EUC-KR + +EUCKR_CLS = ( + 1,1,1,1,1,1,1,1, # 00 - 07 + 1,1,1,1,1,1,0,0, # 08 - 0f + 1,1,1,1,1,1,1,1, # 10 - 17 + 1,1,1,0,1,1,1,1, # 18 - 1f + 1,1,1,1,1,1,1,1, # 20 - 27 + 1,1,1,1,1,1,1,1, # 28 - 2f + 1,1,1,1,1,1,1,1, # 30 - 37 + 1,1,1,1,1,1,1,1, # 38 - 3f + 1,1,1,1,1,1,1,1, # 40 - 47 + 1,1,1,1,1,1,1,1, # 48 - 4f + 1,1,1,1,1,1,1,1, # 50 - 57 + 1,1,1,1,1,1,1,1, # 58 - 5f + 1,1,1,1,1,1,1,1, # 60 - 67 + 1,1,1,1,1,1,1,1, # 68 - 6f + 1,1,1,1,1,1,1,1, # 70 - 77 + 1,1,1,1,1,1,1,1, # 78 - 7f + 0,0,0,0,0,0,0,0, # 80 - 87 + 0,0,0,0,0,0,0,0, # 88 - 8f + 0,0,0,0,0,0,0,0, # 90 - 97 + 0,0,0,0,0,0,0,0, # 98 - 9f + 0,2,2,2,2,2,2,2, # a0 - a7 + 2,2,2,2,2,3,3,3, # a8 - af + 2,2,2,2,2,2,2,2, # b0 - b7 + 2,2,2,2,2,2,2,2, # b8 - bf + 2,2,2,2,2,2,2,2, # c0 - c7 + 2,3,2,2,2,2,2,2, # c8 - cf + 2,2,2,2,2,2,2,2, # d0 - d7 + 2,2,2,2,2,2,2,2, # d8 - df + 2,2,2,2,2,2,2,2, # e0 - e7 + 2,2,2,2,2,2,2,2, # e8 - ef + 2,2,2,2,2,2,2,2, # f0 - f7 + 2,2,2,2,2,2,2,0 # f8 - ff +) + +EUCKR_ST = ( + MachineState.ERROR,MachineState.START, 3,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,#00-07 + MachineState.ITS_ME,MachineState.ITS_ME,MachineState.ITS_ME,MachineState.ITS_ME,MachineState.ERROR,MachineState.ERROR,MachineState.START,MachineState.START #08-0f +) + +EUCKR_CHAR_LEN_TABLE = (0, 1, 2, 0) + +EUCKR_SM_MODEL = {'class_table': EUCKR_CLS, + 'class_factor': 4, + 'state_table': EUCKR_ST, + 'char_len_table': EUCKR_CHAR_LEN_TABLE, + 'name': 'EUC-KR'} + +# EUC-TW + +EUCTW_CLS = ( + 2,2,2,2,2,2,2,2, # 00 - 07 + 2,2,2,2,2,2,0,0, # 08 - 0f + 2,2,2,2,2,2,2,2, # 10 - 17 + 2,2,2,0,2,2,2,2, # 18 - 1f + 2,2,2,2,2,2,2,2, # 20 - 27 + 2,2,2,2,2,2,2,2, # 28 - 2f + 2,2,2,2,2,2,2,2, # 30 - 37 + 2,2,2,2,2,2,2,2, # 38 - 3f + 2,2,2,2,2,2,2,2, # 40 - 47 + 2,2,2,2,2,2,2,2, # 48 - 4f + 2,2,2,2,2,2,2,2, # 50 - 57 + 2,2,2,2,2,2,2,2, # 58 - 5f + 2,2,2,2,2,2,2,2, # 60 - 67 + 2,2,2,2,2,2,2,2, # 68 - 6f + 2,2,2,2,2,2,2,2, # 70 - 77 + 2,2,2,2,2,2,2,2, # 78 - 7f + 0,0,0,0,0,0,0,0, # 80 - 87 + 0,0,0,0,0,0,6,0, # 88 - 8f + 0,0,0,0,0,0,0,0, # 90 - 97 + 0,0,0,0,0,0,0,0, # 98 - 9f + 0,3,4,4,4,4,4,4, # a0 - a7 + 5,5,1,1,1,1,1,1, # a8 - af + 1,1,1,1,1,1,1,1, # b0 - b7 + 1,1,1,1,1,1,1,1, # b8 - bf + 1,1,3,1,3,3,3,3, # c0 - c7 + 3,3,3,3,3,3,3,3, # c8 - cf + 3,3,3,3,3,3,3,3, # d0 - d7 + 3,3,3,3,3,3,3,3, # d8 - df + 3,3,3,3,3,3,3,3, # e0 - e7 + 3,3,3,3,3,3,3,3, # e8 - ef + 3,3,3,3,3,3,3,3, # f0 - f7 + 3,3,3,3,3,3,3,0 # f8 - ff +) + +EUCTW_ST = ( + MachineState.ERROR,MachineState.ERROR,MachineState.START, 3, 3, 3, 4,MachineState.ERROR,#00-07 + MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ITS_ME,MachineState.ITS_ME,#08-0f + MachineState.ITS_ME,MachineState.ITS_ME,MachineState.ITS_ME,MachineState.ITS_ME,MachineState.ITS_ME,MachineState.ERROR,MachineState.START,MachineState.ERROR,#10-17 + MachineState.START,MachineState.START,MachineState.START,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,#18-1f + 5,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.START,MachineState.ERROR,MachineState.START,MachineState.START,#20-27 + MachineState.START,MachineState.ERROR,MachineState.START,MachineState.START,MachineState.START,MachineState.START,MachineState.START,MachineState.START #28-2f +) + +EUCTW_CHAR_LEN_TABLE = (0, 0, 1, 2, 2, 2, 3) + +EUCTW_SM_MODEL = {'class_table': EUCTW_CLS, + 'class_factor': 7, + 'state_table': EUCTW_ST, + 'char_len_table': EUCTW_CHAR_LEN_TABLE, + 'name': 'x-euc-tw'} + +# GB2312 + +GB2312_CLS = ( + 1,1,1,1,1,1,1,1, # 00 - 07 + 1,1,1,1,1,1,0,0, # 08 - 0f + 1,1,1,1,1,1,1,1, # 10 - 17 + 1,1,1,0,1,1,1,1, # 18 - 1f + 1,1,1,1,1,1,1,1, # 20 - 27 + 1,1,1,1,1,1,1,1, # 28 - 2f + 3,3,3,3,3,3,3,3, # 30 - 37 + 3,3,1,1,1,1,1,1, # 38 - 3f + 2,2,2,2,2,2,2,2, # 40 - 47 + 2,2,2,2,2,2,2,2, # 48 - 4f + 2,2,2,2,2,2,2,2, # 50 - 57 + 2,2,2,2,2,2,2,2, # 58 - 5f + 2,2,2,2,2,2,2,2, # 60 - 67 + 2,2,2,2,2,2,2,2, # 68 - 6f + 2,2,2,2,2,2,2,2, # 70 - 77 + 2,2,2,2,2,2,2,4, # 78 - 7f + 5,6,6,6,6,6,6,6, # 80 - 87 + 6,6,6,6,6,6,6,6, # 88 - 8f + 6,6,6,6,6,6,6,6, # 90 - 97 + 6,6,6,6,6,6,6,6, # 98 - 9f + 6,6,6,6,6,6,6,6, # a0 - a7 + 6,6,6,6,6,6,6,6, # a8 - af + 6,6,6,6,6,6,6,6, # b0 - b7 + 6,6,6,6,6,6,6,6, # b8 - bf + 6,6,6,6,6,6,6,6, # c0 - c7 + 6,6,6,6,6,6,6,6, # c8 - cf + 6,6,6,6,6,6,6,6, # d0 - d7 + 6,6,6,6,6,6,6,6, # d8 - df + 6,6,6,6,6,6,6,6, # e0 - e7 + 6,6,6,6,6,6,6,6, # e8 - ef + 6,6,6,6,6,6,6,6, # f0 - f7 + 6,6,6,6,6,6,6,0 # f8 - ff +) + +GB2312_ST = ( + MachineState.ERROR,MachineState.START,MachineState.START,MachineState.START,MachineState.START,MachineState.START, 3,MachineState.ERROR,#00-07 + MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ITS_ME,MachineState.ITS_ME,#08-0f + MachineState.ITS_ME,MachineState.ITS_ME,MachineState.ITS_ME,MachineState.ITS_ME,MachineState.ITS_ME,MachineState.ERROR,MachineState.ERROR,MachineState.START,#10-17 + 4,MachineState.ERROR,MachineState.START,MachineState.START,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,#18-1f + MachineState.ERROR,MachineState.ERROR, 5,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ITS_ME,MachineState.ERROR,#20-27 + MachineState.ERROR,MachineState.ERROR,MachineState.START,MachineState.START,MachineState.START,MachineState.START,MachineState.START,MachineState.START #28-2f +) + +# To be accurate, the length of class 6 can be either 2 or 4. +# But it is not necessary to discriminate between the two since +# it is used for frequency analysis only, and we are validating +# each code range there as well. So it is safe to set it to be +# 2 here. +GB2312_CHAR_LEN_TABLE = (0, 1, 1, 1, 1, 1, 2) + +GB2312_SM_MODEL = {'class_table': GB2312_CLS, + 'class_factor': 7, + 'state_table': GB2312_ST, + 'char_len_table': GB2312_CHAR_LEN_TABLE, + 'name': 'GB2312'} + +# Shift_JIS + +SJIS_CLS = ( + 1,1,1,1,1,1,1,1, # 00 - 07 + 1,1,1,1,1,1,0,0, # 08 - 0f + 1,1,1,1,1,1,1,1, # 10 - 17 + 1,1,1,0,1,1,1,1, # 18 - 1f + 1,1,1,1,1,1,1,1, # 20 - 27 + 1,1,1,1,1,1,1,1, # 28 - 2f + 1,1,1,1,1,1,1,1, # 30 - 37 + 1,1,1,1,1,1,1,1, # 38 - 3f + 2,2,2,2,2,2,2,2, # 40 - 47 + 2,2,2,2,2,2,2,2, # 48 - 4f + 2,2,2,2,2,2,2,2, # 50 - 57 + 2,2,2,2,2,2,2,2, # 58 - 5f + 2,2,2,2,2,2,2,2, # 60 - 67 + 2,2,2,2,2,2,2,2, # 68 - 6f + 2,2,2,2,2,2,2,2, # 70 - 77 + 2,2,2,2,2,2,2,1, # 78 - 7f + 3,3,3,3,3,2,2,3, # 80 - 87 + 3,3,3,3,3,3,3,3, # 88 - 8f + 3,3,3,3,3,3,3,3, # 90 - 97 + 3,3,3,3,3,3,3,3, # 98 - 9f + #0xa0 is illegal in sjis encoding, but some pages does + #contain such byte. We need to be more error forgiven. + 2,2,2,2,2,2,2,2, # a0 - a7 + 2,2,2,2,2,2,2,2, # a8 - af + 2,2,2,2,2,2,2,2, # b0 - b7 + 2,2,2,2,2,2,2,2, # b8 - bf + 2,2,2,2,2,2,2,2, # c0 - c7 + 2,2,2,2,2,2,2,2, # c8 - cf + 2,2,2,2,2,2,2,2, # d0 - d7 + 2,2,2,2,2,2,2,2, # d8 - df + 3,3,3,3,3,3,3,3, # e0 - e7 + 3,3,3,3,3,4,4,4, # e8 - ef + 3,3,3,3,3,3,3,3, # f0 - f7 + 3,3,3,3,3,0,0,0) # f8 - ff + + +SJIS_ST = ( + MachineState.ERROR,MachineState.START,MachineState.START, 3,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,#00-07 + MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ITS_ME,MachineState.ITS_ME,MachineState.ITS_ME,MachineState.ITS_ME,#08-0f + MachineState.ITS_ME,MachineState.ITS_ME,MachineState.ERROR,MachineState.ERROR,MachineState.START,MachineState.START,MachineState.START,MachineState.START #10-17 +) + +SJIS_CHAR_LEN_TABLE = (0, 1, 1, 2, 0, 0) + +SJIS_SM_MODEL = {'class_table': SJIS_CLS, + 'class_factor': 6, + 'state_table': SJIS_ST, + 'char_len_table': SJIS_CHAR_LEN_TABLE, + 'name': 'Shift_JIS'} + +# UCS2-BE + +UCS2BE_CLS = ( + 0,0,0,0,0,0,0,0, # 00 - 07 + 0,0,1,0,0,2,0,0, # 08 - 0f + 0,0,0,0,0,0,0,0, # 10 - 17 + 0,0,0,3,0,0,0,0, # 18 - 1f + 0,0,0,0,0,0,0,0, # 20 - 27 + 0,3,3,3,3,3,0,0, # 28 - 2f + 0,0,0,0,0,0,0,0, # 30 - 37 + 0,0,0,0,0,0,0,0, # 38 - 3f + 0,0,0,0,0,0,0,0, # 40 - 47 + 0,0,0,0,0,0,0,0, # 48 - 4f + 0,0,0,0,0,0,0,0, # 50 - 57 + 0,0,0,0,0,0,0,0, # 58 - 5f + 0,0,0,0,0,0,0,0, # 60 - 67 + 0,0,0,0,0,0,0,0, # 68 - 6f + 0,0,0,0,0,0,0,0, # 70 - 77 + 0,0,0,0,0,0,0,0, # 78 - 7f + 0,0,0,0,0,0,0,0, # 80 - 87 + 0,0,0,0,0,0,0,0, # 88 - 8f + 0,0,0,0,0,0,0,0, # 90 - 97 + 0,0,0,0,0,0,0,0, # 98 - 9f + 0,0,0,0,0,0,0,0, # a0 - a7 + 0,0,0,0,0,0,0,0, # a8 - af + 0,0,0,0,0,0,0,0, # b0 - b7 + 0,0,0,0,0,0,0,0, # b8 - bf + 0,0,0,0,0,0,0,0, # c0 - c7 + 0,0,0,0,0,0,0,0, # c8 - cf + 0,0,0,0,0,0,0,0, # d0 - d7 + 0,0,0,0,0,0,0,0, # d8 - df + 0,0,0,0,0,0,0,0, # e0 - e7 + 0,0,0,0,0,0,0,0, # e8 - ef + 0,0,0,0,0,0,0,0, # f0 - f7 + 0,0,0,0,0,0,4,5 # f8 - ff +) + +UCS2BE_ST = ( + 5, 7, 7,MachineState.ERROR, 4, 3,MachineState.ERROR,MachineState.ERROR,#00-07 + MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ITS_ME,MachineState.ITS_ME,MachineState.ITS_ME,MachineState.ITS_ME,#08-0f + MachineState.ITS_ME,MachineState.ITS_ME, 6, 6, 6, 6,MachineState.ERROR,MachineState.ERROR,#10-17 + 6, 6, 6, 6, 6,MachineState.ITS_ME, 6, 6,#18-1f + 6, 6, 6, 6, 5, 7, 7,MachineState.ERROR,#20-27 + 5, 8, 6, 6,MachineState.ERROR, 6, 6, 6,#28-2f + 6, 6, 6, 6,MachineState.ERROR,MachineState.ERROR,MachineState.START,MachineState.START #30-37 +) + +UCS2BE_CHAR_LEN_TABLE = (2, 2, 2, 0, 2, 2) + +UCS2BE_SM_MODEL = {'class_table': UCS2BE_CLS, + 'class_factor': 6, + 'state_table': UCS2BE_ST, + 'char_len_table': UCS2BE_CHAR_LEN_TABLE, + 'name': 'UTF-16BE'} + +# UCS2-LE + +UCS2LE_CLS = ( + 0,0,0,0,0,0,0,0, # 00 - 07 + 0,0,1,0,0,2,0,0, # 08 - 0f + 0,0,0,0,0,0,0,0, # 10 - 17 + 0,0,0,3,0,0,0,0, # 18 - 1f + 0,0,0,0,0,0,0,0, # 20 - 27 + 0,3,3,3,3,3,0,0, # 28 - 2f + 0,0,0,0,0,0,0,0, # 30 - 37 + 0,0,0,0,0,0,0,0, # 38 - 3f + 0,0,0,0,0,0,0,0, # 40 - 47 + 0,0,0,0,0,0,0,0, # 48 - 4f + 0,0,0,0,0,0,0,0, # 50 - 57 + 0,0,0,0,0,0,0,0, # 58 - 5f + 0,0,0,0,0,0,0,0, # 60 - 67 + 0,0,0,0,0,0,0,0, # 68 - 6f + 0,0,0,0,0,0,0,0, # 70 - 77 + 0,0,0,0,0,0,0,0, # 78 - 7f + 0,0,0,0,0,0,0,0, # 80 - 87 + 0,0,0,0,0,0,0,0, # 88 - 8f + 0,0,0,0,0,0,0,0, # 90 - 97 + 0,0,0,0,0,0,0,0, # 98 - 9f + 0,0,0,0,0,0,0,0, # a0 - a7 + 0,0,0,0,0,0,0,0, # a8 - af + 0,0,0,0,0,0,0,0, # b0 - b7 + 0,0,0,0,0,0,0,0, # b8 - bf + 0,0,0,0,0,0,0,0, # c0 - c7 + 0,0,0,0,0,0,0,0, # c8 - cf + 0,0,0,0,0,0,0,0, # d0 - d7 + 0,0,0,0,0,0,0,0, # d8 - df + 0,0,0,0,0,0,0,0, # e0 - e7 + 0,0,0,0,0,0,0,0, # e8 - ef + 0,0,0,0,0,0,0,0, # f0 - f7 + 0,0,0,0,0,0,4,5 # f8 - ff +) + +UCS2LE_ST = ( + 6, 6, 7, 6, 4, 3,MachineState.ERROR,MachineState.ERROR,#00-07 + MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ITS_ME,MachineState.ITS_ME,MachineState.ITS_ME,MachineState.ITS_ME,#08-0f + MachineState.ITS_ME,MachineState.ITS_ME, 5, 5, 5,MachineState.ERROR,MachineState.ITS_ME,MachineState.ERROR,#10-17 + 5, 5, 5,MachineState.ERROR, 5,MachineState.ERROR, 6, 6,#18-1f + 7, 6, 8, 8, 5, 5, 5,MachineState.ERROR,#20-27 + 5, 5, 5,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR, 5, 5,#28-2f + 5, 5, 5,MachineState.ERROR, 5,MachineState.ERROR,MachineState.START,MachineState.START #30-37 +) + +UCS2LE_CHAR_LEN_TABLE = (2, 2, 2, 2, 2, 2) + +UCS2LE_SM_MODEL = {'class_table': UCS2LE_CLS, + 'class_factor': 6, + 'state_table': UCS2LE_ST, + 'char_len_table': UCS2LE_CHAR_LEN_TABLE, + 'name': 'UTF-16LE'} + +# UTF-8 + +UTF8_CLS = ( + 1,1,1,1,1,1,1,1, # 00 - 07 #allow 0x00 as a legal value + 1,1,1,1,1,1,0,0, # 08 - 0f + 1,1,1,1,1,1,1,1, # 10 - 17 + 1,1,1,0,1,1,1,1, # 18 - 1f + 1,1,1,1,1,1,1,1, # 20 - 27 + 1,1,1,1,1,1,1,1, # 28 - 2f + 1,1,1,1,1,1,1,1, # 30 - 37 + 1,1,1,1,1,1,1,1, # 38 - 3f + 1,1,1,1,1,1,1,1, # 40 - 47 + 1,1,1,1,1,1,1,1, # 48 - 4f + 1,1,1,1,1,1,1,1, # 50 - 57 + 1,1,1,1,1,1,1,1, # 58 - 5f + 1,1,1,1,1,1,1,1, # 60 - 67 + 1,1,1,1,1,1,1,1, # 68 - 6f + 1,1,1,1,1,1,1,1, # 70 - 77 + 1,1,1,1,1,1,1,1, # 78 - 7f + 2,2,2,2,3,3,3,3, # 80 - 87 + 4,4,4,4,4,4,4,4, # 88 - 8f + 4,4,4,4,4,4,4,4, # 90 - 97 + 4,4,4,4,4,4,4,4, # 98 - 9f + 5,5,5,5,5,5,5,5, # a0 - a7 + 5,5,5,5,5,5,5,5, # a8 - af + 5,5,5,5,5,5,5,5, # b0 - b7 + 5,5,5,5,5,5,5,5, # b8 - bf + 0,0,6,6,6,6,6,6, # c0 - c7 + 6,6,6,6,6,6,6,6, # c8 - cf + 6,6,6,6,6,6,6,6, # d0 - d7 + 6,6,6,6,6,6,6,6, # d8 - df + 7,8,8,8,8,8,8,8, # e0 - e7 + 8,8,8,8,8,9,8,8, # e8 - ef + 10,11,11,11,11,11,11,11, # f0 - f7 + 12,13,13,13,14,15,0,0 # f8 - ff +) + +UTF8_ST = ( + MachineState.ERROR,MachineState.START,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR, 12, 10,#00-07 + 9, 11, 8, 7, 6, 5, 4, 3,#08-0f + MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,#10-17 + MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,#18-1f + MachineState.ITS_ME,MachineState.ITS_ME,MachineState.ITS_ME,MachineState.ITS_ME,MachineState.ITS_ME,MachineState.ITS_ME,MachineState.ITS_ME,MachineState.ITS_ME,#20-27 + MachineState.ITS_ME,MachineState.ITS_ME,MachineState.ITS_ME,MachineState.ITS_ME,MachineState.ITS_ME,MachineState.ITS_ME,MachineState.ITS_ME,MachineState.ITS_ME,#28-2f + MachineState.ERROR,MachineState.ERROR, 5, 5, 5, 5,MachineState.ERROR,MachineState.ERROR,#30-37 + MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,#38-3f + MachineState.ERROR,MachineState.ERROR,MachineState.ERROR, 5, 5, 5,MachineState.ERROR,MachineState.ERROR,#40-47 + MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,#48-4f + MachineState.ERROR,MachineState.ERROR, 7, 7, 7, 7,MachineState.ERROR,MachineState.ERROR,#50-57 + MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,#58-5f + MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR, 7, 7,MachineState.ERROR,MachineState.ERROR,#60-67 + MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,#68-6f + MachineState.ERROR,MachineState.ERROR, 9, 9, 9, 9,MachineState.ERROR,MachineState.ERROR,#70-77 + MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,#78-7f + MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR, 9,MachineState.ERROR,MachineState.ERROR,#80-87 + MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,#88-8f + MachineState.ERROR,MachineState.ERROR, 12, 12, 12, 12,MachineState.ERROR,MachineState.ERROR,#90-97 + MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,#98-9f + MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR, 12,MachineState.ERROR,MachineState.ERROR,#a0-a7 + MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,#a8-af + MachineState.ERROR,MachineState.ERROR, 12, 12, 12,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,#b0-b7 + MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,#b8-bf + MachineState.ERROR,MachineState.ERROR,MachineState.START,MachineState.START,MachineState.START,MachineState.START,MachineState.ERROR,MachineState.ERROR,#c0-c7 + MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR #c8-cf +) + +UTF8_CHAR_LEN_TABLE = (0, 1, 0, 0, 0, 0, 2, 3, 3, 3, 4, 4, 5, 5, 6, 6) + +UTF8_SM_MODEL = {'class_table': UTF8_CLS, + 'class_factor': 16, + 'state_table': UTF8_ST, + 'char_len_table': UTF8_CHAR_LEN_TABLE, + 'name': 'UTF-8'} diff --git a/venv/Lib/site-packages/chardet/sbcharsetprober.py b/venv/Lib/site-packages/chardet/sbcharsetprober.py new file mode 100644 index 000000000..0adb51de5 --- /dev/null +++ b/venv/Lib/site-packages/chardet/sbcharsetprober.py @@ -0,0 +1,132 @@ +######################## BEGIN LICENSE BLOCK ######################## +# The Original Code is Mozilla Universal charset detector code. +# +# The Initial Developer of the Original Code is +# Netscape Communications Corporation. +# Portions created by the Initial Developer are Copyright (C) 2001 +# the Initial Developer. All Rights Reserved. +# +# Contributor(s): +# Mark Pilgrim - port to Python +# Shy Shalom - original C code +# +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; either +# version 2.1 of the License, or (at your option) any later version. +# +# This library 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 +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this library; if not, write to the Free Software +# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA +# 02110-1301 USA +######################### END LICENSE BLOCK ######################### + +from .charsetprober import CharSetProber +from .enums import CharacterCategory, ProbingState, SequenceLikelihood + + +class SingleByteCharSetProber(CharSetProber): + SAMPLE_SIZE = 64 + SB_ENOUGH_REL_THRESHOLD = 1024 # 0.25 * SAMPLE_SIZE^2 + POSITIVE_SHORTCUT_THRESHOLD = 0.95 + NEGATIVE_SHORTCUT_THRESHOLD = 0.05 + + def __init__(self, model, reversed=False, name_prober=None): + super(SingleByteCharSetProber, self).__init__() + self._model = model + # TRUE if we need to reverse every pair in the model lookup + self._reversed = reversed + # Optional auxiliary prober for name decision + self._name_prober = name_prober + self._last_order = None + self._seq_counters = None + self._total_seqs = None + self._total_char = None + self._freq_char = None + self.reset() + + def reset(self): + super(SingleByteCharSetProber, self).reset() + # char order of last character + self._last_order = 255 + self._seq_counters = [0] * SequenceLikelihood.get_num_categories() + self._total_seqs = 0 + self._total_char = 0 + # characters that fall in our sampling range + self._freq_char = 0 + + @property + def charset_name(self): + if self._name_prober: + return self._name_prober.charset_name + else: + return self._model['charset_name'] + + @property + def language(self): + if self._name_prober: + return self._name_prober.language + else: + return self._model.get('language') + + def feed(self, byte_str): + if not self._model['keep_english_letter']: + byte_str = self.filter_international_words(byte_str) + if not byte_str: + return self.state + char_to_order_map = self._model['char_to_order_map'] + for i, c in enumerate(byte_str): + # XXX: Order is in range 1-64, so one would think we want 0-63 here, + # but that leads to 27 more test failures than before. + order = char_to_order_map[c] + # XXX: This was SYMBOL_CAT_ORDER before, with a value of 250, but + # CharacterCategory.SYMBOL is actually 253, so we use CONTROL + # to make it closer to the original intent. The only difference + # is whether or not we count digits and control characters for + # _total_char purposes. + if order < CharacterCategory.CONTROL: + self._total_char += 1 + if order < self.SAMPLE_SIZE: + self._freq_char += 1 + if self._last_order < self.SAMPLE_SIZE: + self._total_seqs += 1 + if not self._reversed: + i = (self._last_order * self.SAMPLE_SIZE) + order + model = self._model['precedence_matrix'][i] + else: # reverse the order of the letters in the lookup + i = (order * self.SAMPLE_SIZE) + self._last_order + model = self._model['precedence_matrix'][i] + self._seq_counters[model] += 1 + self._last_order = order + + charset_name = self._model['charset_name'] + if self.state == ProbingState.DETECTING: + if self._total_seqs > self.SB_ENOUGH_REL_THRESHOLD: + confidence = self.get_confidence() + if confidence > self.POSITIVE_SHORTCUT_THRESHOLD: + self.logger.debug('%s confidence = %s, we have a winner', + charset_name, confidence) + self._state = ProbingState.FOUND_IT + elif confidence < self.NEGATIVE_SHORTCUT_THRESHOLD: + self.logger.debug('%s confidence = %s, below negative ' + 'shortcut threshhold %s', charset_name, + confidence, + self.NEGATIVE_SHORTCUT_THRESHOLD) + self._state = ProbingState.NOT_ME + + return self.state + + def get_confidence(self): + r = 0.01 + if self._total_seqs > 0: + r = ((1.0 * self._seq_counters[SequenceLikelihood.POSITIVE]) / + self._total_seqs / self._model['typical_positive_ratio']) + r = r * self._freq_char / self._total_char + if r >= 1.0: + r = 0.99 + return r diff --git a/venv/Lib/site-packages/requests/packages/chardet/sbcsgroupprober.py b/venv/Lib/site-packages/chardet/sbcsgroupprober.py similarity index 70% rename from venv/Lib/site-packages/requests/packages/chardet/sbcsgroupprober.py rename to venv/Lib/site-packages/chardet/sbcsgroupprober.py index 1b6196cd1..98e95dc1a 100644 --- a/venv/Lib/site-packages/requests/packages/chardet/sbcsgroupprober.py +++ b/venv/Lib/site-packages/chardet/sbcsgroupprober.py @@ -33,16 +33,17 @@ from .langcyrillicmodel import (Win1251CyrillicModel, Koi8rModel, Ibm866Model, Ibm855Model) from .langgreekmodel import Latin7GreekModel, Win1253GreekModel from .langbulgarianmodel import Latin5BulgarianModel, Win1251BulgarianModel -from .langhungarianmodel import Latin2HungarianModel, Win1250HungarianModel +# from .langhungarianmodel import Latin2HungarianModel, Win1250HungarianModel from .langthaimodel import TIS620ThaiModel from .langhebrewmodel import Win1255HebrewModel from .hebrewprober import HebrewProber +from .langturkishmodel import Latin5TurkishModel class SBCSGroupProber(CharSetGroupProber): def __init__(self): - CharSetGroupProber.__init__(self) - self._mProbers = [ + super(SBCSGroupProber, self).__init__() + self.probers = [ SingleByteCharSetProber(Win1251CyrillicModel), SingleByteCharSetProber(Koi8rModel), SingleByteCharSetProber(Latin5CyrillicModel), @@ -53,17 +54,20 @@ class SBCSGroupProber(CharSetGroupProber): SingleByteCharSetProber(Win1253GreekModel), SingleByteCharSetProber(Latin5BulgarianModel), SingleByteCharSetProber(Win1251BulgarianModel), - SingleByteCharSetProber(Latin2HungarianModel), - SingleByteCharSetProber(Win1250HungarianModel), + # TODO: Restore Hungarian encodings (iso-8859-2 and windows-1250) + # after we retrain model. + # SingleByteCharSetProber(Latin2HungarianModel), + # SingleByteCharSetProber(Win1250HungarianModel), SingleByteCharSetProber(TIS620ThaiModel), + SingleByteCharSetProber(Latin5TurkishModel), ] - hebrewProber = HebrewProber() - logicalHebrewProber = SingleByteCharSetProber(Win1255HebrewModel, - False, hebrewProber) - visualHebrewProber = SingleByteCharSetProber(Win1255HebrewModel, True, - hebrewProber) - hebrewProber.set_model_probers(logicalHebrewProber, visualHebrewProber) - self._mProbers.extend([hebrewProber, logicalHebrewProber, - visualHebrewProber]) + hebrew_prober = HebrewProber() + logical_hebrew_prober = SingleByteCharSetProber(Win1255HebrewModel, + False, hebrew_prober) + visual_hebrew_prober = SingleByteCharSetProber(Win1255HebrewModel, True, + hebrew_prober) + hebrew_prober.set_model_probers(logical_hebrew_prober, visual_hebrew_prober) + self.probers.extend([hebrew_prober, logical_hebrew_prober, + visual_hebrew_prober]) self.reset() diff --git a/venv/Lib/site-packages/chardet/sjisprober.py b/venv/Lib/site-packages/chardet/sjisprober.py new file mode 100644 index 000000000..9e29623bd --- /dev/null +++ b/venv/Lib/site-packages/chardet/sjisprober.py @@ -0,0 +1,92 @@ +######################## BEGIN LICENSE BLOCK ######################## +# The Original Code is mozilla.org code. +# +# The Initial Developer of the Original Code is +# Netscape Communications Corporation. +# Portions created by the Initial Developer are Copyright (C) 1998 +# the Initial Developer. All Rights Reserved. +# +# Contributor(s): +# Mark Pilgrim - port to Python +# +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; either +# version 2.1 of the License, or (at your option) any later version. +# +# This library 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 +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this library; if not, write to the Free Software +# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA +# 02110-1301 USA +######################### END LICENSE BLOCK ######################### + +from .mbcharsetprober import MultiByteCharSetProber +from .codingstatemachine import CodingStateMachine +from .chardistribution import SJISDistributionAnalysis +from .jpcntx import SJISContextAnalysis +from .mbcssm import SJIS_SM_MODEL +from .enums import ProbingState, MachineState + + +class SJISProber(MultiByteCharSetProber): + def __init__(self): + super(SJISProber, self).__init__() + self.coding_sm = CodingStateMachine(SJIS_SM_MODEL) + self.distribution_analyzer = SJISDistributionAnalysis() + self.context_analyzer = SJISContextAnalysis() + self.reset() + + def reset(self): + super(SJISProber, self).reset() + self.context_analyzer.reset() + + @property + def charset_name(self): + return self.context_analyzer.charset_name + + @property + def language(self): + return "Japanese" + + def feed(self, byte_str): + for i in range(len(byte_str)): + coding_state = self.coding_sm.next_state(byte_str[i]) + if coding_state == MachineState.ERROR: + self.logger.debug('%s %s prober hit error at byte %s', + self.charset_name, self.language, i) + self._state = ProbingState.NOT_ME + break + elif coding_state == MachineState.ITS_ME: + self._state = ProbingState.FOUND_IT + break + elif coding_state == MachineState.START: + char_len = self.coding_sm.get_current_charlen() + if i == 0: + self._last_char[1] = byte_str[0] + self.context_analyzer.feed(self._last_char[2 - char_len:], + char_len) + self.distribution_analyzer.feed(self._last_char, char_len) + else: + self.context_analyzer.feed(byte_str[i + 1 - char_len:i + 3 + - char_len], char_len) + self.distribution_analyzer.feed(byte_str[i - 1:i + 1], + char_len) + + self._last_char[0] = byte_str[-1] + + if self.state == ProbingState.DETECTING: + if (self.context_analyzer.got_enough_data() and + (self.get_confidence() > self.SHORTCUT_THRESHOLD)): + self._state = ProbingState.FOUND_IT + + return self.state + + def get_confidence(self): + context_conf = self.context_analyzer.get_confidence() + distrib_conf = self.distribution_analyzer.get_confidence() + return max(context_conf, distrib_conf) diff --git a/venv/Lib/site-packages/chardet/universaldetector.py b/venv/Lib/site-packages/chardet/universaldetector.py new file mode 100644 index 000000000..7b4e92d61 --- /dev/null +++ b/venv/Lib/site-packages/chardet/universaldetector.py @@ -0,0 +1,286 @@ +######################## BEGIN LICENSE BLOCK ######################## +# The Original Code is Mozilla Universal charset detector code. +# +# The Initial Developer of the Original Code is +# Netscape Communications Corporation. +# Portions created by the Initial Developer are Copyright (C) 2001 +# the Initial Developer. All Rights Reserved. +# +# Contributor(s): +# Mark Pilgrim - port to Python +# Shy Shalom - original C code +# +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; either +# version 2.1 of the License, or (at your option) any later version. +# +# This library 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 +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this library; if not, write to the Free Software +# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA +# 02110-1301 USA +######################### END LICENSE BLOCK ######################### +""" +Module containing the UniversalDetector detector class, which is the primary +class a user of ``chardet`` should use. + +:author: Mark Pilgrim (initial port to Python) +:author: Shy Shalom (original C code) +:author: Dan Blanchard (major refactoring for 3.0) +:author: Ian Cordasco +""" + + +import codecs +import logging +import re + +from .charsetgroupprober import CharSetGroupProber +from .enums import InputState, LanguageFilter, ProbingState +from .escprober import EscCharSetProber +from .latin1prober import Latin1Prober +from .mbcsgroupprober import MBCSGroupProber +from .sbcsgroupprober import SBCSGroupProber + + +class UniversalDetector(object): + """ + The ``UniversalDetector`` class underlies the ``chardet.detect`` function + and coordinates all of the different charset probers. + + To get a ``dict`` containing an encoding and its confidence, you can simply + run: + + .. code:: + + u = UniversalDetector() + u.feed(some_bytes) + u.close() + detected = u.result + + """ + + MINIMUM_THRESHOLD = 0.20 + HIGH_BYTE_DETECTOR = re.compile(b'[\x80-\xFF]') + ESC_DETECTOR = re.compile(b'(\033|~{)') + WIN_BYTE_DETECTOR = re.compile(b'[\x80-\x9F]') + ISO_WIN_MAP = {'iso-8859-1': 'Windows-1252', + 'iso-8859-2': 'Windows-1250', + 'iso-8859-5': 'Windows-1251', + 'iso-8859-6': 'Windows-1256', + 'iso-8859-7': 'Windows-1253', + 'iso-8859-8': 'Windows-1255', + 'iso-8859-9': 'Windows-1254', + 'iso-8859-13': 'Windows-1257'} + + def __init__(self, lang_filter=LanguageFilter.ALL): + self._esc_charset_prober = None + self._charset_probers = [] + self.result = None + self.done = None + self._got_data = None + self._input_state = None + self._last_char = None + self.lang_filter = lang_filter + self.logger = logging.getLogger(__name__) + self._has_win_bytes = None + self.reset() + + def reset(self): + """ + Reset the UniversalDetector and all of its probers back to their + initial states. This is called by ``__init__``, so you only need to + call this directly in between analyses of different documents. + """ + self.result = {'encoding': None, 'confidence': 0.0, 'language': None} + self.done = False + self._got_data = False + self._has_win_bytes = False + self._input_state = InputState.PURE_ASCII + self._last_char = b'' + if self._esc_charset_prober: + self._esc_charset_prober.reset() + for prober in self._charset_probers: + prober.reset() + + def feed(self, byte_str): + """ + Takes a chunk of a document and feeds it through all of the relevant + charset probers. + + After calling ``feed``, you can check the value of the ``done`` + attribute to see if you need to continue feeding the + ``UniversalDetector`` more data, or if it has made a prediction + (in the ``result`` attribute). + + .. note:: + You should always call ``close`` when you're done feeding in your + document if ``done`` is not already ``True``. + """ + if self.done: + return + + if not len(byte_str): + return + + if not isinstance(byte_str, bytearray): + byte_str = bytearray(byte_str) + + # First check for known BOMs, since these are guaranteed to be correct + if not self._got_data: + # If the data starts with BOM, we know it is UTF + if byte_str.startswith(codecs.BOM_UTF8): + # EF BB BF UTF-8 with BOM + self.result = {'encoding': "UTF-8-SIG", + 'confidence': 1.0, + 'language': ''} + elif byte_str.startswith((codecs.BOM_UTF32_LE, + codecs.BOM_UTF32_BE)): + # FF FE 00 00 UTF-32, little-endian BOM + # 00 00 FE FF UTF-32, big-endian BOM + self.result = {'encoding': "UTF-32", + 'confidence': 1.0, + 'language': ''} + elif byte_str.startswith(b'\xFE\xFF\x00\x00'): + # FE FF 00 00 UCS-4, unusual octet order BOM (3412) + self.result = {'encoding': "X-ISO-10646-UCS-4-3412", + 'confidence': 1.0, + 'language': ''} + elif byte_str.startswith(b'\x00\x00\xFF\xFE'): + # 00 00 FF FE UCS-4, unusual octet order BOM (2143) + self.result = {'encoding': "X-ISO-10646-UCS-4-2143", + 'confidence': 1.0, + 'language': ''} + elif byte_str.startswith((codecs.BOM_LE, codecs.BOM_BE)): + # FF FE UTF-16, little endian BOM + # FE FF UTF-16, big endian BOM + self.result = {'encoding': "UTF-16", + 'confidence': 1.0, + 'language': ''} + + self._got_data = True + if self.result['encoding'] is not None: + self.done = True + return + + # If none of those matched and we've only see ASCII so far, check + # for high bytes and escape sequences + if self._input_state == InputState.PURE_ASCII: + if self.HIGH_BYTE_DETECTOR.search(byte_str): + self._input_state = InputState.HIGH_BYTE + elif self._input_state == InputState.PURE_ASCII and \ + self.ESC_DETECTOR.search(self._last_char + byte_str): + self._input_state = InputState.ESC_ASCII + + self._last_char = byte_str[-1:] + + # If we've seen escape sequences, use the EscCharSetProber, which + # uses a simple state machine to check for known escape sequences in + # HZ and ISO-2022 encodings, since those are the only encodings that + # use such sequences. + if self._input_state == InputState.ESC_ASCII: + if not self._esc_charset_prober: + self._esc_charset_prober = EscCharSetProber(self.lang_filter) + if self._esc_charset_prober.feed(byte_str) == ProbingState.FOUND_IT: + self.result = {'encoding': + self._esc_charset_prober.charset_name, + 'confidence': + self._esc_charset_prober.get_confidence(), + 'language': + self._esc_charset_prober.language} + self.done = True + # If we've seen high bytes (i.e., those with values greater than 127), + # we need to do more complicated checks using all our multi-byte and + # single-byte probers that are left. The single-byte probers + # use character bigram distributions to determine the encoding, whereas + # the multi-byte probers use a combination of character unigram and + # bigram distributions. + elif self._input_state == InputState.HIGH_BYTE: + if not self._charset_probers: + self._charset_probers = [MBCSGroupProber(self.lang_filter)] + # If we're checking non-CJK encodings, use single-byte prober + if self.lang_filter & LanguageFilter.NON_CJK: + self._charset_probers.append(SBCSGroupProber()) + self._charset_probers.append(Latin1Prober()) + for prober in self._charset_probers: + if prober.feed(byte_str) == ProbingState.FOUND_IT: + self.result = {'encoding': prober.charset_name, + 'confidence': prober.get_confidence(), + 'language': prober.language} + self.done = True + break + if self.WIN_BYTE_DETECTOR.search(byte_str): + self._has_win_bytes = True + + def close(self): + """ + Stop analyzing the current document and come up with a final + prediction. + + :returns: The ``result`` attribute, a ``dict`` with the keys + `encoding`, `confidence`, and `language`. + """ + # Don't bother with checks if we're already done + if self.done: + return self.result + self.done = True + + if not self._got_data: + self.logger.debug('no data received!') + + # Default to ASCII if it is all we've seen so far + elif self._input_state == InputState.PURE_ASCII: + self.result = {'encoding': 'ascii', + 'confidence': 1.0, + 'language': ''} + + # If we have seen non-ASCII, return the best that met MINIMUM_THRESHOLD + elif self._input_state == InputState.HIGH_BYTE: + prober_confidence = None + max_prober_confidence = 0.0 + max_prober = None + for prober in self._charset_probers: + if not prober: + continue + prober_confidence = prober.get_confidence() + if prober_confidence > max_prober_confidence: + max_prober_confidence = prober_confidence + max_prober = prober + if max_prober and (max_prober_confidence > self.MINIMUM_THRESHOLD): + charset_name = max_prober.charset_name + lower_charset_name = max_prober.charset_name.lower() + confidence = max_prober.get_confidence() + # Use Windows encoding name instead of ISO-8859 if we saw any + # extra Windows-specific bytes + if lower_charset_name.startswith('iso-8859'): + if self._has_win_bytes: + charset_name = self.ISO_WIN_MAP.get(lower_charset_name, + charset_name) + self.result = {'encoding': charset_name, + 'confidence': confidence, + 'language': max_prober.language} + + # Log all prober confidences if none met MINIMUM_THRESHOLD + if self.logger.getEffectiveLevel() == logging.DEBUG: + if self.result['encoding'] is None: + self.logger.debug('no probers hit minimum threshold') + for group_prober in self._charset_probers: + if not group_prober: + continue + if isinstance(group_prober, CharSetGroupProber): + for prober in group_prober.probers: + self.logger.debug('%s %s confidence = %s', + prober.charset_name, + prober.language, + prober.get_confidence()) + else: + self.logger.debug('%s %s confidence = %s', + prober.charset_name, + prober.language, + prober.get_confidence()) + return self.result diff --git a/venv/Lib/site-packages/requests/packages/chardet/utf8prober.py b/venv/Lib/site-packages/chardet/utf8prober.py similarity index 56% rename from venv/Lib/site-packages/requests/packages/chardet/utf8prober.py rename to venv/Lib/site-packages/chardet/utf8prober.py index 1c0bb5d8f..6c3196cc2 100644 --- a/venv/Lib/site-packages/requests/packages/chardet/utf8prober.py +++ b/venv/Lib/site-packages/chardet/utf8prober.py @@ -25,52 +25,58 @@ # 02110-1301 USA ######################### END LICENSE BLOCK ######################### -from . import constants from .charsetprober import CharSetProber +from .enums import ProbingState, MachineState from .codingstatemachine import CodingStateMachine -from .mbcssm import UTF8SMModel +from .mbcssm import UTF8_SM_MODEL -ONE_CHAR_PROB = 0.5 class UTF8Prober(CharSetProber): + ONE_CHAR_PROB = 0.5 + def __init__(self): - CharSetProber.__init__(self) - self._mCodingSM = CodingStateMachine(UTF8SMModel) + super(UTF8Prober, self).__init__() + self.coding_sm = CodingStateMachine(UTF8_SM_MODEL) + self._num_mb_chars = None self.reset() def reset(self): - CharSetProber.reset(self) - self._mCodingSM.reset() - self._mNumOfMBChar = 0 + super(UTF8Prober, self).reset() + self.coding_sm.reset() + self._num_mb_chars = 0 - def get_charset_name(self): + @property + def charset_name(self): return "utf-8" - def feed(self, aBuf): - for c in aBuf: - codingState = self._mCodingSM.next_state(c) - if codingState == constants.eError: - self._mState = constants.eNotMe - break - elif codingState == constants.eItsMe: - self._mState = constants.eFoundIt - break - elif codingState == constants.eStart: - if self._mCodingSM.get_current_charlen() >= 2: - self._mNumOfMBChar += 1 + @property + def language(self): + return "" - if self.get_state() == constants.eDetecting: - if self.get_confidence() > constants.SHORTCUT_THRESHOLD: - self._mState = constants.eFoundIt + def feed(self, byte_str): + for c in byte_str: + coding_state = self.coding_sm.next_state(c) + if coding_state == MachineState.ERROR: + self._state = ProbingState.NOT_ME + break + elif coding_state == MachineState.ITS_ME: + self._state = ProbingState.FOUND_IT + break + elif coding_state == MachineState.START: + if self.coding_sm.get_current_charlen() >= 2: + self._num_mb_chars += 1 - return self.get_state() + if self.state == ProbingState.DETECTING: + if self.get_confidence() > self.SHORTCUT_THRESHOLD: + self._state = ProbingState.FOUND_IT + + return self.state def get_confidence(self): unlike = 0.99 - if self._mNumOfMBChar < 6: - for i in range(0, self._mNumOfMBChar): - unlike = unlike * ONE_CHAR_PROB + if self._num_mb_chars < 6: + unlike *= self.ONE_CHAR_PROB ** self._num_mb_chars return 1.0 - unlike else: return unlike diff --git a/venv/Lib/site-packages/chardet/version.py b/venv/Lib/site-packages/chardet/version.py new file mode 100644 index 000000000..bb2a34a70 --- /dev/null +++ b/venv/Lib/site-packages/chardet/version.py @@ -0,0 +1,9 @@ +""" +This module exists only to simplify retrieving the version number of chardet +from within setup.py and from chardet subpackages. + +:author: Dan Blanchard (dan.blanchard@gmail.com) +""" + +__version__ = "3.0.4" +VERSION = __version__.split('.') diff --git a/venv/Lib/site-packages/firebase_admin-4.4.0.dist-info/INSTALLER b/venv/Lib/site-packages/firebase_admin-4.4.0.dist-info/INSTALLER new file mode 100644 index 000000000..a1b589e38 --- /dev/null +++ b/venv/Lib/site-packages/firebase_admin-4.4.0.dist-info/INSTALLER @@ -0,0 +1 @@ +pip diff --git a/venv/Lib/site-packages/firebase_admin-4.4.0.dist-info/LICENSE b/venv/Lib/site-packages/firebase_admin-4.4.0.dist-info/LICENSE new file mode 100644 index 000000000..261eeb9e9 --- /dev/null +++ b/venv/Lib/site-packages/firebase_admin-4.4.0.dist-info/LICENSE @@ -0,0 +1,201 @@ + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [yyyy] [name of copyright owner] + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. diff --git a/venv/Lib/site-packages/firebase_admin-4.4.0.dist-info/METADATA b/venv/Lib/site-packages/firebase_admin-4.4.0.dist-info/METADATA new file mode 100644 index 000000000..b168bea41 --- /dev/null +++ b/venv/Lib/site-packages/firebase_admin-4.4.0.dist-info/METADATA @@ -0,0 +1,27 @@ +Metadata-Version: 2.1 +Name: firebase-admin +Version: 4.4.0 +Summary: Firebase Admin Python SDK +Home-page: https://firebase.google.com/docs/admin/setup/ +Author: Firebase +License: Apache License 2.0 +Keywords: firebase cloud development +Platform: UNKNOWN +Classifier: Development Status :: 5 - Production/Stable +Classifier: Intended Audience :: Developers +Classifier: Topic :: Software Development :: Build Tools +Classifier: Programming Language :: Python :: 3 +Classifier: Programming Language :: Python :: 3.5 +Classifier: Programming Language :: Python :: 3.6 +Classifier: Programming Language :: Python :: 3.7 +Classifier: License :: OSI Approved :: Apache Software License +Requires-Python: >=3.5 +Requires-Dist: cachecontrol (>=0.12.6) +Requires-Dist: google-api-python-client (>=1.7.8) +Requires-Dist: google-cloud-storage (>=1.18.0) +Requires-Dist: google-api-core[grpc] (<2.0.0dev,>=1.14.0) ; platform_python_implementation != "PyPy" +Requires-Dist: google-cloud-firestore (>=1.4.0) ; platform_python_implementation != "PyPy" + +The Firebase Admin Python SDK enables server-side (backend) Python developers to integrate Firebase into their services and applications. + + diff --git a/venv/Lib/site-packages/firebase_admin-4.4.0.dist-info/RECORD b/venv/Lib/site-packages/firebase_admin-4.4.0.dist-info/RECORD new file mode 100644 index 000000000..0b2d9d260 --- /dev/null +++ b/venv/Lib/site-packages/firebase_admin-4.4.0.dist-info/RECORD @@ -0,0 +1,59 @@ +firebase_admin-4.4.0.dist-info/INSTALLER,sha256=zuuue4knoyJ-UwPPXg8fezS7VCrXJQrAP7zeNuwvFQg,4 +firebase_admin-4.4.0.dist-info/LICENSE,sha256=xx0jnfkXJvxRnG63LTGOxlggYnIysveWIZ6H3PNdCrQ,11357 +firebase_admin-4.4.0.dist-info/METADATA,sha256=-8pgZa6XSLYrRE4KAAIktoN9MNaTzBg8oczVmFMbOoE,1160 +firebase_admin-4.4.0.dist-info/RECORD,, +firebase_admin-4.4.0.dist-info/REQUESTED,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0 +firebase_admin-4.4.0.dist-info/WHEEL,sha256=EVRjI69F5qVjm_YgqcTXPnTAv3BfSUr0WVAHuSP3Xoo,92 +firebase_admin-4.4.0.dist-info/top_level.txt,sha256=j8IXOwvHIaefIBBzAehVx1lROs_uinrBtfYXG-wDO_A,15 +firebase_admin/__about__.py,sha256=5mU5mINso34PbcaxMmj1aX7BUjTyc8pgxAVfhEF8xZQ,808 +firebase_admin/__init__.py,sha256=PnuQ64TnrHDQdKtVAbVDMU9Pr9AuAJ2pOwrG-jjqxmg,11961 +firebase_admin/__pycache__/__about__.cpython-36.pyc,, +firebase_admin/__pycache__/__init__.cpython-36.pyc,, +firebase_admin/__pycache__/_auth_client.cpython-36.pyc,, +firebase_admin/__pycache__/_auth_providers.cpython-36.pyc,, +firebase_admin/__pycache__/_auth_utils.cpython-36.pyc,, +firebase_admin/__pycache__/_http_client.cpython-36.pyc,, +firebase_admin/__pycache__/_messaging_encoder.cpython-36.pyc,, +firebase_admin/__pycache__/_messaging_utils.cpython-36.pyc,, +firebase_admin/__pycache__/_rfc3339.cpython-36.pyc,, +firebase_admin/__pycache__/_sseclient.cpython-36.pyc,, +firebase_admin/__pycache__/_token_gen.cpython-36.pyc,, +firebase_admin/__pycache__/_user_identifier.cpython-36.pyc,, +firebase_admin/__pycache__/_user_import.cpython-36.pyc,, +firebase_admin/__pycache__/_user_mgt.cpython-36.pyc,, +firebase_admin/__pycache__/_utils.cpython-36.pyc,, +firebase_admin/__pycache__/auth.cpython-36.pyc,, +firebase_admin/__pycache__/credentials.cpython-36.pyc,, +firebase_admin/__pycache__/db.cpython-36.pyc,, +firebase_admin/__pycache__/exceptions.cpython-36.pyc,, +firebase_admin/__pycache__/firestore.cpython-36.pyc,, +firebase_admin/__pycache__/instance_id.cpython-36.pyc,, +firebase_admin/__pycache__/messaging.cpython-36.pyc,, +firebase_admin/__pycache__/ml.cpython-36.pyc,, +firebase_admin/__pycache__/project_management.cpython-36.pyc,, +firebase_admin/__pycache__/storage.cpython-36.pyc,, +firebase_admin/__pycache__/tenant_mgt.cpython-36.pyc,, +firebase_admin/_auth_client.py,sha256=Ni04rDESj1nJ44JxQKkMaErCX4y4BG5pgcT9tdov2NA,33179 +firebase_admin/_auth_providers.py,sha256=kf0_zIkUnnAq_pCvJN12oWJSqtafoOCoTRvmVBp7MUo,15358 +firebase_admin/_auth_utils.py,sha256=j1yI_0o7KxYDCpqux8rSiHtH2uA-2iekxdfAaT-OQFk,16481 +firebase_admin/_http_client.py,sha256=2NcFOqJBUfgtnbPjFZWlS7lIKkUC_DhTJJXr-f1GnLM,5459 +firebase_admin/_messaging_encoder.py,sha256=-F-59VH037rM7n5HVHiZujIGz73E0LCjABJjx8w1vuw,32878 +firebase_admin/_messaging_utils.py,sha256=8kPD2Vrxl-R3AVHt4O2puZa8HY5pf_cg6zwHlIUgtn0,23448 +firebase_admin/_rfc3339.py,sha256=mh_P5KPRwSEbzhryMfx5-CvVocnmc7wN8Q1YLplRwzw,3189 +firebase_admin/_sseclient.py,sha256=JgG34KhR_nMyAhqyyY6JUfhiHy9YUqNmKXP86wkiq5c,6886 +firebase_admin/_token_gen.py,sha256=AZAbBLW6IAUjORXNtu9PorkszAdooQ5kDDbCkDcayxM,17633 +firebase_admin/_user_identifier.py,sha256=jiV5Y-q99-35HE5PZ-V-FHhH-I2uOQeyjsqtfMoQ0Xk,2721 +firebase_admin/_user_import.py,sha256=7h4efZDR9LEsIuMRJbR4maJbLYi5DSi-DTy0xfi_7B0,17392 +firebase_admin/_user_mgt.py,sha256=w8trY-mHdGPfdOop0wS-f2_bXGwSH15NXEdES1UsXoA,32316 +firebase_admin/_utils.py,sha256=jxZ4wxp9dIAng5DmHAWhznbkQ8TFDn-nn42SddRi0As,13330 +firebase_admin/auth.py,sha256=7HYMDM3JYL12-rWmfdMWZkg4pLwc032NHB6y9wfYE6Q,35606 +firebase_admin/credentials.py,sha256=JH2HfY2tXBpyt1AzSEs2lGDZ0KAM4eOMx3OUB4XwsM8,7986 +firebase_admin/db.py,sha256=8Vnd-RXFdkdUSjAyRSRvJ2UNTTYxr7q-fOmoWKcgCbs,38298 +firebase_admin/exceptions.py,sha256=K6QCnP2fT2x23Na9-lYhq2AfU_yCkmsXmG7XCJkBZss,8503 +firebase_admin/firestore.py,sha256=ClQU0Bw6ZvlfpL8lvqWBz-deciSTTZ7KQDxPZ3YBuZo,2789 +firebase_admin/instance_id.py,sha256=CrJhUKrc-CZSziqB2QO54v7wG9ae2N6ziPZmoF6wSNk,3795 +firebase_admin/messaging.py,sha256=DrM0awnCwLKin3tN6uUEwQ6hZdxOhhHKDHVvtYyNQvU,18135 +firebase_admin/ml.py,sha256=VZUgL_L1yRZp1C_U00H-kv30rvokNXYAWVb6f1cwhqk,36536 +firebase_admin/project_management.py,sha256=0-8k-h6_mfR0NGK3pURxQtzWitNS3_1UnAQ2pDlkGek,24991 +firebase_admin/storage.py,sha256=lC7evcKOE033GCx-tt_Db2ZAPR0mamzxcUmq769E2ng,3335 +firebase_admin/tenant_mgt.py,sha256=1t-RHPRQP4zZFFmAdJLZalO89B9NWtbKsqPwh5DajV8,16976 diff --git a/venv/Lib/site-packages/requests/packages/urllib3/contrib/__init__.py b/venv/Lib/site-packages/firebase_admin-4.4.0.dist-info/REQUESTED similarity index 100% rename from venv/Lib/site-packages/requests/packages/urllib3/contrib/__init__.py rename to venv/Lib/site-packages/firebase_admin-4.4.0.dist-info/REQUESTED diff --git a/venv/Lib/site-packages/firebase_admin-4.4.0.dist-info/WHEEL b/venv/Lib/site-packages/firebase_admin-4.4.0.dist-info/WHEEL new file mode 100644 index 000000000..83ff02e96 --- /dev/null +++ b/venv/Lib/site-packages/firebase_admin-4.4.0.dist-info/WHEEL @@ -0,0 +1,5 @@ +Wheel-Version: 1.0 +Generator: bdist_wheel (0.35.1) +Root-Is-Purelib: true +Tag: py3-none-any + diff --git a/venv/Lib/site-packages/firebase_admin-4.4.0.dist-info/top_level.txt b/venv/Lib/site-packages/firebase_admin-4.4.0.dist-info/top_level.txt new file mode 100644 index 000000000..9b59c15ec --- /dev/null +++ b/venv/Lib/site-packages/firebase_admin-4.4.0.dist-info/top_level.txt @@ -0,0 +1 @@ +firebase_admin diff --git a/venv/Lib/site-packages/firebase_admin/__about__.py b/venv/Lib/site-packages/firebase_admin/__about__.py new file mode 100644 index 000000000..de6a75223 --- /dev/null +++ b/venv/Lib/site-packages/firebase_admin/__about__.py @@ -0,0 +1,21 @@ +# Copyright 2017 Google Inc. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +"""About information (version, etc) for Firebase Admin SDK.""" + +__version__ = '4.4.0' +__title__ = 'firebase_admin' +__author__ = 'Firebase' +__license__ = 'Apache License 2.0' +__url__ = 'https://firebase.google.com/docs/admin/setup/' diff --git a/venv/Lib/site-packages/firebase_admin/__init__.py b/venv/Lib/site-packages/firebase_admin/__init__.py new file mode 100644 index 000000000..7e3b2eab0 --- /dev/null +++ b/venv/Lib/site-packages/firebase_admin/__init__.py @@ -0,0 +1,309 @@ +# Copyright 2017 Google Inc. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +"""Firebase Admin SDK for Python.""" +import datetime +import json +import os +import threading + +from firebase_admin import credentials +from firebase_admin.__about__ import __version__ + + +_apps = {} +_apps_lock = threading.RLock() +_clock = datetime.datetime.utcnow + +_DEFAULT_APP_NAME = '[DEFAULT]' +_FIREBASE_CONFIG_ENV_VAR = 'FIREBASE_CONFIG' +_CONFIG_VALID_KEYS = ['databaseAuthVariableOverride', 'databaseURL', 'httpTimeout', 'projectId', + 'storageBucket'] + +def initialize_app(credential=None, options=None, name=_DEFAULT_APP_NAME): + """Initializes and returns a new App instance. + + Creates a new App instance using the specified options + and the app name. If an instance already exists by the same + app name a ValueError is raised. + If options are not provided an attempt is made to load the options from the environment. + This is done by looking up the ``FIREBASE_CONFIG`` environment variable. If the value of + the variable starts with ``"{"``, it is parsed as a JSON object. Otherwise it is treated + as a file name and the JSON content is read from the corresponding file. + Use this function whenever a new App instance is required. Do not directly invoke the + App constructor. + + Args: + credential: A credential object used to initialize the SDK (optional). If none is provided, + Google Application Default Credentials are used. + options: A dictionary of configuration options (optional). Supported options include + ``databaseURL``, ``storageBucket``, ``projectId``, ``databaseAuthVariableOverride``, + ``serviceAccountId`` and ``httpTimeout``. If ``httpTimeout`` is not set, the SDK + uses a default timeout of 120 seconds. + name: Name of the app (optional). + Returns: + App: A newly initialized instance of App. + + Raises: + ValueError: If the app name is already in use, or any of the + provided arguments are invalid. + """ + if credential is None: + credential = credentials.ApplicationDefault() + app = App(name, credential, options) + with _apps_lock: + if app.name not in _apps: + _apps[app.name] = app + return app + + if name == _DEFAULT_APP_NAME: + raise ValueError(( + 'The default Firebase app already exists. This means you called ' + 'initialize_app() more than once without providing an app name as ' + 'the second argument. In most cases you only need to call ' + 'initialize_app() once. But if you do want to initialize multiple ' + 'apps, pass a second argument to initialize_app() to give each app ' + 'a unique name.')) + + raise ValueError(( + 'Firebase app named "{0}" already exists. This means you called ' + 'initialize_app() more than once with the same app name as the ' + 'second argument. Make sure you provide a unique name every time ' + 'you call initialize_app().').format(name)) + + +def delete_app(app): + """Gracefully deletes an App instance. + + Args: + app: The app instance to be deleted. + + Raises: + ValueError: If the app is not initialized. + """ + if not isinstance(app, App): + raise ValueError('Illegal app argument type: "{}". Argument must be of ' + 'type App.'.format(type(app))) + with _apps_lock: + if _apps.get(app.name) is app: + del _apps[app.name] + app._cleanup() # pylint: disable=protected-access + return + if app.name == _DEFAULT_APP_NAME: + raise ValueError( + 'The default Firebase app is not initialized. Make sure to initialize ' + 'the default app by calling initialize_app().') + + raise ValueError( + ('Firebase app named "{0}" is not initialized. Make sure to initialize ' + 'the app by calling initialize_app() with your app name as the ' + 'second argument.').format(app.name)) + + +def get_app(name=_DEFAULT_APP_NAME): + """Retrieves an App instance by name. + + Args: + name: Name of the App instance to retrieve (optional). + + Returns: + App: An App instance with the given name. + + Raises: + ValueError: If the specified name is not a string, or if the specified + app does not exist. + """ + if not isinstance(name, str): + raise ValueError('Illegal app name argument type: "{}". App name ' + 'must be a string.'.format(type(name))) + with _apps_lock: + if name in _apps: + return _apps[name] + + if name == _DEFAULT_APP_NAME: + raise ValueError( + 'The default Firebase app does not exist. Make sure to initialize ' + 'the SDK by calling initialize_app().') + + raise ValueError( + ('Firebase app named "{0}" does not exist. Make sure to initialize ' + 'the SDK by calling initialize_app() with your app name as the ' + 'second argument.').format(name)) + + +class _AppOptions: + """A collection of configuration options for an App.""" + + def __init__(self, options): + if options is None: + options = self._load_from_environment() + + if not isinstance(options, dict): + raise ValueError('Illegal Firebase app options type: {0}. Options ' + 'must be a dictionary.'.format(type(options))) + self._options = options + + def get(self, key, default=None): + """Returns the option identified by the provided key.""" + return self._options.get(key, default) + + def _load_from_environment(self): + """Invoked when no options are passed to __init__, loads options from FIREBASE_CONFIG. + + If the value of the FIREBASE_CONFIG environment variable starts with "{" an attempt is made + to parse it as a JSON object, otherwise it is assumed to be pointing to a JSON file. + """ + + config_file = os.getenv(_FIREBASE_CONFIG_ENV_VAR) + if not config_file: + return {} + if config_file.startswith('{'): + json_str = config_file + else: + try: + with open(config_file, 'r') as json_file: + json_str = json_file.read() + except Exception as err: + raise ValueError('Unable to read file {}. {}'.format(config_file, err)) + try: + json_data = json.loads(json_str) + except Exception as err: + raise ValueError('JSON string "{0}" is not valid json. {1}'.format(json_str, err)) + return {k: v for k, v in json_data.items() if k in _CONFIG_VALID_KEYS} + + +class App: + """The entry point for Firebase Python SDK. + + Represents a Firebase app, while holding the configuration and state + common to all Firebase APIs. + """ + + def __init__(self, name, credential, options): + """Constructs a new App using the provided name and options. + + Args: + name: Name of the application. + credential: A credential object. + options: A dictionary of configuration options. + + Raises: + ValueError: If an argument is None or invalid. + """ + if not name or not isinstance(name, str): + raise ValueError('Illegal Firebase app name "{0}" provided. App name must be a ' + 'non-empty string.'.format(name)) + self._name = name + + if not isinstance(credential, credentials.Base): + raise ValueError('Illegal Firebase credential provided. App must be initialized ' + 'with a valid credential instance.') + self._credential = credential + self._options = _AppOptions(options) + self._lock = threading.RLock() + self._services = {} + + App._validate_project_id(self._options.get('projectId')) + self._project_id_initialized = False + + @classmethod + def _validate_project_id(cls, project_id): + if project_id is not None and not isinstance(project_id, str): + raise ValueError( + 'Invalid project ID: "{0}". project ID must be a string.'.format(project_id)) + + @property + def name(self): + return self._name + + @property + def credential(self): + return self._credential + + @property + def options(self): + return self._options + + @property + def project_id(self): + if not self._project_id_initialized: + self._project_id = self._lookup_project_id() + self._project_id_initialized = True + return self._project_id + + def _lookup_project_id(self): + """Looks up the Firebase project ID associated with an App. + + If a ``projectId`` is specified in app options, it is returned. Then tries to + get the project ID from the credential used to initialize the app. If that also fails, + attempts to look up the ``GOOGLE_CLOUD_PROJECT`` and ``GCLOUD_PROJECT`` environment + variables. + + Returns: + str: A project ID string or None. + """ + project_id = self._options.get('projectId') + if not project_id: + try: + project_id = self._credential.project_id + except AttributeError: + pass + if not project_id: + project_id = os.environ.get('GOOGLE_CLOUD_PROJECT', + os.environ.get('GCLOUD_PROJECT')) + App._validate_project_id(self._options.get('projectId')) + return project_id + + def _get_service(self, name, initializer): + """Returns the service instance identified by the given name. + + Services are functional entities exposed by the Admin SDK (e.g. auth, database). Each + service instance is associated with exactly one App. If the named service + instance does not exist yet, _get_service() calls the provided initializer function to + create the service instance. The created instance will be cached, so that subsequent + calls would always fetch it from the cache. + + Args: + name: Name of the service to retrieve. + initializer: A function that can be used to initialize a service for the first time. + + Returns: + object: The specified service instance. + + Raises: + ValueError: If the provided name is invalid, or if the App is already deleted. + """ + if not name or not isinstance(name, str): + raise ValueError( + 'Illegal name argument: "{0}". Name must be a non-empty string.'.format(name)) + with self._lock: + if self._services is None: + raise ValueError( + 'Service requested from deleted Firebase App: "{0}".'.format(self._name)) + if name not in self._services: + self._services[name] = initializer(self) + return self._services[name] + + def _cleanup(self): + """Cleans up any services associated with this App. + + Checks whether each service contains a close() method, and calls it if available. + This is to be called when an App is being deleted, thus ensuring graceful termination of + any services started by the App. + """ + with self._lock: + for service in self._services.values(): + if hasattr(service, 'close') and hasattr(service.close, '__call__'): + service.close() + self._services = None diff --git a/venv/Lib/site-packages/firebase_admin/__pycache__/__about__.cpython-36.pyc b/venv/Lib/site-packages/firebase_admin/__pycache__/__about__.cpython-36.pyc new file mode 100644 index 0000000000000000000000000000000000000000..bbec1577442b84e960d511bdb7e2bf63385493e2 GIT binary patch literal 506 zcmYjOO=}x55M6)8sf%0aIR_nWsCS*zhc<)|L+PP0z4*2Wge;ABRqslRH0xrY^It;# zlCS+2Ic59>k|Cfccx9I7M% zu&$Cn!;4*42)Y+y_fd$`$H@601R5-W%$^Xk#@zX1PH}vV9AehK5aK2BT@vB|ug~h1 z*MS=33yF2kodxa98n}kALRazHnt#r(_y(kB6CR+1fZ*9RSCCD9T;K4@yT722uOT<8 z046P(5$3Q&wv-B(2jwzr4qAo{kxNRoYd$jz9t^^WWLe1!0zZpzlrEu0_QMb&t~R^N VyVB{pfcww;N%jcZ&35Cs-vFWuq`LqB literal 0 HcmV?d00001 diff --git a/venv/Lib/site-packages/firebase_admin/__pycache__/__init__.cpython-36.pyc b/venv/Lib/site-packages/firebase_admin/__pycache__/__init__.cpython-36.pyc new file mode 100644 index 0000000000000000000000000000000000000000..fa18ae3b3284079c1cff65732d20375752181abe GIT binary patch literal 10913 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 literal 0 HcmV?d00001 diff --git a/venv/Lib/site-packages/firebase_admin/__pycache__/_auth_client.cpython-36.pyc b/venv/Lib/site-packages/firebase_admin/__pycache__/_auth_client.cpython-36.pyc new file mode 100644 index 0000000000000000000000000000000000000000..49ee1ef0da3dc7fbe72a078b00246007b12bb8ad GIT binary patch literal 32567 zcmeHw+ix6KnqOadX|^cpYFoa{Oj-7f#a)S#Ju|yAvd3$hx|m*BQb@|4?a`#W*i|Hp zYIe1&swI=50&FD2o(C@w1PB&b1pAPeY#y>N`?T1XAP@Ni@(`erw+)gFkcR+CUgjyk z-*+xm)m@~hi#?uQQ|jvK>T~_hcmKX~`iF-P*FRi;*!;6UE|vbal=-XT{yn_n9bCLp zqvVynN~hc?%X_6!!F#n+*{U|GWqvn?`?1ED+>hgayfH5K6S$vfOvwEt?k5|Qa$m!J ztx=QvDcnyrrpl$OC9m!sdRX!fJ*YJ5US+v7JH6vv2_k>hjeW=MCmT+?6ZqZ4iTkV0 zR_OIR{@nk>2us&z%Y!3LmT2~(@NVGwQH)22)T4e9bog<)xsfEjrfLJ9>&+y*<9D0u zeixsPHv6$3HBq;l1Z#mGNe%UEs~1KIK2NDKTkA=i-I~8i+`NZZe4$(_`6YmE$9om;&v^^pY40`Ec;36@z3zP-n#+yZ{7ro!{ei!dAc~`u% z-Z^~pvUk;+^UmY$74L%gCcgU)M)2Lu?_mUQc|XK+$NQ1@V?2M=`@s7>@AvWKw72N} z#QQ1kUh^(`Z{xeyZJl?#pW*rUy?4Do!1Eu-B7ZoTSdeAidD|}bJeHE{&~}p`?Am2- zhdtkOlF)ITxaYUAOl>FeyKXm`yWS?!@^1pKF}xP=ivKAtyXDPNJd*%vMHno~)A^U!X2cl-fAP22AJ3!4%znwUXmz*GWBLCAq za9d5M-S*?y!JHME0}<~AZGW!rWd7cqb8e9i9R021w%cJJ)X+vN1eV)5>x5CR&RcUR zok+u(-u=&douC~goo(lC;HD%t-|IPHj}VVXTKZvOORUaOU%heT>b1+wg=;r%U25K3 zy7A%Vg%!u|-VLI#yG4q<>qddQ3VPi+dUHG32)pO!y{({o{-0d9zjO5G=M(~*`xtbK z-e)U=dOE4Wsf$I2lbELPT#*AMPU@xvCM;+bw6ol>P@VL(UzMGX4W(h zX}ataY@vBqb<}J|#FWO&hjG~b0L(#+gPcLI3f)BGQecIg;;P^EBR2^nFbm5%)RV?x zDS-(H?*KPa1<;W^h-z%+5Ed}{$nCo8el$3&nTh%sRaoHUP0hX*!tPqIu7`8Xa<%4` zDm^oVRTBGXrdV{HSv;;(B#!OEEZg42W_x_?3y@)cu{&($*x5?b%+pBKU-?$xi zeJ={``nNqlzLSK#+x>2EFO2To-uB(d`O)pz-}2+ckDNDexBc}W{q)VZZtJzUeb?Uz z+8tmfaPS~TRd8RT^p26L5-0vJwK$|ml+Mqr8 z<2zr%7sw=bOPi$6^3D%dWVK0{ZXAd0z)e7x_W}r1QEj-eXfp2wSjQC&Eq z=mlJUh*!*oELC@o>T%e$u?&igidZEBIf)w%WD|^uEN2sfp5|--o;%?uI+xDgj+wbViCm-~co#Xta7`$dYwv(SoO>H+gETBn zkTZdV2!K5I@%+1f2kbY3{B(n@_@XoKctM+s>qgsbRXrznUiF=z+wSx|Kr!g1jpxS0 zF`ZG|#_h~zhQ8z{{ir)M`qk~kmp;`fLB?F7wMdUW==S=F({m$t%LkIi+2-6JM%7&3 zDdzx4)-c9=ZO4r`gS&1g7=pqI*}yUuLfDQ}cDs&G9^{1Wc0Y;%&j7T*#R|IX>D--u zY(7W+R+#wC;`~R3m8YNvauJbctI=`14Nj=FXsV@FJjE0s5)P_ZR%ii3i!+Ryub}8p z@QTUpN=GKjJ1=SMENK6VMN}fGm820qB#?DU`9URqB>|dlR+BNvKFC9ntEElIQcB1B zkcOL+QDe8dS@SAE=|KhWRZ3Yt-yOSCjT*_+X5AaxguKCA@dr>W zcS!~l?k_L|%~zF(By7R6utp>c&rMuGWa2Pb616|i`S6pK3=YggzV;Fl59{JvY3}YbnbIm4^@gtzNR7(h=das3>^R6RJ%qcDOy&noxVnT)`;? zN%Boz{;WrxZKO%!p4Lb)WmDH7jG=6?O1_;X1@n=1TCLoIs`<8BD_Bb06W!TUu6?ed zg{DCZy{7q2m6TibJ_=%}MeU6}AhHTR-(3eWP|a4-OA|&6j=#3%lP>sVv|FKyR!i{~ z4!#>FZg*IbUGO7XSkUeLD}HVq#k_Qlg$(oT^;e<0IzTq3owgGfKp<7Gg}%3Qpi3dM zb91rN@z>psA{9eRkOAv`s;+YmWU1UaTM)PuZWN*0J>PLwL2hTARfwK-s7_tyG}PJC zbB&tOXBraRU5QIXg3`2apg7UV|~V98H7eMl-k!#@JtUg11N1 zY@nKE#KE8n-8ZV@`^IyH%RD&VRG77SFELY8s_lsaT$~*j6{k@%oiq;T@KO&V@I9>! zG>!Ql(M%07l-I75EkCJ*c`L0wQX9;2NC{SlwFW$I$91#$%BhM7hs` zI3a#fC(1DB73zM_CpJRQ>GvRKd?kNa?2XuIwNx`r;T%nO4T?uI38*H!TRmXEhzZ|F z66e;+g2hs3MKRc67pff=9lA2f+V6$!jX7sg6z^_3UH_hCPg2LWZ=syFNbL=HE3j7@-Pv?83}s*m+-`dIbrm>j@Gu}2ZO<#uT9 z4htINQAv4yF^?4p7#^D=lay1=mK%o@t_#jypB;;6y$lX1;t+FoP=#g=b_Ft+ttdO` zJ18@xkPeBP<}niUilvZ%Vd&;n9aMLs? z)U>$xRiOt5aXn0~z>nmmC{hRk#|uH@)RlyiQ?#JYad0$)&gS1Wh(_S14Z-#yt{Akc z(VfE*;yW4CQ-Hxb5(}KA2Q_eXtRBh@iJVz{`#E09=$V;GT?3}!CqkpYdU7-(59{oU zNm9b%gM4ya&%+cUC`8@OR4+7?Qz+SHo*J#xI1bEnID}E8>V}GY3HHGBQ2JP^H0LIp zBE>VruEDtUq46sseh6wszk@r2Q)l_~cX`R9)8LrFn&#?uQyThHluD87lxA2X#hwVu z{=*YtSr3j?-|6efay}2lV5&Av5W3K)|Tqaig;$!@F?b!hVBuQu!dQ zFaM zLxB8Z(Z)Z2IZMtUP{P<-t@N9WWgnBNr=Br#YyQFX37}BX#Mj0Oibc?~so+4AK`HNe zG^Ha^jX3v@Xk2f&(C**)S#IvCMMu^$@Uv)9C;)+TWCrn)tTLz2YUQ70hOazzL)xE( zI(tq9R0dX=1wMdgM!SeE1L&2RHnL7;@nP+?_GbRWb?wMf&V>;5p-eGL@fA(+bRfhJ zaY;&FloA9&A5@}KUzDIE!;?7v0L7IrH>KH`4m2AYW6GFXRCul+V#r_eq-8xfO}jim6btd?m}aVXoz6aS_n|p zQ&6RzieFE?gM0uOkV=GyFJk{oJ3OiN1^GBR1bSd@F!U5xh!;3aQpMj$Ed)n0ZRYq;cdXC4A;7 zg+}A}O&v8%zZi_6&!lnK0)n>AU}^>3i=HoTrN}{Tm}!JMtT=*3QK*0e>NvlM7~Mh$ zPS5Z^8WD-aeyd*3Aq(XfN2iUx zUmhj0d;tV`P|>I%p}p&BCY9(dl#PBL7fkmjyqBqoiYL*#AK}@5!%NK1vC_`l`%EH; zRpfS!R#U->1GTE4c@5acbOx|ULy_)tu$^h8dTg zFjJ`=ovzMQPF8IA*Y?;Zf8!rfmoI)6IHYV7Y7|!q?3g(v;=(+SqL6d6n(1PLma{Gn zXu`l`fWXm4S6U`C46U zZlp(46-~_rQKT@LRAx<9?^ekya zF9$R#(>C8T%PW>)h*S;wTp4jk+KSQZj0>lDiDfW)MNuQy0Xre4nFUsZ$)p10W&|zx zf&~{{(y{W;<@+7!050+HUe3S0ROE!a2DWyK+~g*pD$^x&hw(H+Mh8&$G61ArM^G!0 z%W8aim_LR4%<_P=#hi2{ml2N3I1=?K@E7n~s%5j~>tL1Q!mX3Pi&Tr5e3g!Qa40h! zNG;)yR%{MxUU;wD30)5{7wx(&@4TkPLfU33Bu#lOdK!mwD_|J#JjNQm&&vWY!hm(( z!tme2)BlB+^1eJjUD-J{(x;U>gaBWE$O^2k%-uCW;ZNWr#;3|I^o=i-mv{#Jc0m$g z$ZZ+U$np-86qNN4gV!Q9m*h>8QRZ;x9$2KLumImsm{^7=CUUGi%ZcMGVW*tt4|TE8 zMkT3-2&@7cOkYBRgSA@ydq_dh={#y488XY!j2Fbcj=SCLB7x?jFnUfKQ7-+3!!L59 zBN>}Nafjuq^`c;lc|r2c{`HuQN5xnC;Ea1Bfg#IfOzHw?iKaSPhaOwLlOPR!nQ@tx z_Z&dhKTmEpqQ64%J08Zv*y1PZycn zvk@#1!*7oXJ;OHW05L7(y0F+$$Tx{{OE!3se!{w`*oDo=0R;`=;Nx*qF1NLG6%MBa z_w*c9h{MP-qLl$m%1*)cXpun!RM9S-GR4B;L)M<-!Gxl4DXf%J%O|5tXaH&Onqi$n zEaJFkSee!=-_CKYY?yludf}gxkr_pv#Zb56S^pANXMh$b z--2s7A1>dxuFVU0HQ`IL`KLNhIG3NxT>)Wt1ZYOMTCS1N7nnl9)K%C5%%#b-dRCTU zq`3pGK_;mHIyi;DGBv2n1Z&%dJ@1h*lNDRgTxcE!erMDtjW0NBFojmDFspzjF*58_ z{wJ6Zc2`7D-X$cUc2Vrvwucly=6hykTamqyN=liiN}TYxuS1K|Q2|OhlWq3V`H}@9 z6DcD!MXaX!^nz1{ZdQh4G$@mD&Ai}@z7H9g6_`p;UglE~l&Q32$ycqkd=-gdMp|Yv zP1=-_{Np?QDGPYTr*WY+f2S7B(3hh0dpfxBv?8ftl$llcKcU((!&3;a%N7MD07_;% z6Rh@aXMkt_Ptq^=1jM;!}K1jh)a$$QqQ`|L8OLjJJ2A&UM1u( z01Rfw5P<;m!sKB|!ZzbyE_%jS6yG-%FDbZr2l5_U`DZtV?(7~!~=ynecGV5(qO z05a#uq?jO^VY?aR*uzrWUx|7w77yz&$ARaZn~-FZ6-ETah`8I1%n|<=0^3k@EPv@Je&g_{0Oq&>gcdiCn~&fB9rey)jqnyOP&c0o(F`? zz6&C&&UC#@zQm|a=|m0bt2^J(dVFzdtI{*T#g{Otqqs3K_XlO}f@K)XJ&C3-`5kOv zQT{;T6M=~fi8@OFr-UE{7B4*s-dVIbfJ2L&>aIwL&o=SUkC!ah))Lx`O&3|-P|R(1a^Dh)4G zmO<&QO(`!fy?bb@?gB%3F5 zvs|EjgOCQ04p0hXl+#;I!S&+4Fy*y=r<1Y?1tYkmAemST{XrBkDPhP#Z!xH)KyeE+ zqGIlIy5Xj5Pi+9qdZwgM7r<>pd$#N zHic)CpjVK!JS`ebQ>_d3Hi#c*T76VbZzV2{T@vm~OxAE7R695vK&6{D#)ub#2^ISq z<~fUC9UE3>Jq4Zhgq951eyq|;h1Dvp%mgrO2Z6te%BI3rxRmLX-G2|JvnZPa)S{(g zz@RC4G?5hI-vksKZluqw&3u9cBOo=SD#Fvbdq8|9YQF(c2FdZ*_5%fv>KxcTo!cs% zUOwO(QGWnZY<%h5aa6?=xx|E8?}B5XZSGD(6ENwF7>l5q1fTZ7*r>9pC>8hwvVjy_ zF@DGEbAP&Y8jDhCajw;(U$p6V)?uvKtSh@QCxwY`W56~Gpf=Ub3iZdpM!BG$Z6UPB1dp(S>O?WGtl~kbnabXx;GAo5-Dp^VP zq}-_J#kfv|ji{l|IoJH|I`Y^wmy!Ci3kiy=9kHPX|FgD_k#TMFyvM+dLuj=|rWdZt zu>@IDf5{w9uqPZxdQah+1}^sW9joapaUqtl9z)#ULf9bKF)UW&gr2?vN{W#g#6AGi zA*X{8rS^wH;g>yKN;DSk^))mk`7--#^;M&?SeAm`avD`aa~d8N(m0wff&xOs%~2-& z#r%Rs&8%9)z|}CjxrS#CEW3FQ4rRk`vYlCW1KyEtIX{jMirsj!=^T2F$~E|N=u7&H z1FeFF{p4J@c5anKtwK56fdhK(1l>DA5oX!NY{SNXgk2S>5Zsm?Ew<=JR7!hh{YHr< z<8M`!GLja2BZOsa`=+TU+s=V6KC&JRMetn>7`lk(H}NHPP0(ViH7^rcz~g28G(&?q zpArJ>Fx%}O+Fa}Gfio3&*kK@j)1&x>BIttQu5w2>4r&mkils9?2ZT$Y-!UVNXH^ii zNjTC2lnTxjE$Y+-&-Z)MX9k3Y#Kv){@R9|Vz(@_)ga)<3I)8I9L%RpF1NWz>+)NHi zP+IFXJb+WM?KEa?&Mz;2a%1UIbLsN(Wk~nI$)XiDf$f)!3awK1o4PF9G!`He>!Oc% z8L|Lhv2_jXnD+v!khTBJ65lacfhOd=Uya8k#y@=mVpN2pqMrKboE$+~Fj~SiRQ5nfjEnfMf=H-v(7q7w3OY+eq7hUJQ-l4T8 zZDHT1GHo?oW^q>N>o0Tk^@i4^A64ryY3$1>>aJky9h-^iS@R6c!j_FokuY7~cH8*aK{i)@fqAs%}zqN!V z6xCc_yn1~Re$A&LEP?{5?oC=fn#u^3|F}P4?NQ76%Rn)yBXb%bjNvL-+GY3up?R%| zh+@=g(T#sIcdQi@Eq%C>uMbXmgcDOM8O-g!=$N*O_fZ!`-InJ+x@KyrgSEuwkobaW zn(i^2xMi)d40S%9Z6T>x&;+$jk=eRt-FmXirPT@puRRA?zzx3^e3mC=HB7`GsS;iv z*`bSVQ2EiLL-#IxK1>A~25xG5=leLQJ{GC;W22AdI!;>z`+pATFp%A9oLYKlnF6ix z*uIHUL#kH9U1h)MJ+&Fp0NvK6(}77sj%@|_md0$!5tZqN~DY2k38-EkzzjEi@@ z33tmvF0n5+5wrgGNGavLwLXTdg`cmeeF89mX?w+r)j30sRoV+D&iy^te~(# zK?Vm@9V70WA2iOMJ3#)Pg1I`|RD;iq6{FB?FvxGR`9_AF_3!9FBz%92fRg8Pph|&p zZ4*XS$>kpuF<27BFoRuzotsbo%ae_QH@bb2!wxbITI!liD~XT4_v z7X4)^Fd^(opLUmHkSSi1>HP+{RK^$eI84VRRTbjmH=5n#a;l1kpDqbp#RUw(G8LUC z^(>gm&%snGP|FlkIhkWB`*c%mFzk`}@aJG!D)y#gTVJ=)@K~D*hq6O?aQ?a^4(B9Hr%RBU7s7tBp)<1KK^z z&XH}Bx!GvF3Gs>FmhF;CNg`1oEc&Dd!D*@rLDpFYLUkUD|s$Su8>e zd~W|2;xq4a8})d7BYbWS$7QWb4QGob8TZ5ikR)dit0NH~?Q)CVt@0epPV;$zcGcLE?iQUQF8XRvmalHK> z_~-JDx7>6L797O!maq5^-0`MyIYkHZzrgD?d5}!9EzUPOVFYN4-c2SO;&~<&D_<4A ze30&8wUw5aZ-}4m(Pr&uKfdtOX7)^Gm3Lrro@|RhpF_di;mu6n$NB0^msptBJ4Z9g zt(+JCjAxB!MRk&(2TymlJ4pfMK7*bdv=gE{_EYc-i++M_JlN;jmt(^S3T(W#+Kg)4 zaUx_>N&?0iW_tOb;SgW+Fn{UFvib@w@U)3-Bv|3l`Ry1E+)re`1YpcGJ8llZ_wWO^ zeH@qo*WgGO0s|-wa$Y68y9s-;D8w-M!z8RbGVtsGl+lOkF~O*s5!hwZE;*d2 z7!@PGBU`%Q2Ld*pA=I#k#jftG!BfP9l&clvS375jAtOVh9I(HCAZKxRkp*WGf;7&^ z_8XQoSeOSMPf%XPkC7<+U(laq@3ua5(~bmAZ~A)Sg_k@$w{s7uz&#{v9V7|wwAipC z99beeocF$c}FY5Y7vQc)g3zDf^AF6NNyHbuyhm_s45 z?Gtlo1C#!h^>K{E9EzHI1~G@+Y>YGU+n9qs%Y9CMn=E@cqrmIin1hdVOMdIlX8euD z9Eu3ddXvBLF^8hjW6;#I_-6#Iia8Xqsz=8hJn+ANWBK1u%%QN!Hmni(<4L_Xq7B^~R}VJdqi{<;Z*dwvJalS=t@jtlTL@Z{ds;{-z^->yf_*sSo*yG^(Bzk^vOh&QhwO$~bQzt-rSZysKeHw0SnHoFi(W_ZK@Hm=n>=QF zFfJK*(c5fkC>Zk^p8X90Bbie8>9LdLofmaLX7q>Bcu*$)UokfjOxN-AN7wNucayxs z-|QRwty-oAHkTNGM1wh6<%PmF zBF068ZU*84dpWn0p#vVc5x<8^tvpt#pO_x6AFrROJy$y>|K2+KQtjp1>$MkZ)3ulD zr|Ku`Cu=8b$LcTFU#QI-Jyknif1^~czry>7t<4^aHt`m{!OIa|u&Sj9cvh01c9!3` mlT+3srU?t^q+-$d2DNw8ioMI0Vr~;3tJEsB+&Smd)&CF7=q*wJ literal 0 HcmV?d00001 diff --git a/venv/Lib/site-packages/firebase_admin/__pycache__/_auth_providers.cpython-36.pyc b/venv/Lib/site-packages/firebase_admin/__pycache__/_auth_providers.cpython-36.pyc new file mode 100644 index 0000000000000000000000000000000000000000..8e54fbc77f692649a10efd6adb7bf25c90208bcb GIT binary patch literal 15188 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 literal 0 HcmV?d00001 diff --git a/venv/Lib/site-packages/firebase_admin/__pycache__/_auth_utils.cpython-36.pyc b/venv/Lib/site-packages/firebase_admin/__pycache__/_auth_utils.cpython-36.pyc new file mode 100644 index 0000000000000000000000000000000000000000..5ef7c81ac2f526a226e5053e4a6238a640ef5717 GIT binary patch literal 15541 zcmc&*+jHAidI!LZD4LROS&nasgE)>ibZq*vUT5QG6EhO!(2*%c7hkwa5QqnoAdvub z0NN&3>g=r2ozAq|r%s>x)amTZ&UE_Lf1)$(OZ!s1_My!`(1)GQw7>5h00bqvopHp=qs2rIBLHqMT+W9&GaU?w;prq}>^i%F zr#G0zZn7Wa=@h%ge)64CKh18l5Al75t+Ai7k5F=!-C=(O$T{{g`x(C9#4JBypJJAu zTG`FFc2o89fZSzeK*}NHZ9qO_Q-DkXqNC0`fK0OrAQeC^0P-#%GwdE9_d>`;Kt5+x zK&oLs?*Ve3eF4Z9fLubW9|1DU9su$HkoN&80#ajhfXs!E%Ye+YF9G=y5E|M66q zaclAVi0K;}rniB&4y%t+hlX#rEWG#H^;E-It7jXcMv$_e17e##Zk|_9ZTfaS<*cp+ z8OL=RR*>>KtM%MkIJbJ?VP&B@^Ten;C|76e1@UDpR`1oSwfgvcd2#X4+`_c6P+6=j zHE8b92lJB>@G%}N1)Q%C*Vj`_V<})E&C)D`?~IjYSvK;W0=^ZT4p@%39p9s@08EVq zg?V$`s`?f;eV3c>tBO)~bUS?4{SDLC&1Tbm=7m7pS=ZgC7S~PPv%c+ESeEXtQDMuw zqPq?-jutv0sFcs^_$+PMXxwTyt(N8ZCShA|x+e2bt&PFs=DO|puHLd*F7IB^O^1a; zS|0kvRIFA>f3#tVNB!A`+q6Xgq7M*AU$v-=o0y$vu`6gDjpMjz&BbUXIiE(;^gP|M zXeC>g)%J9ZYSDTfu?Xr^^p3S**4)M6*gjy@}hl>J@ybo?Z1< z>bAPA7*J5SYfJ&kQ?=gtsSfApRW85P@q8UK#QgOd5Ln_M0_p|%hi0>5RXBHfFlIDl z8-r#BR<#{wJuhlO+OwK#^+K}rcM2av55NCi@MBkO#`^H&zA4l5*MZ1~~%@ zvVFrS5)N~?DQa5Hsadsmavtp?1}#PP8iXVI5aLs~1oFSZ!?v=i_(1xmwySPw{4$FX&YtTetlFYcRG5^vg9t8j2b(P$yY#d7Y*&h$nC31Wr>o z*YM;`;HId@fR_R=a}4)!V5xU}07Fze#tzMqE`c3FtFMHsP)QM|Gd0TWS7@k8NTzP47ZKNtXWpm*}bYxavGL zn>N!sHoK!=_{H^|3#2bCde?=Xf{rqwtemS>tL=An51J7h!ZRD2tOMO0>(CoFf2ub& zOl~%SX0KGt1bN%D9nUxAKIn5!b{rqYEy%99yk+{(W+@C5}Y;w8{aIo zmGV}$HI_a@sHLY2J@HMn%O=}_-$!b_4+|P zu{|DRTU4!~W~hNk>r4RO1vRhgz&^i>vKZ$B8u@FK0Ox9gK}nbP8MKdcEr~ne9M(4Q zJL_jQvy9jk?9A)HaVA+0IL?}*P;uBRZ3fox$WYL|w$-rLY#^$=K{kogX{}m3G)U$X zApNOmMm7no6j%dYy=gwzVJ%oC{WEM{7R-=mcC!g90I0{7S1H}NeM=0WH(cmWn>bpS zE5a&ph?Sdm4|39IxST;en%$EAIXcvzS&#{yMOsr-bhDxVpal6qMGijF8dXg0`=EE^=jPR3 z`D*?8)sMdFJv>aef`_hzNQ?00>o$Y=Lj>Zb;>b{L%}cD1W(hP7i^qeJ(%2|!^^91S z;M{{*R@8YCv+Rgu*(|osv)DRwDyI!~ILqFaEPJp{y&P*(QWnsrNj;iH>s~EJ6|78{ zSS*y#l0F{+`j`)OD9mO_;M;wQdN5#}^-?jNKvAqVp)Panu)CqyI35ddRBe+GLi>x< znWrJcS(V?!dxNwjeFik<04hlS_HHkI=_QSc4JAf}R_k5D{xMX;t#*BgXn1;vRu^Ol z?DZ8EDJiU=V+EO}xoS0suCcGAWNWOzBLhq>aDtQ*E#i=r9$a2>$HektF=I9~tJ&4b z5QxQWIsqJt1WER2^?Q^x*t`&SYf!gC*M2glZ?bBaP|)8ONl%j{%|8Tu=?{U2shHWh z`xJuB_3CtthWS41P*^wu6H0Vy*lZ{gCSxQdYX0f~9Q^bT%?i;R^yOhV0Ps*qC`8?o z-7^#meO5?T{j&qm@KF*CB=B^GnWD2E}?c~JBpKi6XZI)DZEHQ*0KDi+XzN0kuRy3s*j4! z3{(>23bLZ^K7)25TA&fv|4SmnS=G!92iRmX5 zcEa4^7lC)NTXhS*FmQKLj}+$uXp;tQ780}()FfpN+T47sY@_y8N|?Ar=}6J1SY}J* zzeKOuBy>^Ia-?_v;eb^p2}rIXZ0@Z#k+%agYbgT22}8aRoH5!iyaymRxrD5BIziNW z?|tUNsPN6j=J16EdrH?7H z9fcjiU$Nnts`=n^I-j@rU5FQ$XhxI_LE5Kyp8 zeJlpTHL}ks(C3`E+TWsSf^+hMYsf_~spW8|i<6Kyh-2uJ!9~V^ko>>LgXA1tq|gKO48X^*%D$E&ST{%e$KTMGX*O4DRK z;BX}^DY$1){#%r%a9;f_%E{zcw^LzxI^?gc+1X?G!-gX3U-FrxB)8f)BEi}ujS{g_ z?3pC1+{ERPBhYN>&&)2E$%S7lY?Ww4{=fOIkHdrhzExT;={K+FH)nB`t`|eEV#`7? zI7c{4h0RXQ0e7oOQ)+<@Sc_)5VGt29lL zw|&S(T226|A`h$CmKb|V{!Z*o?c^NS6*geA+wfV zW@UpEe$mQ~#VZT@|Cc>W`#iZcT5`On{xe?UJyrVH!aY?ug-CCyz6MQoOM2FPyc0FM z=e8}0pTk`zgQNdr5u z+tLvqv0GlKC#RCIc+czmSg-+``u)YZTEvyYXBeJq#gfIO|B{o{fa5YycOcEo+U8VR*N&4@!D|+wRl)$WXu8O@U zT8_j*j4oI~p5*!1C`{fU&FqFB9Hr3X!o$jR*hx?z9gjseDBy!=rsW6eEvxIH8`pN= zqj9-!u^`oU+r?~sOk&ZHydf^R_Ifu3CS?X!O>-UXVeg``JH+12V z_fg4`wM>B#dEC{YmGK9)m4mC2bo96=gA!Xp?SbF{*+D`(U%&%A=gQUyKkvg^PT?T3 ze|(a_zJ^8wZ!Xfh@NbjvP}rK`(F^;(02&08#wIam{1K8TcS*1bj1TDQ9#{j0;OU3u z+3K{62OH(7rRrSGSb8#FS?p7ce~C#Jk%y2NWUm_UpNSKd{tNBG$Qm6dCRP3rkQfo9 z^5_zX_y!N_h=M&|kdd2d<*S($ZAaTlLAj)$;52?82M8#zo%Hj|+i8@)v4dj)ytXP1 z0vc2i(4{KhmL4hJjuV{JAl}CxA&y4J2Ph$}cYBIk!etAqq|+wvt==-dE!ZD0Le@Cc zP~Vy(h6JWf-YxY;AipJG4X#59OUYB(ES`ens~x+^4B44ModsF5-G&oa*xGynm5Nz$ z95Y*BTTvqg78ZMAJ>S@%<^q}#&wEhIAEAT)#^sSiUeU-8PAryJPiy0vC~Z(d^r5rj zU0fc8g$E<`h|)vVQ9A9}TB^HD?@Zu|*LIB7x2c;>OCXC>vcnamg#Qw>O*cZ$WI#mQC zIOcg2tj;t{%s&|0@cp&{_0>kYg|!#46g4{vb6&<5)!zA`*ofo5H5hqk(1g=bnV+K@ zp*T3otThusR3jW*M&pLX+rC2eJPk-(pHtIXTH^#eH2qFhD5SF=DZT42poj>q?4#ke zS8Q>3Dsl?YB+14N0(?U^lWu*~kxx<7Je?que!!xCh){er>Mb#X7)uO8L^!dBI0QR1 zan4m8ud}vhH*6dQ=Plkseh$=$6tN1SyMcfs1to9_1h)!XfKn3hPQe@>H5RA8KyawB zMSHLeQ0h1qg*`#?{^RAlp>!2QcH$W&I}%oi#VODyhNZzMFN5iH3KK`ilD=qJI?0oF z=i0R>wW74{y6a7=gfPoBgrdD`GSvdRbf+y2nan~wsVTB)Hr!`4&Yl&PDK|r`Q$%#3 zIT66-$Y+9O)?ex2xh*)^NBy+rAU-GkASC>u+IR{6yO`iV97Fq9>~}7@eN7%@nADpC zJec7GJ2Vfz6&elGUAXk^#;omZO}o$;As2oe!m<51TRIaZ|j)}rP6IMIW3 zkh%nmnsR7d4)$cFUS(M8zKQ;l{k#TgC&Sg1`8r%_j(-@+UQJLo^5YH1)@#ys4RoYj zx1{nX*Z^%)0Nlmp(W!mk=8d2AV!IITf1k=? z`jHig%!)W!F{%J3$AJxPX)o6fPb$8S^}M3azn!4Wn?qI_)1#=>4%nN2K;>^>QaARH zgkS?Cc@=x=t$B*`*F@xh$gV6%bAVk1Z+x6Iuy1p|O{97ChOa@dL+sI?Cg^qPg@}kL zcQ~@yAkm#YWFy!B*Zb^$RgqEU|q^T$wgUoTb;0nV_)jY&q^TDc7$kJTnPm=m#t?CW8>5 z%rN6tj5^d@qPYGP4MJ8t*|MA?_h|E0VchF1SSBn)q1ov%oa#|d)0Ib@x$PY?%_THHerf(;NP z-fJjjb3kduS@uv_nc$?HVwF9x5v=eV8&YB2!YeW!kuA?*#mS96#5T5hq&_u~-!606 zCBEU!EDbo#W)99eL&%Wc6F%UGdY7DBt0wIR4rXwEBN${EY;4 z-aUBnF^LXsYqg0md-$JV#eDtL)Ld<*dT)85EWD4kxg}#}Zn-vHKRUfUKU@i^k)je?M{_rdr;5 zkVD)?xYHBX5BZ6LGvQRluSr&Ax~`mHkJy|1m=wCqhq*Kq4=5l`09Wk}N@5Nn7hoLk z`zyTIaDI0$Nar^azu^KEPVbAzZbEi~jd<;jiX4c^Fmnb5F#X9qCe%he5H9k0IKD-8 zsDlk-2VAoQPT+rmm|lird~ld&SQhyafZ!=}N@1x#(atEuZB&y1O7Gw)aMc>w$0NOa z^D;Zihs`Cml|Wu>7ynqm`CH@?%6ueOTy?RH4r@sFmeBe^Q zPbF{Dja=&dDcvY~9HiIqqa&n|Bj+FC9sVs~_;Dn0twG-T`VkquldRFDW<6>)>RBkD zpO@{S9_J|jbD|U3q~uK3ge(0RVl~;+Y0xPxoa>WnK@)Www13ctq?uTC3YSMoecLLZ zL|h#)8{mBscvpdQge$f+ehHaq$V%HKNO}incD#{1rgupevo&G6_4JC6zGv|N!xe~> z1KPQh0@q7Z-a(-B#wd9BK1Cl&zqq-BB-If(^GqM{tW``zhy->{vHWcU5Dr8U{W@@O z9uI$p(!Yr`v7((uJVC&U>de0XrJ{;|0oQQI#?uYq^p+I6ik^ZjGR~Uzs>o5Rk4KI{ z`I{@@wHFf3t2C!Mx;>!VGTm}?yGS>Rr-}S%kr^!VXGQiXCrtB?==KTS2>T+}LF5H+ zilB?&ng}e3Scvp4lUJQL=w{K4(M`A@$m7E4jL+%B$hYW52N!8Hl7-C4D&u5FaN3`E zhi)Xgf*%B?5=_mIr$t-DZ6fDdph3{aO`ODO;smyXVpX98%^As*DN>oC z?ATC&#o7;j$)Z5t`VZQl#HTI#l=lJ!`qb|XNr`flHpNPq3x_jv&Ya74&hYlBQ}t(^ zV`uZcVf@1={ASR9fTFsnxY0DY$*sWbSxw8Nekmw5OK9!D?v<6d6+Xl3eD+tofnI{H6#pjO=K7V92>v%fN7x1(o>PMyKEH7;uON)nZ*1}lG z&<)trt*uwg3w#mAtQYY?AR6^L+uHF}_Q?7&+ViA%7aFoy~h!aB{P|cr5mb#B;$2Fm8FQ~!Fv<$-rK1Bf1>OE z3)SNeEijC4f3;Lis$LX^!iy7I3YRAp6}$03B@1cmfE`Z+zKWBDo``oM?(FaQaXNBZ zy1o)l6gt_W`EA$RjoNLe?Rs$}-@gSBPm{{33fc!K>T6WOXqwQB#Z73!!XLG;MY&z! zHZLEW&_|Utacmr!%^LbOKBN0H=tC>IU*~iD)Ug5S&-2r0=lB9&M0<*#;b+m#^K<+> z+SB|3zle5$U*eb1E^-Unx{}nN#&Q3l*3sc#e(fqTp|yb$oW&6-B!5BbAT{DQUWy5R z7^5iWhUpGUDCI}tH4JdJgDQY>GvzUN09A&u@3}GN=qaQv(!bxKgqyg5e>f&Y zUY1E)3pSE?%h|pk?=U}Z(0-x7gOFOXL}Ft95FY1_cK9FE1|jJ#BauuM<wXBdO+;YWV_rj`*u)tS8lM^-Wbe%diZTqLD?QHNj*$gd8txQD6XUhBEP-BO6H*ZYW~ZbztA+m}M~ z?ed-)>2nLS>w_%>~moYgXN|&3W`L;a@Qi&yHhNBVXlF zYCu0~sXRnc6rutA24LMp8X?c%8O>*Cw1m>?2lV(ks+TB=RBl*@X9`3zxqljs%UJ#q z8sEdKO_ZEQ@gTWMKaI$hj}!SmUj4Q}qruSc z>jy9kq=9^uFl5Qn;-d^p^-l;fsrOw8INpxIIzYS&VYMgo&JmR8j23Z|(o+?|;&F7~bRUs}AZL2o%2p`8P*g^&2>NK!{1O>Z zh!wsXZSMtyp_(fi&*ss_N+7q=Ks@3Oc-deZqK*9uU`LJvc;b<#;5c-i>-maCBs;NsUruxIND8n5sPCmo8hPuWPuVr%V;YRdJW`U^M*1^=ivLSGkRCAu^z?y+ zZVwniK|&z|M6A6k8l48~i1->rsN#uuucJ1_Y=l@6w-mi7CV_J;?PB!V-A8goAsP84 z=NfL1Od(3r+Ffw~6f5LkBu+&CK17Yzzw2M3C&xkzI22|+XS7(<#fe3v05AA>RV6fjEHtQ7@Mca#}%aFQ4kSG zB@q#Q7-n{{BFSmGWK?6BNy34pvTii)QJB!gB*9R!kluG-64`|Za|sudN~+4F1ob49 zRPgdgcyq$p*F+~B9Zfc4E#X$U+U?&UA)7kj~3qD{6xI=e~q1~n{7J^8|){imy z)7eTE2@)MR7SfE=I)>O_%;e_3#YgEv zQucyKiH}6|24?(`HcHK{ZXPZact}^Cq1=Xm(Q%Tx1w-c%h2h>qcN zk5(VAyneprY^-i=eCa%Vx&CW1|5~YbrDmspN%K6E z(T@cC07WrWC%%c4@TJ1mUqg&0zDhyJ)nxt|Aa^XW!@B_Z6wJ~uP5MfyQwI9pkl`wl zR7EKz1)67@FV`C*-4gi`ypZXRh#=B%@_{-yI`b?fQNM@bohQXa_Lcp>jlrR7berty{3?x#-iOH!HkN!yx3 RD48qSWy<{PCA&1=`42qxgH`|l literal 0 HcmV?d00001 diff --git a/venv/Lib/site-packages/firebase_admin/__pycache__/_messaging_encoder.cpython-36.pyc b/venv/Lib/site-packages/firebase_admin/__pycache__/_messaging_encoder.cpython-36.pyc new file mode 100644 index 0000000000000000000000000000000000000000..b8e0beae08272b6b0ec76dc4b0fd94f46f81fd29 GIT binary patch literal 23995 zcmeHv+mjsEdEeY;c6Ro@*u?@MI9yzaA+ZC17l?u&8X!nel)x1YKvFaUH5g3yE@pOi zW^uX~AesZ&5vUkUg);3ZPAs!*mhJeWIF5X&RPv%fAXQeSQm#C7IaRKtDph<*2tpO_nm%mVxs)z^$(i;Urwd|ODgi0L;eDO)?Fk< zs*y6%My8i;q~)4vWaOG{WaXM`OGt?(#+fcLm&y z;jU_Q2@$*Q>3*QN7#hb&QtX8T6~$ zcBf}m*9NL;-!`k8re(F(+3dvSOK;bzn*(FJXVyQ%)KjZ%rvBd;G8gc(mXVk#yiSU* zg4Za@WYc&NnI>L@Qz*H`w`Fj%HHRg+=sn8BV_SB$-Rf6wnN`c|+ts_BR`qg6nYUV& zS-sR7Y#UYG6Vs}f%T@ec8uaZ}r*BoaTK9W{mQn5W@dlgvjapXqp4sbFaaCr!v(@3C zkp}hZTYYp?cBj4FYpIiw7smo@Tedu+tshY}-)pt)-u>#JZ&n9uReP{u_R(dq)oE9; zXlQ11WFgl&X3wy^30_p|);Sr6)5TJ^&Q&i~jZT|QTMEOiNoiI0s-75ZNlmX-uU^F5 zH_ZE%zf;?$h3U&IBLi@vShC<5e2!%+tP$qG8~*hNc4w{AmUY1d`WVNuTm81Y%FUa> zZr4{M4R79zPA3=(aH9qtW6xnO>NeP(wa)r3cEZEah(_Z;UNy3L;Bw6^-zo`YOO zgFQ!BYi~C7y6-&@FyX7RJ=QL-BtUVldL0O)%=HeoK|`XH3)G;-Fz2rwW54Z-pY#GR|Iwl*~!Vnoc#1H_+m(CT#o-#*3)#wWOJw(b+4iCQwf zn>SC%W35wo@hxSpb>0hM3k@~o>lf!_f};Pew_I(PK}z_?YX-kd_*v(W4Aa9@Gd0X0 zO%Jn3Gs7Ix>@bfsH!L8{4~s|(!xGZsa13e5NP+I8S8HQ#ju_}xqUhijJ%DzL9z?o1 zf|NTR0Sh-TTgVIW-5m>FuvT_+mf2fVS5)%?h#kW!8Nd7pbCUE)L zkK5;NY+I(XZrp0w+qZ9kv>2*$*Sukv)&`z*W4qtEH&7cl?wc)Ded&f}0#R*KRnOdL zo9i!q{>%$Ew$z|&w(T2tO~6vm1gWq)D3(GIpwq9kqq^eU!y6Wmm7)GH$lrv)nOjpzJ0IU@hzB zy4IlY=8f&mEz6zs9w4mDRJF9KU@TcvolN4^EjF7#z-E(hV-bo{X=f^&n$*?CR{g(P zfp14tXg1w)v#B{A@|9-u&UUNk)nHU(&~7%>6b4lLm~by62_LTbyaV`I-2T#RE|W@^ z$E7sJJP9Tj*o!N*2q3ge-||%%sC>6N+PFL3{JIu~2g-71+PBU22I&Xn zs3w8m&GyW`TSl90^9`j2$}Q;U?@jq@B~6>2#+vNia+HFQzI+8gYaU4|Q%P6Sr5L4k zmUg_ePjG7mP1S07wSdlQk;#50OH71xB~dL>p;z&!v=A!bCSN<;H zXFZ1m3!IV#hCHVixSPQe9|uuMcXR&o%EDzXrx7@<2RLD!K zWmMI&^2X{2^6Ds)5LHC5@Lo|5&_e@DBhmU#bC$A5E^!@>0zdm+Q_K+ z7z~|^Lx$iOdb|$2d5{JCTtR(4geaq6Pj1g~-VNMhDg!_>R857OAzv>*=l^Vc$W za@X|o*D|tg>KQbJfS9SDcGDXp8}qaBc~WXl^wsw{E+0}zIcIi*v?ga(Ki?a)TRrPl zWc=RFvEU7&tb;hE(MDeS@9J$7VcSjL9eEvf62;$%yvMVTo0QRCyhr}kXxWbl6nqlMtV{(lVq0@?-V z)yIIgNVK~FwFM|X94xmGRB0bTz4dpx`RaMB!N}^%_WwhaKOT%ZwL~y}Vu*och9|i> zjub-74oFd_6XtmcWe@SQ$R|eOVh@Pmv;J>@2#-Sy(3lF6)=7Sm3sh&o{|WzKPO=5o?5~HDbawTUf^6P7HAHsWrC1`G|HqP zy6XrS`=WGYM!(9rKPj+8`USv3p@6?j9Oxw^Vn#?0Aq+go2q_s;r)@}F2JRkGwmNO+ zAamtoB0|o2`7tB{^s-|>7HswIL-n?*A_4&p_J8|Ztrh3uO5^m(=U1Bb?;Lyg{WB+D zKKjR#Y1 z$uIdi)?-qyhu`z}xDaI|DUmNl_&Tt2Dg5TEwe;m$B}pZ6$3-F76m>!NOVu!{I>Uq* ztX^btmdPtjLQW|;vH4I%`6hlM@s@JAOeS5aR7#a8q__$!v{4`Y5r!||XO*DBj%ZTQ z5k&u?9tBNG^3U?34T?@(aeI=B^0UYvHlCLJ9P(A;8OhHhzib?l z{66H58pkBRfc$aeS;;RNCyd$$sm6YkJ!d>GWlP3M=sYWm8n1I5x*l8`gU#yAn_s^6 z)m6{fNBwLQHmyxKbF^`tE-M&OJ3v;44lB<-7PvU*G=VXUW7OLe3Hiq>e?mfN$E1@D zLUXzcUiLZ!YfL1&8c=lZ6m{Zj_*v8mIuutA-N-yh3&jD2@1)kV8%0H%M*1I%;0lwo zzzGzJke08Ya|C(_IFMT@TZ!EI=X?Ms2D$a+xS6xA%+0}F6J)m6YkHzyD7ywD)Y5Jq zhTTmIEQCb1QD&9yF!Eq`cIS{k_9u|aIL|zG0>OGxp&><*_56KghA{s`lwrv9!uDtY z%7_x2>%zo|^@j7(&UK3h7-AQ$%VDZJhFtk!8l`yyB)dCKp#LZ<_a)p{q}2p+lMi7= z>P{gy4Fl8ICq-;VsyhRsFWb_cH875-NS_X~#w51qQ#^k{3{X_Br<~IotmtC{oQ=Az ze6=_NL95Oeyj7`teuGfyj=R-jgK2|9-8m2|t<##(+OkZVxt-Z~9jI2zS%{ZG0~@H0 zeg8Ua-p8=Y&arsCf`33^yG^6%8TQ4ZT`NK_k31^0M7bq@NOy6U&TiJWd)kdb+mM^P z-C4iw7W(wF_M8{u6Yxh17G;^Om+2v0);*T%0L+URNWF#xmYpgGosRe$#1q|^hz+cH z1Szbh&R=9ss54R1J*a&Y&6f5%Hlq$6?Umuw)i1DZ*=x(Uy1;@1Bb_6DAN|_r*(wVI zw=WRWhv62mUNEpL89C$!Vj`G~5BZm9Z&9rC`BW*BgEfyo+C(Z|ZaP!OJ?(tXQzNJs zA1^>VzC2M+(Cz{?Ff@bE9QEw|M- z_Km0%%sm7(MZgH;y=w> z%Pm^)JoXLC`C1$s8(nSb?H7o8G>()#;n9$25zCF|sHYt<$+>;%e}`W))qvEXR}J??}(uv@*R zH%&K-cXo3S=x@9EwccQ$L^Tovm790gI=voDjby+=WYj8iwCB6|eycyQM&axYRQ)IX zEJ~X`nGmBt?27!KOw;1BkcQb`htKF8Qgx3sU||CppQ1_tW511?1Q{QSkq2WiP6Ng= zVo}vF_9|hlTL{&qZV`|MQ=>shyFo|`YweQlK@Q=|F2S9X3*aq3%&Q*&-r(K=ya7IA z@P<+k-p&N@7K4dREF)}=8ZdSMS)&rIcdm>m93gO4qwRhk01GXdPXJQt3RZeAkWz1> zL8$F$nD{Eo-eK~KOlaU#SCK$@6zDmEJm3tA5W^`{kMQxL*q9bHLb#`-4({2)U>5I}A?xG_F-obX`FHnV`qAv55O44>QL8PnLx1 z9`(6y_n5Jy#ng|}YRx|0ebzVtLJYfw+-Hr0T3|)HLl4s^dj#A5G2^L+X=(8YBJJUz z#naN_N74c_krqEfi)Vrs%bE>foc}z`bx%M{A4C4Hk+0d$b)WB^)b-sJ;|Rp-jIn&4 zzJz1OQIrFnKZbW=m^WV7C?c1`$j@$H zI4yH2usvFz^je=m>*A23ez2Z;P7K%R14f_9v z8{bGF%qL@<;RujjUUJR`WF#Wauf}8A0udxs3s;>haZVDIA47JPD858T_oe*(-e}Rf z`mKR+Kaga0)HLCRXd;Tja(uZcxd|18#1`#d2Oew0D8e=BEG10<8o)pWnnU6oJD{}5 zovp!k-*6U_#7r43*DaMCdC+pT`z>@_vQ4lb9IPC!tNJ=fJz^aITqa^3EN0LkTs5~W{<9{%g6_W9^!-(H zr$$!DT{O(K7L=#vXvKtIq368d-}azI+K|0$n=9;2j@*~SWp!s`bC4xe-@;2cGv7Y) zEm&+@D{B{5F2DQ!S=ejOCT)SNU4Zpo2qdk#)gxE0zWL^BuhrGx!+46eKIbb*BSd$G zZhB?j*+zJsfrw9d@2xFFBd^`3ttx29U8t*@9Ja+_-%c7fwn=-A8@AK~n;diBv2U&% z+gv$jTtD`ubI0C3ckEjI*jhtTICisuT!gp`?zu&8$wfy;dFwrAHEA;b<^~J3>~&l| zSzX3xykIs{!Guy#2pX!vTSA_?!Q@>g-)7Qea+3-7THRtoG*fLR1``^Y8&e^c32jnqtP*>} zi^#bPBiQ2+9@Sy9E|U#5+vf>}ahy?%T#)tGrtUs(&oglY$jxtWZJA1aO?tPG?;EvoEzMFZ(R#Kl4B=A05CK8m zMba2~D=!GkQrB5IrK3_{-=d+bzdj-atJl#en}*Q)N67d>Zz=0rTf(chxrF!H8ng3W zm-sfC98@qJ$HM-TVy{_9XAqZlAWTtOfMW*YHFL1&lrpsJFvpfO92C4!N>J)x?RhR) z{B9*!vjQ=kIv#BaS^TUrUirzza5@w|Li9AOt`xbo)wO6)bV@BFcq9kq1BKYM$JW3gJi>VJ&zmi%@i*ur69HLF0;-|5+ltQ{7=>bU>mr};T zPhfaACOkp#Dd$um2*Rv;h0Noc$2;gi@DD#kCBQ@?7e|?Z-i+8MV&nTV;9RVfmfnc) zbv$0F9|ISvZ&2|?h-VYqt*wnV1OX#HxidRPa%a7wNGJ76XzRR~IQEV?MEOiz{W5#L zl-M)!0B`#7uEK+>@vfTHMmS_WiA#?#?pMILznCmQAJKpz}4I>L=3w5R&VQe3s&s!vF$%#@+(aKK08cBSl&czc}JO@ zybP&(W51r^PRMO6c{MwsB8kbUr#J)8;vtMlY_Wt>0l7v_t>0=1vG*5K*6|)1m|Vx# zknzbqh%C(OK7of576g}Oc9uu4rSu_9kU@fH(H^$7qffFA0SV@^bJZ{5XOYK0ISKZx z4z$A;#hpdR7Kki}GA$h-tVaHmoRHxP$uP9rLY%0L9*s&QYJsoHi#*?rg2e{&DcEeR zv@ZUreetr}W(y}nEI<_3!Yz9D+T~J0k#Ae&5;Z1bog+|n2DREJ^^Z7=@6EZVPk-(7 z<^(PqzeU8*9=dFN+desEl5OAhy)@n^-zOj~ps^1~Q7_GOW;dUV*E@g;K92N2pyCCL z`8cS+o)ZpW9JO)EQ=Fn;$&zO|STfSG+>1NZt0U{CMT~vOx@i$(o{$8K7*cVJ;yNSc zbgRXOoBY*D|mUR!%jsEU)@Q~-gw!xe?3a~OAK&!d#L7IIhdfx{=e!(c;NQ@I5Y_2-W8+u6wwJ_LQIG0^j{*MZ=spT8B|N!)t7X8@ zus^YiHlC-FY7FRq+BTEeQ5#;8I%>1Vp`@x_tG~WYqsL-WEzL4V6DxdMhc9I$zNM&; zwJ98rlWALSUfx@4I)d$4ypvXKz7B9l@F1q+mXs-Le!qd>0?~Tk>f^|o9t4VA2gfLE zQG>LDMJqPch}@#5&M11ta0qYP9zZ3v6&RV_bH14LD#5A-d%MhTqI=p(D}m^|Tz5_- zb=LtVO;WaCfR>!jtvjES(-k~DrS*01^sGK2O-}=)jHEF^b^aOVuYQxs50TWKiZIr> zgf2n|-6Nisb}xbGd1gIJeat}*GNFv3evOH!p0Xih!E!{lrQ}12`T<%u=Dc0OIlf?9 z)IZ@kqM9=5sWDA0PBzBZC`Duar)>2m5=2W$WR5JHs^Il_^2Fbe$pKA)H*Y3D)J2W5LL>dqr&Z^h zUdsg1Soe@Tf(8Bqb{#%YqpZ4tOMS{}5lKac4+Z((Ld8!B zxm9E|Qa`Jy1S?Na7NI0+DnOMj_IG_ZA247*7Sit{2vk z4fOXMp;Y|0aQ5K15kg_{2?;odaOeooC#;wdR&ZVnAuNEbFhFA$rpvhT{zkBa9(+Y) zvbxllZrk>jb?($D=Xr0h!;z&$1p2;o{rWrCs$aW$rCuvWcI|iZ-l6{BmO-SHZQbkG zI;hr*&vA?1X@0$B(rIMhzK?|iiI{bZ#yjie4B*4M;kc>sQ zM;~h0Jpc~qP6-Zy7|40yZ${2D!;E_}QQlbzHb=Z$@2pieJWc%nRNLLO!jSBYC)AvquDu_*!uXU(@j&*VuJ;o=JSig^yrQV#sv`!#-|L#ATllT?(a|M+Asuq=-;;gzAOSCq80@lxeq( zxD?rl2-NO{X5pYdsvYJaVex2Gn=?OBFUkN6OA^0Esk>H=Z02OVbp#L3a(kqc$c^l& zxt(_afvS2EW~o0!#SHgw7MVaY6O1CgbdK+iQM*RJ5sih5{Vg&P(l`(0P^*OjK8b=# zRW=?OT!8JFyQ|gTafuy<`itGoV^5*}8U@528&Hd3&4x`Fs<4#Ym69CG!!d^g+X(-E7VPDV~jG5r5GQ%>`knX6?s(**}6Wuw+%n1kear{%k z@p%u&C!OPQ9N&^N#yd^W&KYi>hp-^oyHjjb$#I3cGj?&y^7PRPv-rY~xjs<$oeAE7 zE5bel=Xfno)1RqqtufFO<(7iBW4hf+$G9$rL1zZ?mJKy+rFFN}!HE+{XH%QoHZv<; z70w&W^Flo!1bk0{nj39EFaEPnpjEM7ZC?bgvnbKTX*wYER#U&wzred_0fDNEyq_Cw zC4OY>dlS(A6SQi0Z;X{``0v^b-nHSsE8Oq044MKasX3mkC}dKkL()Pwi{SiGTKFSW zREb9?kV(NiR1$54QX=t)alrhcJWcAz;4IL{T|)g@TOqq5t0K!1g!+ACqNH({R);l$ zA=nRWNsdk9{CO8(Y`uUpQKGzfstGKS+A)Otk~oIw3@Qr2g#Ag~f@LXV5P332c`0Qn z^cQr&ePv092U5KJAuL7{8!7A8aV_DS4?jdZaRY(u`m)SajPU{Pt*UGkztXVQSq~%k zLha=%1Pk3L;CDMtxhKT-T|&G(bobsh2C(>eGaD#V9b2H?(U$sy=mgiagMEU zh*s_eQGi3<;OfU%d1oc;**9d+2vYFyaO^<7`ZM&=ajY+f9WlweenimMb7zRc4$!K8 z>-5Pp@78_k>luzBBG^Q1lnC_~z~>CLr&pf)=e!k$?j7b6_p|`9)Q|A;KSlF%gx_Uk zG#}u>--;O3rvbx$P+=*(AJFSOy&GS!nzDxhYbWe7qEO)XEM&JR{06XlU<7vSJ7G6a ztA$y3YPDETCGW=;=0V0OYm;?Q^`^CymQ$8f@@6a{%V{BHEFtr>kRp~4*3mJsj?U0J zs(u1ReTI+?HR>mr&y-f9P=>=O>TjeL7E{#z4Qj{}V0d zg!P&rWlaSB=&RYJ7 z{+$unXe^`o_%rDjc*^@saBpqj()v6(ko3`kZwtX~7@IgE1mj zy$De7_*mW9pV$h^Ra?-UI;2A-zv(Cm5_8L60NJ(8vc=pXCO45ZxK`Zf2A5AlAsgN@ z`@7okmRWD6j#ClsB;?Ie6-7jYfGw+k#V3uBwSS4SUnE(39U0$zL$X$q5AOIr#L&p7 z4UUr;9rU478X1LcXK@mD55gzd77)HH9vCog#;z& zi4{EP7gKI1A|)v|LBxDN5_9=Jp&>8|1&}bC*-c@Mc8+Z>H(0pZtFpOPiQjZFsD9#* zDXF$P&QF~%XQUZgfM5fjS%+c+>FgXh0!(!LQWmx`@0`CXr#}%@kFNmvUt_H5Z!uQa z6pqQVLOxGerJ!<>UkpMuzod%8*d@P8vQ{^u3LBjH1cW60xL>PxT$T(V)BO#6NA_suJSQ535}^dzzRM} zZ4@FO>5=^p!d`4dY6$fenmdW!687?k1OSeSu$NKKj2A(g6zHPoDRciGI>Qz6q~GK9 zwFS?OXBu_D?ii=T*OU)()(&YN#%U>9I^6Ndk#ij^I?uYdn8;H85p!aY4Bc@uyECjH zT&llhBE%K&s%*q|q!<5Rv&oxG$jtCXuI)`9<0>pj4;mGiy>T2>$A{}x z_tsjL`3{=>2ABCLGWhVM7pO?SR>9pg{%H=Si);ay2i#lmz(tFYs_tz>4Bz-BLeDNB z^EhVp1m{fS*6h#-wi{nM?}Kz?#X>P9ZqyD(^O%wtznlYM`KYNac7U`Twu|tY(1<2d z#^X$9{}#*iC)|ZNH}Ou6j-IXG2@R{Y14*B%P@l)R0vZ|`FZ1>dCXC3E09bX8IRUkg zn4^Uy?H@2l!=9p5Lj5Td3PKuS1^fs>iZ2i$=^+{u71+T#i3GAyrjn~1z-KPz z@PDgPtISkRRrXgVQNrJW%3|d?C?&kkM6FSCMlAO z1O`H>Yo=+!w6ufFOpE-uc0r}M-5pZwm~*ssP)e^dCrhAa8n_}G{?_H4`>_a?&e z-o&$s@v(1>d6VAM568TzA51)(L~YueL2U-LDb!}YIn?G*n?~)7H;>vpYBQ*v^%hWD zKy4PaMQ;hUCDi6nJLjE8?L2B{P`lt=MC~GK^Qc|&E~9oCwX>*Q@s?3rMr{GLtKK!# zuA#Pw+I8;+YBx|@LhTjrCTcfPJBQk*yjM|s6}9uIecE$Sb5Og0+Go7iPSTs zeHOLP`V${t`oZM0%V_zW_j$B@9xYeUvW%8n-fgtpM$1*STtmx>_Xb+tK+AQs-0;4z zIks|V@5@hj`+nlMk>?E3APmv~wL#*0PIK2uyS~%&lf>-=QOCLc{{2TQPA~QbpyfT$dC4Sfz>_|+rm_hO9 zV`2^;|MipBy)9r;BwI~49dx(i$oE9B?QeO0@;r_ETZ1UriN*7+UEdYXJ6nklT&KQp z-r8#Uop-+a*4tZs5r6Er(yeX38?*pQH%f!Mpo(_twB45P2)`9~A`nd+Ims>_?%~#G zd+TA)+)9GfzuR|P&jFics~rfx=_Y>N^?E_HTF=R$mI0}{22;C$#PjRFKqc}TVKeGDw{1Eggb`66I zKN<9VujZ^fJ@-Y>8}vB%JB}B$+rD5IW=yU$!A-lA3vMe#Hx2~F(Dcz7K^F8NB)A;@ z^+gbiAO+AK>u-i<^%^ZeJsMyc7y+!q+Zv5-(CIcB4j|QNM6u|(VWUxWo~9v$4umGh zyqm^%xje@k2r1hR8%SbAi#bgqzL!s$6L*0wCjxi`h$jKxMPA};yWs#c1Kuzn&rN-~ zSQY?n>SCrrl%#IdDnS5128Faz->Ylxl>DP6u3H@PjhV08?}u7E6NLiH!xDwx3DA*R zSsFk0qr{qTkD%+hX{$?d9SaW>md2DAK7mrG7K=3VF0dH)9_YZsOd(xd5D5^#RtLly zV(n#uUJpY>5!7Q6D4=hk9`h`9Ag9#y^Dzik#VtwA`3S`6TCyu_#>$s{TioLrh~Go;UXH1T-?>PASjD8pb3x}QgBBBsNL$-wG2662&n51lx9Bm z02?i85dQIV0@r<9Ne#uQj@qAsrkdQJMme=VgK~O*7Uhi5U9;JOVOxr;Y|ijtHVKBw zt{y;;*%ZN=EtG+ooh>bUWlm5ei}Nflu(-(L5(|oQafJo->aeh<7WfTZ$r6gO2`U-$ zZ*SR>-G#Q9g|^|}%CtC(hr|MlMHcMjV8wC{zrK!3Dzv!^Qxjw3f^98a`QLSXTf=p< zYPnQFKW-h*>-Ivyl;P&|T>*}Ua!*ceFF6m|)qFyVl|~B0ljIPK(aJnv6MrE;U)};c zbQ0|5#B&HBSz*zkH1f{^WJ&7e%L8@CLTX`1Vn`_h!g`2(I{u43D4muyBvYgDx)7aC zvkBIO-tCp8S>A6F44PBbAQTuuSlz)Q+ zR+3iQ?EofTS@O#XKxE@nlvPOTcAzfYPUT`NMjSFUqLY9s};mub>>p>>4+{Q*>+(-J-uqtu@M&VfS|MA(9|dtRqaK|**6fU57% zz)9Q+&==qzq+RG-TGx)e9~Q#luz%3DhAt@@7-7hlTo9$SdVm<(<*=hd zcM!F@h62hnNH7I!h+$GFR!IJ+hp>mG@%UZXjGAZ_<0$)4t4}EZTQJ{Lo1p~ISN|+=hEKX383Dg9wpsiUW#h;oXI_~ z{0u;aZG}iy%g4fc!EYr3%_l77RwYcdMEit*qIx?JD#bMZ7r;^sb}(F8T{nvSupU4T z72gfLSnOB@)?@m|1&OBMK_4=8(@&L9Ycy07O&QSC9f-hyrloc*K!|Ru1@Rg*8N{IY z7nF=J?4+GfN?m{aAjdaFU+8c9q4V}z&h3ZrpMrkeUx6oM29!9G8b#hz5YGteJryKHtlQ%k<^du5o>M6gH(=-;gt}E^lT<^I7n%H z^lal^_|k1``DMJ~CcqIQgALuKnO@$I$qWSOP&@iROxa7Nx7p%eZ;O0 zzm1d|xgdx;z=PGj=eONKNV3;Hf$Z(Wr}yRh_TY-voQ+b5ELV;aiy$)}?zo_qk`X+N zGXj??d`LN7rvtCK4)lX%z@U+6!6Z22(zslK@WDg~3PJbKhF}!HcO=}<=1JS6;A!&Q zW(??;dr6G%--NT(!KBeiEXP%kCo(J{{9X(MYc>Qn2jG3_5r4$k)d!mv1b66l)|9!^ zg$gx8&@4sw3|jSiK5eRzHDPMhG-fhYfRfAbeMgV%bO!Vii`XN7@1|)#xwpECHTYo+ zhN-zKB2>fBtMHl;=!!b4JD9xN4EIeXH2W5P}e8vA_%XbOR4@Bd0Cmo5S*mMH-rwt z3jNnpNGv2yWj^0XZ15(zt`>gvCqQNDEa6#M)qTsmE3L$(j(Ef53+U zchx1GAx3`iSexkcVaHMts-RU6Au=Nkb3T#B$k5G>3(eH@A@*&|v3o3Gcm&mTL__na zo}c@Ef8=p%6`O-*LcalIq{B!qP45U3#gx(=NjN5+SH0wR8vv7X%)rAMp#&T0x-=R? z7@{trRRcmsH_#$VAJh-LEsd=K8jZ5%)=wMI=)D~(E8q2u9Y^*xfdjBp#gqyue!z6# zG9xT7Y&)Q132)6-V0c6!xaR<$BA=NeP-_i_5p%rnvJ$KE8-=J=4kHu{;(z$wyG}CF*etV8z6!(C!>c(dPjh*) zuY3fufPs>>L2N^?=KPxSvJJCBdV>IlSh?!XoRdi<7PLl$a@FHi+?@+nZVnYfXge^@ zv8DV?qtOLrcC6(FijRO7jH*Th2G};pRoNx|0Z6VjY??r3HyYTX5`Id%4KxJr)d=M~ zx!jlV$-67&S)M?>h1h3WnlCoMn)FH9@S6M{T||(1`3YF}46{Ok!}NTl_6KwC-GZ-l zADS+l4)6&^kyQCm#n<3!O7kum^!xCo;OBcxfvCZ1qGPvFa)Z9f9u80~N0|R|-n(~+ zXebtRgDJlc==m?;5Qp##$>W*!Af%|+jR&`&^#%zg$;aGu<7TA=5pA6UHxe_9;Wf!1JQf}e92q8-vJyM1fQAJ$ z9j?K4iR^o$#Y7hV@iX5M`%_e2en)J74*O!W`)5$j?a!k;vws%l{Qd&Uv-^uE7xtG> zF7BU0xwL;C<+=R}D9`U-M0sKV63UDFmr-8Yzk>4e{xZrd`&Use?_WcCb^kibYi9TD zdXXKHO>rY4o0e)Oo0cjWdvI+!Jnknty`7S(~3^rZrp%;cKOeO?Z<(97Cem6q2B(v&Dy$ zgqzyba({~CzbCn{FN_Na24i@Ykt%H}<+H<|9olSH0lxAUWd)$P!!KpQx|M6DcmFUi z$}mbx>;@WbN<&DxA;or|RFAsqGDU+vhMN`&P?2dI)s0h}`|RtKU@Gp}Xz1J8?fgC} zWzc#M>5V{X4=U>t3KLVYq+}a8I$fxoym7R{LkBMAcZzXOlnW<$FuQgToU-c&u4H9O z@w8-OW;2LY78P9fQxc@iL6hkLd&>{Y#Fz8TvC{$WqTjz{-!ji^erjB>#o~uaG_3I! zN*RkEhEpdmXeuo-J@$U4Q$D0M)5gx{0M-ygW!s2S=1HB5V{N|sU3ru4qms7W$PITP zz>_*$4_!(_72xjS@3JrYOGiH?53aFlhUMUlWie)77HE1~dH zy4L8n@$B5t3|A%;g5ScuRcQS?b|iZr-@7pay&SDfxjbf`$D8Q+=j>e~b_NNAY_Sl_ zU)Ffbk%(RV$Zz%sN%y`=ApA4TShtuk&1n+|y9obaM`bj{O8-zsit~i~C{9C9!P(R~ zj55O8s7or+mhw>2n(nNSF-++h9h0rU=4o9THf6;M(GFcSq-m%jbXd9!;+!8!`Ax%V zU3!Ru+39QQ^uEJK%6lK?Hu*!X=F}@udoSO|NMppfYk{A(Yq998cGF(CD%!2Dy!pj9 zUx%m1REfJ^lAUd|n1{?ie&)POGwC2Z*>LkzHmm7nD18g8C=UE% zV(3Ne2Lwe5qRWU4P?H5@**S2CwFiu?jVgo1q_(JWbZ$q%qSBy8;)~3kSBW3Rk8~h( zcGQPY9!k#Vd{mbs1bxC(_Ziila$IN>8nyi;d@ow7aQ`2KdMS1MwFBW>P{HwK{W}=t z-#C&a0Va#H#UcSFC9d(7BT3*=#T4ED2Ept0LgHI!9?9raLRu4u6{1k`+sC$*7S=t) ztsy#;;R)WYBom7cbh3>#gOb{o!T%z}Q{>K)IAlk(&zUuAiK4Q>ZA;FA;^=+8+^LL1 zC&6w`Jcl8wKLQx}5)~Os9c!|i$}6tGyJE?bT(3?Sk-?&S4mnWIMJC#)SU)JBi1rZv z7SfE&AOY9`X58lZQ9S5$v4z64JanW(C{pHF-2^EQo{TU&^@~>VNSby<jt zS3(=7BIwJ5Mb@1rw6xDzsI6571c7c0tv1o9G@K*{y}~Da0<~W*LtqvJEQEukn5!vw z!DHZ#LBrgY0~|3m3|xvvm;W=?>jqwQvBW6~;0=YNtw7O+P^jECbGY zICtEum%Rx}LeM|VHmT*b+=WEH}G6$yxh2>+~vpVe~jaw;1w1_=4b&k0=jaU~v#gRJP$^A{(J zHXCdFd=WPmw864jtswWx_7fejTg4%`Qc#dal;Bcrt+V-Wb|Y1GbWNM*lrn|FYj|)&@(O^$-Tcm zcGL)cR9cPPf>v4c{6^M8`kTrU9hKRmda>AXgxLP})2EL&sa+3XPbCkI5iOeHoJ@%5 zn}A>y>hBTtWVtbfh(yI}!b$nv^kph&$mA!n%d8=u^q{UN0IyU9l*I-z&yX|) zqu~L~s>n}Qfq7;j;_%Mu6PX-a)*;E`Z{dbs4+p$?tUl^6RT@)EYK+`y4MQU2A3sU% zQo}6c%czDiI$=^U1e48bgvqmY#y6M2nRoH?fhX=Bk@QQx`6U8NQEQMLbj@WVL z-^lrj5gE2ve8mN>;W}!M=`81@iEi(o^%t5J5JwWXni48y9}Z-X&~QIFnz}SN3-jhV z%qn>*CU>A<(trYBtBa1Lj}fB=*$mqH(Z^%8)1mv$d5ttxrd-zZaQh@6L`Z#?kYWU* zObUhwCbCH^RBFzZNu`kA$F13nnst>(-7?5wL~ieL3C20%j~#D+4`Xhce&vCEwpd7~ zUSGp?bPQ&4y`Q*0#`5tAKSDZ}^jnoDXT5hq(?O0i30Zqb&<&9WO-j(mreH$zw6G!_ zaAOUltn;2SX$&KUh|zxjy2-N0{d(y>z$%wF=vfy2raTxyqg@m02*TO7&ga{3i-X=e zM~|lf)x!0emy!OsAd8~Pi@T5G^*oHS$zzL0tx(IodLH2<*beh!<>oFDIS( z3BIHNiL!$}yaC%&EL-@MFkt?1Cl);MpwD*|Z$lV?wE<>|7p7G9mUfXu?#ZK4@bn<# z3w5jsL3@AZWef843Ph#u+VYHY`1S@V)Bcc@AXUWC05VBSe2~K5a>3xh+s92vCpvLn z2JXqs8P0{_%4H*L_?GW3FWZrQVow z&}nq#4H+RemrYA9Rel3wwAqCbTFmAQfn;ZLgmH0Ngb~y-j@Z5QM5}j==T>0N5zOCUp zT4pXL#cS5Pg#Osxd-H0@Nly7F3d4ySC1mkE<@)b zi4DR@9$J+Fq$Xqob7paRR(TtZ23}4hZ7wOGFp@=kZ3MRvZ-B-x^+d`*Gz#s?-G#_N zDxi#atJj@q{>~G;A@(3aDL(1+SOchZH#O@*s5%^8s+-<6lmYEsYU3~LqXyV;VB(QKg%S!ME_Ek&a@F;n#hzNh^5A&Vjx z__ta8h{YO<3QhDER22+gk4=uooA)jl`Cq7{d1D10Uo}0!C_mzOoX6a<3MmV=TI%WL zEx{!^^hG$$T}9`|4k!m7Y*q(VKG76JjB;f9A?Z^ykT(2OV(-W{FSi4+XVrsF)O>py%pE(229Vjz^A?OJq6C7#Cn;1;qP(@xpGnR-9z+AQQRS?w)?3~}h z6#mNeJ~szDhb<>0r1^q~_I`9E1tE>}^b`YAo1)iki5Q2S@d^!E?ef^?sO$UkI}H*& zW}`u3rh@1HmS7{QvC(j;Sb2etpj*V$xgDoe-#-*p-KzNT`k?yV!((Zdg z#A5I3pdEx7VScK2wo2D($8S1JSLM4%y0k@bhMOnHu?ZU>RX|{08gFJn;LA=3V}{^; zT=Lzg>Db5PALGrZAoq#=$sbIOtE!^7zZ-gazbQW{N4a(Jm161 zcJXRQwf4Q*CSGDe*%RVyKazL!kGU6@N338r`st~Fzx+g7n(w{n0=9U&$O!nw7FH*I zpT!@rsG#_NEP?x#(FL6f+I5VXS$rM=BY4q<*_d$d&SYaeiWPxG5=IT%&V1aKNW6VVB(h+ zZrE}{++6rDQXs@TJ2WHw(K=$5c`7tz&!BXVdQAxgtkxFba~_LV@4f3GVT$TqXZFY! znW{WG+!WCukC=a=BpIU_GEYjTKk3(r%DYd6!bR-ez0Uy4NqFktOQ^ds0-95yjR^Xe z9Bq>jU~Jh~c}2eR^4XI8PG>2lMzH;I#aN>>aq>;LU%UbgMdGq|wkr`Mc%hdalUmBH2nXJ7wMrBeVRhZXE>DXx2k`G>B zAt^d~`lQ?K4iLeLBB=xmC-QHwXf&;~riF?HG_C0|;UPVAO??QDo^=dQ;FS=Zp^Qu8 z+MJo!2G}?8?{JvAz~P&`ARH1TsES31)Rdwy4jd{F_mHG64~ayQg)Y@+bp#KMxI0DL zSR#x(pJUZ*)w6@ILlj}5m>c_8d;M-k*f#}WyyxD$J5!uiCft;N2j6CxE3qSnb`g;)p@h*=J^z@|z?a@cN9n3~2; z%jH2k``qO|SoEln`5rcH$LCJF=X(2&N9ka{_o%bmA%p(Gevj;RJ+FJv_q>Bn-@*M} zx8Ih+ZRY{qShxu&bMo-{V36nMWF;X}NMFEQ!Sfu$^{C4vo-Iv|6O+UUC4gS z>t5KwOfHhE1Na{MG5t~q4lx|*GpM+imH4!X?Nmb`a9%=IadLa`kHsi%;K0sT-PJ_(tE5+ONsbmVS6k*R};Gx&C{*ry)qKr*NoNFHQp8LFfJ*r zWe?%aDE%ialrb}PTLEI1uFUxZWz9;L&{nRkSy`>kDy00gd2EyoRXwYVz6m|SG+r8^ z^@Fk0U3;T0S=G(FKy$h@GcOy3m)fOWGWf4B>}^sb+1R#QHhJ~vs%evt63gx+?>AoVG=iN5Ica<~Ys^HM4GRnH6hgUD<-&Mj_4T z?AvA~t&YcpyW?>dX%?2a1GX}PW;!cAGw<4QTKfz_ihcU|JFt^lRJQJ#HLG_2U-$}B Aq5uE@ literal 0 HcmV?d00001 diff --git a/venv/Lib/site-packages/firebase_admin/__pycache__/_sseclient.cpython-36.pyc b/venv/Lib/site-packages/firebase_admin/__pycache__/_sseclient.cpython-36.pyc new file mode 100644 index 0000000000000000000000000000000000000000..d8d3be45f3ad87855a1abd277ab9e47f017e2a83 GIT binary patch literal 5930 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 YjY&<{3nvRdR+5Et1@~Aw{u@pIAIb1;)c^nh literal 0 HcmV?d00001 diff --git a/venv/Lib/site-packages/firebase_admin/__pycache__/_user_identifier.cpython-36.pyc b/venv/Lib/site-packages/firebase_admin/__pycache__/_user_identifier.cpython-36.pyc new file mode 100644 index 0000000000000000000000000000000000000000..cd7daa362657b88580b19285106f77605c8a57b3 GIT binary patch literal 3443 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 RDb8J*`=#7txZasN`Ts}@9nt^* literal 0 HcmV?d00001 diff --git a/venv/Lib/site-packages/firebase_admin/__pycache__/_user_mgt.cpython-36.pyc b/venv/Lib/site-packages/firebase_admin/__pycache__/_user_mgt.cpython-36.pyc new file mode 100644 index 0000000000000000000000000000000000000000..29aae9fcbe1c2406025251ff8ce9ed481e5eaae7 GIT binary patch literal 30671 zcmdUYYiwladEVSPGaL@NT<%S)%hBq#R93T+CCk=kBP_MMl4$R8w@XU4Mym{ma}LQN zhclz^oY@t}Lp#x`ukM!aniGlnm z(4s926zTK4-?`2Vxs*_&?d;CsxqRolyx)6&-|w5}r>2UZ+xVb%@ym(Cj}nnj2IrUX zwcku85@w>BFq3Agm8>T5H{D9@q^s$qzL%+Ha4*x!?&PXD@7_dp0{615{7#`-kb60t z7pp}%pTPNKbyCjrI4@O8a$aan?Ubu!oENLp_|90#ts~~-y<~OvwS-wRr#?uSQ}H%CmfUDEygSdJSSEq6HkohpK9>&#!xO&7iaAion58?Vz^9-)f z;OWEWW9H)@B&v_#?i1#dxcemT8n}AOJd3NdR$=Q=w0_1+EhpyZ`;WicRMuMEwv3)_ zDPyPJu5Va7R@*V`-kPz~F?%hm@?%cR(tOgLG_Cb|ujQD{hJ(v&x2|l9_iOc@vsvpo z&6bVJd`+!4o`3%NmvBB)W5uO-tck$-B4H?I_k$xT;h~Ew#{)mm39_&W(z!k?e~cH_cr4#U2^R(E=vw>xdi zRLwiqZPT*1olf_5uid=cQQNn7t-3N^xNQT3wgY%Rce`P2yztU(=kk|WjP$EQFk2GTi`QIh}+C7>scj zY;{u*LMHfb-8N)U^@amRZJb@a0-m&OwZUkGlq_@pkVtcV6z>G*!ihL%bd<5W1gWrU zG}mLDh+tvcx&zG9{iy`^fkvnHha5@n^8w`Y{V|XmCEWDV($aiEP2)W^!^06A+=*Jv z>@;dMVd`!k+_!5fXLo=47Q_}JpT+yn;44I)Pi9hyWHDbVlnRPZ8u$hua>h&e+F!&W z%D}CRnKIMDp0ha5m|2g7XUv>A;j!?HnKuiXg`-T-oRsqd&PDeE%P*Q`NbPAiPZXlY z(EsX!(de`wM?`dX)(!B}wpmxE;RzVf%z8)d2*WjSW@!22%|7Z8X=T0F?LZ3}_l^>d zf?{jClxA9$aduhu4lb0Q%<%|IRmMrY5AlF*r}~e2+$qEn;3fL(Y&LD-Ocm-QN0&Oz z;!d|EikM}Jb~K*dxanTgyiItEtWWnvb@Q>IZbB)0U3&7 z)#^t2G#kJyczmc1eJ9!>AM>qo6czBt6;eh6WVZ%3Z`hl#7!0!mWN2$7J!@4qD#k{q zvjIb;(b<_7W=zE(pi|Hn-oMec+KX3$dV{BNDyBdK2_A$(ll~hpYI*@sCi-(BP&~$f z0!#CgLyTBGfOphs9vDi$Fpeh?4d#Mh?YmCs~SrL6x?@mT}k z;FI>w>_5awlox+Bu@0LF+&C}lbjXXLSO>f~8{x&-2rtftycjBX*_;+0J&E%f^N5_6 za6W4umGdc_&zZ;Myo~eX<_S5U#`#I}l$_7t`~mZ{oFBpYgXTkWKKoTD+ts6BoDaK2 z0{0e_KV|kW1d99t+I!rt_0{;8O-T6gYg0FI5)Q1wd#SC|J?N!QdXRK7_fqzgPS#9r z(Y9&+HZ3iRlS9~^6_RKiiC1^E)>_#uW$9`voqP)|hWcwe!7(3szkj`^^n z`*09wgBGHyz!L4a~Bd5IiPGscKS(lnTZ6qez4+6mY5CF#M8;2Y)^^|?bnMd!O&Ks(Ah(Vsg0KXR* zq)2IxilrLrHn9-~UI{u_JiWae8<{8G$*VsJ?}7(|{Mrc&2v#J#E2Q9R-gol}Q{IO~ zJ%%3sATqe)5!{VvDY4;E;t6}EY3R`HlH7t1mGVtYl<)dOy}M~ajZ(t4;v^Rxw6O_G zd(DDj4eOQ;Uh`nHdacuG!4ad#sI{rA>mI4*9F#WGc(vYwRn}og?!x&K0?3_`_uljx zolmg@F9oV%a1?;P+AYK`UleCXDJNr)Rwt$jr>5SFxcL7UeAx}$pS zhWL2Fnw~SXGm+5jsd{5K@|xGDs1s4#h`?OmV|)Kz##-a(bbBEV)7V&OwX|c(23FWT zdKvWKoK1MOw08?5BhR3(0ne3n2O|cV@pXROqUfB+Pk!rWM8vedc@VL0Y}wq@46tW&my5%+A5>zn5~dK&jk4BGv?s zse6q4IVv~c7{ zIeOY_g9OLBol_^BB+mwkQy3x0!;4LMTIy#|6q4jOyE5}BYL#!~Z5rpiUJJM5P$(bt!%Q}mkN(mv7!N3f|{5Vy5uE;!XmKEBr3 zXto!e`CN!#id|G$9I9oB3fAB?5I3p#2Tgk?yUeB>p;_65jbx-Vb9^>4BqYvh&HZ22gQl0U8;14YZE)wrD0Zym>1`zh0 z(q0m31o-;jOuY-P?#-4vbJJ6k{Av(cO;w(CvjBnG9pXDbDPCl6;lJs={J&T`XC{~E zpNmYP-z_m>L-Y+_jA?_K*HsJtTlP?k?v(#T>ie&3lw(U2Ks8a!i4_Y#K`Le+FXL-J zjYC}EsVAM(7JLZgR)bVCv7J^=4iIsdz+}4rY*|1n1bKXi zurKQ)SmnJO6;8DKIpv{afw<{aIcgrx=r$MpxU7wUa7fE;X3Orh-E6BKf@uz$pHbP!Z3;L`mX-2pYtp8Y><^mHaV)D&G&GD!OUQhnwgMR+~!n zCse|n;O+g)jA~w&Su|saHP%_+7Iay7{H8Dn-(?UrHi824b7MV%^tc?xE%*Y>318RZ6*TWfr#wI?AQXZs-Wl{E zsC}d_XpYc;T|v#%aCW;*_$eVeVCwBOHx%M&7?~%UA-%sP2xwC@mlB58ckv3u=K z2x_ze-Y4FB&oD&mcbbUu`__&LC9C}u2ZDeuoS-{UnBheYh5!kP!~sAQQ1ZdTexSp` zPSL`uj?%71l;@IP^mV{zDW)`+UU~6_nxBZ|YtK`D`5FN_#0S+iAl?Jy01W&=P0kAE zGe*(A600UaT)Y}0?kES`7g34+oT>j05LLSR{}`eI!vi$>sUa#H9*xmhxF+bskSh9{9a$j@;SMH8OLCHp7h;~gLIA=A2yugpDFHcVEs|AS?! zvg^k9@t%WALt(zUNavy;5%Y#F5_v~D8bCxWp}UY`nBaGN%&ask#*KDsSA!PZoe4mE zE-({U5X}ilSNIJrMu)7RG7m@C5Jg-YS_H~O+$qqKZeTDmLt8Lj@cggf(Q5%s<@$3& z0Fs`^*!g(qycvbg*lCRnD;PFhUp18c-3GqFhxB&|Uz@z;f5Sk*rk<{#)NSm#%pf?e2QHO@GAt^4LFyIv<%eKKRAgZT+qH3Vd!3v}m@6q{9 zZQ9yQAKmQWJ*E{o3VMlxR}IKKq{%^p64ezIGl7q`9h(>3>MoRYN^WH#xM|(N>oT`U zzqX0&3=^QJO-d5n5^Oe*5ey9st>QJLJECGFC#|mP+g7dKY6-XV5-0GYD4O15X~5Z3 zo!$nNXEZMr>#kYG@R*^n)m5nM1-;iuH$E>`RBp+#9;C@j!BiLb_d{D4RXu!DypRYR^c_)H~LZ`&k8Zl5i!*WS5 zv*R(87|+Yd`Gl7-pHZildq!xQPNBdR^h)SoSzR4f?;vRc)^61AAYe&ve{A;S*2-c1 zDk4;&1u#L{&2Zv|M}7%UHhdz759O)&s5KG=-oMa&qDa!HnfWCL#l>07^y^Qg`$xyr zA7g-|asesl#JA{~Ax+b(|M{CFM4g-Inc_lCAfdMPp2mLTY}9lB6yfK98=o#$tWf~p z7ZRDTxKn(E6|M+^9AY@`G+(KOSk;US?VQL_UtBO4nX>5h z(;X*^@S|&C_eE?4s8Yd9NSx*!)Hhxhxl^z}YC)&kk&d5^cRW@u*6je@eIuEkXv`5P z75=NlR))THF9`aZ@V<~m0q$gQY&gzEJwpu+Mp$s+NDg$c8=@Dz;q&PW#?o-LsLu0X z>4+hiC;qbs^cPDHLix9Z#Q2{F#1ws$YJ~>^P`!b}eo)+if*3&2CKQEdAOfn_TFXUd&s=U2^#^= zFe49ihW!}2fICY?$xob5M%BD3gd0Me&mV1_yUcs}U@kG|aUS4J|=?6q|Tmm7x6c`ACbtgdrSPmoS zI7288M=aDsk5c^~#f_?w{vE=u(mmE|I-s42^M}@i4Ylg7s&~6u*{TPaNy}>WmAcc| z)XgpEU_5O}c`cOKA#NEEOirB%3;YA@lZ7OHS`VNlAmW-WtZ|}@ir8^rMQ#q_xdW3c z-GaJOuGzgt1L?~($pXOjI`o2`vb^hwnl9}tJvlu@H!FQmM2`qw1zOIBL@9AM<#Upx z*MDFHp5t{Lyg0^g`?nsEY9_DKntkOH_k2@JMh+NzV_NUEV2_FG_h=b+Rg+3|2g$xz=K~43s#^%qkMc37HWClVD~Mvny5aRLoJX(( z3xnNOXPl|96eem|o7ii<^ZO&J9ZX$ToE78g~n`Sy^;ZJGIC7R6?#OC3w>XoMSP zj|rZFc>)MfR>inxwKw2Q7v2QP-y*i)FRUYwWW=Yo8XHH%#|uzx>(TWCcwd4HH#L(6y#PruIAs3(eLJXI=|CKT_J!h;W4>m__`=8MM! z05XsDQb>s==G@Z2u3BmLQMHQz-s*L0W%j!lW|dauAU$wqcH}KhbbWt zTR-p{OBDK#AEq&`)z0qkl^UmUwa|g@vmJto#HM&>gv@X+VQ=CPC9|K#A_-a0P=W?D zqkay}^>2Y#^pa#hEeANZfwgNy^3Bd&!&@p1Znxcrt3+0y!Qz2CrqOHF5fK%CaC9wN zjCRv#gx~+WD;%<_e)q8J8`P8Nt^h|bK7WdrR4&y#56rX>--Ki<_$c-a?gHy7d>C?C zvgLol$>*)u5{6Tr|4xb3z{PU@!uWu;@LtIISb^`i&{?ues*QVS{~Z1t`x-iA0KI6(rXV7Y=(;t z0qjRn%#E}=I_yu9*1n{kJ6!W;Q0z}5%|9?Q?C}Zb2hF%!?0RWbhe<<`g=7CY(uD^{ zyWmxaOqKbm{kiEO)~CIW;f7Mgr$6EEWN!bA-C#^jf`R!`#{VbO9pk}tw_L*a{;JOG zf-Ic6j2sNaPw14k`@a-0QHDvdIflt>Sv>1m=i%wVt`l5LAOgK3TYNxkTxgrB1M`EK zBh4Gj3_D3>TFQbgU>6AH4IrVov+Zjfg0yhf$UiBdpI@7h;5vuZ9K@~m>o>unDd?F6IkJ^TJ9{IE@q2{qG@q|2$;9-QF9l| zbeoMDy8=%-*F?Hg&5m7LL*NjFo2EO5*Emr4HyhkNM3(2eNBz6vqDGDot2^P}#HJ$6 zo!$;p(}!X%Zf$U0}W_ z-`!3ZS{368)Y5NVU0yNj-6r)dETe;g>N{wCZecuwklQFCuln9Ae}Rw0-k52tlgFej zq@AJY1;|$iQo~cwPecp-XRZIO(`RiG+9snzL0sym1qby0*xmITpbbK9c zw=A;h#r8tC+kgImdd9FZUC|Nm$u*4Xim$_z7URIm;nm_CP7Y^tI#y!GsJ+OF>ZfZ`t3D9Se$OI2-vhJvWRa;Ttrn&W=8157QMt)9-8^tg5`W!X+j6jSKs0e| z-1T0=5}B$cgJ|o|;{}lsZW{4CEht1hh@hazz+$bu4^1dI0ePvbd^Ijb+|!zBYMQ3C z1oU72ALRDjX#{KGAz$*T6c(lAk~46FmXpWRMY$>_i;=TZaBqg|nNuZ{%;Bs!_Dp>l zb;op-0&ZNw*XEO`y=bPe4c%$k*d$r?7SdO9I!yta(WR~YdP-6il1No}P?8n6oykM8 zgg#lF)XV3qCG%m~HZED6!ZvT*FfLgwgKoK1ToRko$tH2t8F9Eg>Q2&vxh|Wwss1aT zvKLQFpwAksnDm|0pZ6_G$9tl8SO7b; zE6CD6f9JXQj#xn)@lybcx4&8v`(iPY=i7S0Zl=-ym+Oya^uFe&o8djpyj!F zX2)_xr@!Fj7f`B79h$X5Ba#H^Aruo!^AZ#_?L`*^Lb|#nZ+ox}bdx}rm_Wr`?(%tj z?f-~_i6jRsDy8oOPS1^ zS2~B%h@r$vUo@c?p!Cyju>gM9YX=i`D5CR(89V zcnCG_P9f!G+d|HZq_l|>p?ZY$ywq`CW$vGpMMfr7RyVhO7o)b-1zc3~07MNL*_J!e zt?x<#4OYLJyKW)q@eq!?c}A`|2d@&*4b+lI<-sYBV9j<-1RRfr|Gmw-Lm9lR_++y)4M&sQnkt+}1G= zQ5Hl*!pLkLH_J>20%1(oJAmmmpd56sF1GJzIZbTdQ0@F6m0%6YS zjSTR|X;kLJB#BX1wdTe0<^{drEJy==`yCwtjTC{=D(Nx4*~&>D@hxiwlVk#=u-ElA zCy~thi$7;P_w2J!R+;SKtGot2V}tkfO}|YI_HCWKbI!}}e+M07V4aFBA5+a5^5E02 zAM2Q8is~?uPjpDFR1szluH1Epr?uKf~dw}p!!){ zt0E%-KqULs_BNaxZMqlKhnx!AhW)Pfezx~x6C~GvZZ*=i)zE^_d&rENPT{|r<&wWv zr`Ijyzk-L!k{od|b#Pz&oBfx3{glYC3y>LSBJG`#P+Y}`a%eIo@XtN<0lT*!NAAzP z8pJ%oSTv=8PrkPYRe?oD9+UpDILarMzO^Jp{)>EB&qiHS%bL!^c!vJhW*i@&l za*L4gsf@QeeUm$NMeaVzdS-714mOOkNh%XJTD9cK1V!$yS$2lQQ-7V^Np-fh5IC{V ztZT1uPPlhS{Cchomhz8Ni270J1OWrSP-e!p&X{o39r)5-p6a2hYsjO$sDu|XmxAG0e<{U;*{gR)f;Eaf^93EIy@lLRaMN3Pf3 zBaJbmRMP_s(x)d$9F-r#cu4d=J+_nqg#uf|Vx5tn^3me9bCUZ+jiXvb>M4kvb*r~g zkIZ&|Hq=0*+pk&N-k3`!>pM0ixnS>?SX@jiu9E2F3QO4ffK(Jf517((X%+yEuy@JHG6N3V@fCLk5_X?251#b5{D3}w1 zB*neSK@kY~w+2PH$WR~9^4HPgq*)kD0+A@2y(fZ7FJ0zdvhe5tL#(@60rc0C1=di& z&Z!1+S4_%1rocae;VQ;lLWU{90BoP>EkIPHNm-5=SO%mknnTO@%Hql<)QWeGL-Ur! zz-9tNht57oeoNL%BdjT8k3||U;|({t?I!OGF#;@)rVN$k(Z9o4B}YV%_GhAVr&kfm z)JNj7!F!q`7Xl3Rm1B;v|3Ju(y~T(=w0y2SUlMkwzRErx3sl``97%l*&(vRIfpA;m zAmrg530?|-_dLsHk#VdeDdO9Ji5O|w$+?+>z4@>is!DAQ81K!QZc0!o(D_Xi~s3(m0- zE9(E#K}O#CH|FF9OO-C_`imrIT+_2F{%G+O7p3ffgYO)E=|Ryc(OavE&eT?U00q6B z8Wi`Y(7WjYe7$(Pe9_w^e=xZ<;}P~G2>S>(%g6JhLfGZK=|PzuX#0zUGL-N+k~ZpX zp{Aqev8_2SrXNh3$A!eb5+Lyt{g>b9!V)EkBVU54WK?`9Ed0D$tzU@>DZV}EZ4p9; zEvoKeBGqScSOT*ZqBnR)aO_2%k;>ts(R=og=&GeFi_15!Exc7*TDX2ycto{u^Yt4m zH|U2DCIM%Sq+JH9?5kNZ1mVt+`@Y^GcCLB_E&Ly1A?nxIb=h z|L6%A@54VL8l5g5V!RoEk64V9)6PtG8ipM&+?1}=w{8{PS>s;4_HiWe*yI!7Npu1G8mDsaCCkw zE<+U2>+D5`LxSc`=Z;mK)(875bCVGO{{biA71Wl%W-y>MMKbo)NtJ`Y zT2#xu6vcN2;`?N>EUfA{u4b@AFDe8gZ3LD&g;5q?VO2MA0+I??RgyL@lsGz^25?T9 zIUz^xy+g(Cvjgm7!CiJBXRqNs?9dG9PEt&p1(Kp!6gm58oirEm4h8zHEKQ12pHS!G zl}bQ+AD~xJYe7?pkfMiRZU%8!vme1QU1k)+NW&bmh^n!(?rlaRvSnZ08^3kI-!Bk) z_z#>eChR3JH77+z#K9gZ`)W+FrgANCAK(NYlA@EiM;{5`4>ultBoF&a^?OjV;TxHS zZ$$Px;+%Y#g0JFn@k_|h9&jBMeHdomSDBq0nD+!!@fO~~nm7mo(So3&XP`SljNF5e zz#Nt8Kf)-k$e_Y$!deR7hT3nQnr74qFzTIvbp$_Lm=db}09^70-9zsZz}aUp-xlZm zqYo0~(x8j1zx1u?>)Zx4V!}pT5`Gc>g$J);)pRWvu*{sh`37#4J1czR9V(mT!p8?iK!kOW1+-6+SKZYU$k$vjmn+V(oW1S@j zq`6%%mc=W;-6sy4&EDO`>O(BXkPU`@+Kv%ALY@tV=YuN19?U1bDuF5;dMa3S9~=3n z;u(=WtNKr`65%|T2qGXO9+428;#}xhpdnun8%|Tqe5#uFHtMzAtl*r-nEDIh;5?TO zb}SUH6|fv0EAF<$AAHdZ1jH*B{5XnWqOW4>w8^66C`P;=L%d9ENRfQhlVe_n42N7T zMJYn>F}*L7D``~M_TrzB%Q4$HF_%f^5DycvB(@`e)gy&#y)%-p7e`-?aXnh1!u9?H zC%Z4xd0@|Jzpz7|M@Is}9B?k+AKVGvZv*I^w(cd>MLdV<`F;`!77rr9B8vozs+V8^ z#{!?|#0u_LZQ@r2^qX`spsu{!Nz?O7D-!j67hE#sOu(*8+22Op1=aw6Z~@Y-cn@Vn z3PL3|Cn48LG2ROG*8U-tTXTxx5bga1Kb^*A&+-FCnwf6ESAtUm3@%uM#l2A~ z&{c)=jdNSj^wyfHzo^moHW=X9+(sIaH@YnN!AyxrU&ddVGTDi1R`0~ccoV%g(fzp6 zT4SQcQk~KLW>@q!1W2uW84uiKZ&+cxgxj-ew7~}b{kZ(;Z_4mB?nEq34n!=~{u4L! z=GEd{C8~R@D&~N#^p6V_1TGp`fQ7}f;s=b47#-18^&C$8y~h|6yB8a4(w)HOb2NOt zfvMj|`Ef%#5e_ZZ5J^rz8*Ru0mTl)WP(k~j^Xt4{BPYW~`WN*Mf_ehD;S3Ws{6HA- zMZ?sSP~xEQjb*!{E%;&nbXgo6J~KKIYT(hTd=@i5EsVuIMyJ!_^_w?t`EIA>#p=~C z$JR~P+q>%P9HQ_W!5jTc2{P&Ix|`F=ruqXG6YW~qlJG0?Cf{*Ie{MC8HK?0dm%ecy zQ@s?$s!4+GNxYswWS@KbQ9-816Y+hhz{lwa#rYi6XYq8(zHQ^sGgzh0fdsnnCN8ut zEG9Z5)ndSZl-@&hN<9q?O5#-HA;KYKoXe6J|+eZLCW;;|QMinkE6GFS%m*FXGZ&Y+9l-@l%wWrP*PsvGbdGWQS#U)@k1DMVvPxW-vORdXJjYg+60JvW3&^oGQ- zHmF=syOjJW^hE2FIyFfY+B!lzYa)NUU3due?og2pLUo2{6G`CyPsB(SBaL{uSh9Ts zS7}*YX;Vkp!CI67`LKRg=-j%4tL4rBoLT>;;Xk-izAHHGZcp7*t}?p2{lpwDnd*O1aGg* zr>m1*OnimW76U|Dol=r6ccZg*4NZ+OLTsyP;u-VJJVscZ=;*TjCqj>jds-gJp2L<)g#PZsDU`S0f^*U=e^kch4%g-^h-I-fDSt3k3qp+!-@=_7G z7P009S@l|4PXxI+y-^DiMe0~O|2Nn&Gu*HlDRFyPHJ~heg-{lg9|DHL2cZ(#Al!#- zEPI1%lkz%i8F|YE|7>YK`KtWH4Rj z@I4;B&%;0FK_qVI;FB{d-s&qj{48~O11HSB&!mdE{IUG`@+@`*KFU1h;xqYt@$uq` zq9LUlC>VS&@Wds2?UOk88E#fuFZ;t!aAovjKedX-f!0LDl;6wvN*Wc=21o?C2gszV zQ~ri7veAZ)@Q&R`Q(Se|2zzRriB$h+Y-xW*Vg+L|!)3jKxcSCGWEE9?&aV_dSIO)7 z$7J=Uo6{RAx=4KWe?`nzY+QR5b70o3=9(f@)IY(YT3(O+0H^jfQKwLJ_9#)6PRGks zL`kk`)kfu6OlJ8X;><0qz4(I8aa1Hi`7KTL+dP})fdM?(fKzsUkv)|3<`!#w(Bgs1 zEhN)j^CixIwZtgtB2)j60xScLV0nNmZvLYF>Ccy^@sdp|0NWCXT2)FhInw(F9s>m{ oUC!mx<@xgb%vTbpW*#d)RDQnvba{H_@$yXmO8F~^uOyEAZ*^z^A^-pY literal 0 HcmV?d00001 diff --git a/venv/Lib/site-packages/firebase_admin/__pycache__/_utils.cpython-36.pyc b/venv/Lib/site-packages/firebase_admin/__pycache__/_utils.cpython-36.pyc new file mode 100644 index 0000000000000000000000000000000000000000..f92c27f49dc1610d58d04e3d66309470d54471cf GIT binary patch literal 10698 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 literal 0 HcmV?d00001 diff --git a/venv/Lib/site-packages/firebase_admin/__pycache__/credentials.cpython-36.pyc b/venv/Lib/site-packages/firebase_admin/__pycache__/credentials.cpython-36.pyc new file mode 100644 index 0000000000000000000000000000000000000000..3a8f5a97c67240bc9ab13e8fbc8778c0299b61aa GIT binary patch literal 8112 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 literal 0 HcmV?d00001 diff --git a/venv/Lib/site-packages/firebase_admin/__pycache__/db.cpython-36.pyc b/venv/Lib/site-packages/firebase_admin/__pycache__/db.cpython-36.pyc new file mode 100644 index 0000000000000000000000000000000000000000..a57f7ed0917615230f59c255ff0faf89db860514 GIT binary patch literal 37896 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 literal 0 HcmV?d00001 diff --git a/venv/Lib/site-packages/firebase_admin/__pycache__/firestore.cpython-36.pyc b/venv/Lib/site-packages/firebase_admin/__pycache__/firestore.cpython-36.pyc new file mode 100644 index 0000000000000000000000000000000000000000..5f220f580e7bf10753b0d2b33474f05b7099a312 GIT binary patch literal 2616 zcmZ`*PjA~c6elJBi{hkdm%|G5KonR}1C4@i-JwCTHBFN&MVAC=x^998g%)X>jx4z( zoz{VSnRDG&*mc--A7URu*I|c!g`M_D$##~dGANN2`QGpS`#pWJwB)_$T!epl2>ppJ zU5hY(3Pb$@H--WNK8DIvai>d65{=EoOVX@Y;kKcK|<9)YfMT<)QJTiFJ$(0iM0cl107E4- zUQ&S<&cN(P*Z_pffl-371w(xbH;sCDjI^U&$O`uZ9^+nlf*>}SmSFP{*Fy=8rzDC6 zPmBdrlZYmy#mP_=#wD6d8foj+kHi5YO5oa*9kpR+#JGKfY$jxLFvx98B2Mn711-{o z#*N}cfna(lx8JuB@n;75JJZ;JL~=4)K{goFC*f2W6_5#2S>Mrk$hW0Tpo~?#E zdq>-^jt`Eu!_DL4qrGRZkGHdxInLbsS*Afn-9F3f|4whD7qzaa@MhW`0A z+Gs*fN!4soJ?u8qgfl75c$0B;s?$Mpn22|&JZ+9RmE=)V@jlo9L3!AWc<0gMho3hK zZ#K_(S46-D6r!^Rfop5hrjTBeM`FOs=?{J|)zE*)YDGc=hZX5*|*w|q>aGAs03lx-C ziIw45<`q_9)eAJiL6y~@_7-FXj-0Q5lg7-{-tP6(mZO-}jvpC~<}%M&m9N6WRyiJn z_Me?G3LR!D+}VdvEMCgttXjCQ;YvdkS!K(XPgX4g)o`CsQ*zUo>?#u0P>*c}g=i%Ye!Hey! z<7-*UZ4^7G6jQN4_9yr zJGkOrlP6Q+*l*NKY9+MK!!Yy0F#k+|c|8o@4ryGxsfHm-qcD`WK(tK`NbndMf1g9Y zW>)v56tc-{^47wC3=?G%s)kEW&8@k)QFy;`Q{INZgZky>lUGQ!6Q?bp|EzS%M=GoF z_d;o4ZG)DH2nr!91FiH`=E8=o49q^{nFkGBYGuAcvc*07X<*w>u>4=vvAiqG2B2}4 m#d96}to9^#$XB1hHrv-rj)Uvi!>jPSg_rTNTX##YxB4&p<@quI literal 0 HcmV?d00001 diff --git a/venv/Lib/site-packages/firebase_admin/__pycache__/instance_id.cpython-36.pyc b/venv/Lib/site-packages/firebase_admin/__pycache__/instance_id.cpython-36.pyc new file mode 100644 index 0000000000000000000000000000000000000000..fffdf85639e7baea85f48eed7085c821b12e2e66 GIT binary patch literal 3506 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 literal 0 HcmV?d00001 diff --git a/venv/Lib/site-packages/firebase_admin/__pycache__/ml.cpython-36.pyc b/venv/Lib/site-packages/firebase_admin/__pycache__/ml.cpython-36.pyc new file mode 100644 index 0000000000000000000000000000000000000000..3993f9c6601f1c13ddf9a1e7beed644ee72b5968 GIT binary patch literal 34347 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 E7Z#TQSO5S3 literal 0 HcmV?d00001 diff --git a/venv/Lib/site-packages/firebase_admin/__pycache__/project_management.cpython-36.pyc b/venv/Lib/site-packages/firebase_admin/__pycache__/project_management.cpython-36.pyc new file mode 100644 index 0000000000000000000000000000000000000000..6322d940ac0601969245595c70e4f43348efd819 GIT binary patch literal 24530 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 literal 0 HcmV?d00001 diff --git a/venv/Lib/site-packages/firebase_admin/__pycache__/storage.cpython-36.pyc b/venv/Lib/site-packages/firebase_admin/__pycache__/storage.cpython-36.pyc new file mode 100644 index 0000000000000000000000000000000000000000..bbce402d407feb3f12a9b0930cd38558d21e0283 GIT binary patch literal 2874 zcmaJ@TW{Mo6ecD4630!m>;?>b;DQ0IfyQgM0>y%%XcDwtcFBq)y9ve=Mx<@pvgDGK zJA3ZSlGpu=J?wW3*pJZbp7s~^v_n!(;x?EAGL%T3%XiNCjy}0@qwz)WJgVJ5=x=o8 zw+ib=Fw{>lF%+WdI>XFM@W=~2jJ`+d`vKzqup#eaWd69%{4@M3{t>0#4+zc%NieE} z6^vLVtg=;BWA$?!)}A7^!W!p@HO{=S&ZOGh=8sItBp7sa9ng7z8dxOdxoneRvrWss24+05d-;f`nn3i@Op~$9CW3Kxhvce+_f~1@u8q$vl8vDiI|xfo5<{p$8D#MS`9Q&nN>q4fIK|~njEA&DM;x9aY;sQ zJ11z;YM0j_xwgqpYD^}Ox|*gjUpi*bm5?uVxp23wigu}@?QjBNSHfbzxCG1@QQCfJ z0a!@?PCz|n=lHdtkhE(LL@4=%|>&@w8DK%I>^q&>R`t-4dXXkriB!iE1* zN{Pu;6_iXMjtpRv5KD(qt15j+%kXB8>j>bA6qgeb^I{`9I{xNx=jr2U=lJ+=fA`zt z$HiK7)5`D&BNkn5PJkewPE5Y#K6=Z!=cYS=AWZ5;1w3I$~n|EaPZ24gDvYe zWCbqGwm#1iW~%&J)^xyKq-;C3w!l5}{~A7-gZAINIf}fw53|n@@QHWO@`}}1at5)2 z3RXp}#IF@dLr_JvjAJcw3X7W&<6W93Ix6EC6oKMNS3;jca?RXXTRve!>!zmJu1Ap} zj40ZMCkG*3$Fp~rGpD^cbwQL%j(rGs=Xd~Ad4_-@@xUAS44>hbz7FQ*xia_9eCuL( zqYT}yC9+mEY+QO=teLF7@?3Kap$Z>1Y#_o$iAf|_D=7RpQE~;;JCENqE0esJ9?B{_ zK7^sn0(lMG^j~vtQ5VaNz@*Kdxp@H795XyzkTvRz@(eHNAK zjJVw*i>}h1eYu}52+n=STrqT;Z2ofhQH2kn5!G@XPFj{|`EtXo>oA3@PJLtu@zo?UB=ZD@GRKj( zf$P}AReuBK0M@g&U#S--s)Y|)byH$SWE2&RC~}`_ux>`t^PDE-PA!U97DthM3&aBn zB=G&^I*83*YwQ)9Y>J!uwKeeo7RtC#$AMQ5nsxgY_~f9qA_=??n^$|J|!a sT)4JOueQZVQ{qmsVZiIO7xmAaKMzgeDFbWZd%z!Sc+GG6f!BEFKfks|bN~PV literal 0 HcmV?d00001 diff --git a/venv/Lib/site-packages/firebase_admin/__pycache__/tenant_mgt.cpython-36.pyc b/venv/Lib/site-packages/firebase_admin/__pycache__/tenant_mgt.cpython-36.pyc new file mode 100644 index 0000000000000000000000000000000000000000..2bb2747893309b185665abcbd246d546f38edd31 GIT binary patch literal 15522 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 CT`5}t literal 0 HcmV?d00001 diff --git a/venv/Lib/site-packages/firebase_admin/_auth_client.py b/venv/Lib/site-packages/firebase_admin/_auth_client.py new file mode 100644 index 000000000..1c9b37082 --- /dev/null +++ b/venv/Lib/site-packages/firebase_admin/_auth_client.py @@ -0,0 +1,703 @@ +# Copyright 2020 Google Inc. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +"""Firebase auth client sub module.""" + +import time + +import firebase_admin +from firebase_admin import _auth_providers +from firebase_admin import _auth_utils +from firebase_admin import _http_client +from firebase_admin import _token_gen +from firebase_admin import _user_identifier +from firebase_admin import _user_import +from firebase_admin import _user_mgt + + +class Client: + """Firebase Authentication client scoped to a specific tenant.""" + + def __init__(self, app, tenant_id=None): + if not app.project_id: + raise ValueError("""A project ID is required to access the auth service. + 1. Use a service account credential, or + 2. set the project ID explicitly via Firebase App options, or + 3. set the project ID via the GOOGLE_CLOUD_PROJECT environment variable.""") + + credential = app.credential.get_credential() + version_header = 'Python/Admin/{0}'.format(firebase_admin.__version__) + http_client = _http_client.JsonHttpClient( + credential=credential, headers={'X-Client-Version': version_header}) + + self._tenant_id = tenant_id + self._token_generator = _token_gen.TokenGenerator(app, http_client) + self._token_verifier = _token_gen.TokenVerifier(app) + self._user_manager = _user_mgt.UserManager(http_client, app.project_id, tenant_id) + self._provider_manager = _auth_providers.ProviderConfigClient( + http_client, app.project_id, tenant_id) + + @property + def tenant_id(self): + """Tenant ID associated with this client.""" + return self._tenant_id + + def create_custom_token(self, uid, developer_claims=None): + """Builds and signs a Firebase custom auth token. + + Args: + uid: ID of the user for whom the token is created. + developer_claims: A dictionary of claims to be included in the token + (optional). + + Returns: + bytes: A token minted from the input parameters. + + Raises: + ValueError: If input parameters are invalid. + TokenSignError: If an error occurs while signing the token using the remote IAM service. + """ + return self._token_generator.create_custom_token( + uid, developer_claims, tenant_id=self.tenant_id) + + def verify_id_token(self, id_token, check_revoked=False): + """Verifies the signature and data for the provided JWT. + + Accepts a signed token string, verifies that it is current, was issued + to this project, and that it was correctly signed by Google. + + Args: + id_token: A string of the encoded JWT. + check_revoked: Boolean, If true, checks whether the token has been revoked (optional). + + Returns: + dict: A dictionary of key-value pairs parsed from the decoded JWT. + + Raises: + ValueError: If ``id_token`` is a not a string or is empty. + InvalidIdTokenError: If ``id_token`` is not a valid Firebase ID token. + ExpiredIdTokenError: If the specified ID token has expired. + RevokedIdTokenError: If ``check_revoked`` is ``True`` and the ID token has been + revoked. + TenantIdMismatchError: If ``id_token`` belongs to a tenant that is different than + this ``Client`` instance. + CertificateFetchError: If an error occurs while fetching the public key certificates + required to verify the ID token. + """ + if not isinstance(check_revoked, bool): + # guard against accidental wrong assignment. + raise ValueError('Illegal check_revoked argument. Argument must be of type ' + ' bool, but given "{0}".'.format(type(check_revoked))) + + verified_claims = self._token_verifier.verify_id_token(id_token) + if self.tenant_id: + token_tenant_id = verified_claims.get('firebase', {}).get('tenant') + if self.tenant_id != token_tenant_id: + raise _auth_utils.TenantIdMismatchError( + 'Invalid tenant ID: {0}'.format(token_tenant_id)) + + if check_revoked: + self._check_jwt_revoked(verified_claims, _token_gen.RevokedIdTokenError, 'ID token') + return verified_claims + + def revoke_refresh_tokens(self, uid): + """Revokes all refresh tokens for an existing user. + + This method updates the user's ``tokens_valid_after_timestamp`` to the current UTC + in seconds since the epoch. It is important that the server on which this is called has its + clock set correctly and synchronized. + + While this revokes all sessions for a specified user and disables any new ID tokens for + existing sessions from getting minted, existing ID tokens may remain active until their + natural expiration (one hour). To verify that ID tokens are revoked, use + ``verify_id_token(idToken, check_revoked=True)``. + + Args: + uid: A user ID string. + + Raises: + ValueError: If the user ID is None, empty or malformed. + FirebaseError: If an error occurs while revoking the refresh token. + """ + self._user_manager.update_user(uid, valid_since=int(time.time())) + + def get_user(self, uid): + """Gets the user data corresponding to the specified user ID. + + Args: + uid: A user ID string. + + Returns: + UserRecord: A user record instance. + + Raises: + ValueError: If the user ID is None, empty or malformed. + UserNotFoundError: If the specified user ID does not exist. + FirebaseError: If an error occurs while retrieving the user. + """ + response = self._user_manager.get_user(uid=uid) + return _user_mgt.UserRecord(response) + + def get_user_by_email(self, email): + """Gets the user data corresponding to the specified user email. + + Args: + email: A user email address string. + + Returns: + UserRecord: A user record instance. + + Raises: + ValueError: If the email is None, empty or malformed. + UserNotFoundError: If no user exists by the specified email address. + FirebaseError: If an error occurs while retrieving the user. + """ + response = self._user_manager.get_user(email=email) + return _user_mgt.UserRecord(response) + + def get_user_by_phone_number(self, phone_number): + """Gets the user data corresponding to the specified phone number. + + Args: + phone_number: A phone number string. + + Returns: + UserRecord: A user record instance. + + Raises: + ValueError: If the phone number is ``None``, empty or malformed. + UserNotFoundError: If no user exists by the specified phone number. + FirebaseError: If an error occurs while retrieving the user. + """ + response = self._user_manager.get_user(phone_number=phone_number) + return _user_mgt.UserRecord(response) + + def get_users(self, identifiers): + """Gets the user data corresponding to the specified identifiers. + + There are no ordering guarantees; in particular, the nth entry in the + result list is not guaranteed to correspond to the nth entry in the input + parameters list. + + A maximum of 100 identifiers may be supplied. If more than 100 + identifiers are supplied, this method raises a `ValueError`. + + Args: + identifiers (list[Identifier]): A list of ``Identifier`` instances used + to indicate which user records should be returned. Must have <= 100 + entries. + + Returns: + GetUsersResult: A ``GetUsersResult`` instance corresponding to the + specified identifiers. + + Raises: + ValueError: If any of the identifiers are invalid or if more than 100 + identifiers are specified. + """ + response = self._user_manager.get_users(identifiers=identifiers) + + def _matches(identifier, user_record): + if isinstance(identifier, _user_identifier.UidIdentifier): + return identifier.uid == user_record.uid + if isinstance(identifier, _user_identifier.EmailIdentifier): + return identifier.email == user_record.email + if isinstance(identifier, _user_identifier.PhoneIdentifier): + return identifier.phone_number == user_record.phone_number + if isinstance(identifier, _user_identifier.ProviderIdentifier): + return next(( + True + for user_info in user_record.provider_data + if identifier.provider_id == user_info.provider_id + and identifier.provider_uid == user_info.uid + ), False) + raise TypeError("Unexpected type: {}".format(type(identifier))) + + def _is_user_found(identifier, user_records): + return any(_matches(identifier, user_record) for user_record in user_records) + + users = [_user_mgt.UserRecord(user) for user in response] + not_found = [ + identifier for identifier in identifiers if not _is_user_found(identifier, users)] + + return _user_mgt.GetUsersResult(users=users, not_found=not_found) + + def list_users(self, page_token=None, max_results=_user_mgt.MAX_LIST_USERS_RESULTS): + """Retrieves a page of user accounts from a Firebase project. + + The ``page_token`` argument governs the starting point of the page. The ``max_results`` + argument governs the maximum number of user accounts that may be included in the returned + page. This function never returns ``None``. If there are no user accounts in the Firebase + project, this returns an empty page. + + Args: + page_token: A non-empty page token string, which indicates the starting point of the + page (optional). Defaults to ``None``, which will retrieve the first page of users. + max_results: A positive integer indicating the maximum number of users to include in + the returned page (optional). Defaults to 1000, which is also the maximum number + allowed. + + Returns: + ListUsersPage: A page of user accounts. + + Raises: + ValueError: If max_results or page_token are invalid. + FirebaseError: If an error occurs while retrieving the user accounts. + """ + def download(page_token, max_results): + return self._user_manager.list_users(page_token, max_results) + return _user_mgt.ListUsersPage(download, page_token, max_results) + + def create_user(self, **kwargs): # pylint: disable=differing-param-doc + """Creates a new user account with the specified properties. + + Args: + kwargs: A series of keyword arguments (optional). + + Keyword Args: + uid: User ID to assign to the newly created user (optional). + display_name: The user's display name (optional). + email: The user's primary email (optional). + email_verified: A boolean indicating whether or not the user's primary email is + verified (optional). + phone_number: The user's primary phone number (optional). + photo_url: The user's photo URL (optional). + password: The user's raw, unhashed password. (optional). + disabled: A boolean indicating whether or not the user account is disabled (optional). + + Returns: + UserRecord: A UserRecord instance for the newly created user. + + Raises: + ValueError: If the specified user properties are invalid. + FirebaseError: If an error occurs while creating the user account. + """ + uid = self._user_manager.create_user(**kwargs) + return self.get_user(uid=uid) + + def update_user(self, uid, **kwargs): # pylint: disable=differing-param-doc + """Updates an existing user account with the specified properties. + + Args: + uid: A user ID string. + kwargs: A series of keyword arguments (optional). + + Keyword Args: + display_name: The user's display name (optional). Can be removed by explicitly passing + ``auth.DELETE_ATTRIBUTE``. + email: The user's primary email (optional). + email_verified: A boolean indicating whether or not the user's primary email is + verified (optional). + phone_number: The user's primary phone number (optional). Can be removed by explicitly + passing ``auth.DELETE_ATTRIBUTE``. + photo_url: The user's photo URL (optional). Can be removed by explicitly passing + ``auth.DELETE_ATTRIBUTE``. + password: The user's raw, unhashed password. (optional). + disabled: A boolean indicating whether or not the user account is disabled (optional). + custom_claims: A dictionary or a JSON string contining the custom claims to be set on + the user account (optional). To remove all custom claims, pass + ``auth.DELETE_ATTRIBUTE``. + valid_since: An integer signifying the seconds since the epoch (optional). This field + is set by ``revoke_refresh_tokens`` and it is discouraged to set this field + directly. + + Returns: + UserRecord: An updated UserRecord instance for the user. + + Raises: + ValueError: If the specified user ID or properties are invalid. + FirebaseError: If an error occurs while updating the user account. + """ + self._user_manager.update_user(uid, **kwargs) + return self.get_user(uid=uid) + + def set_custom_user_claims(self, uid, custom_claims): + """Sets additional claims on an existing user account. + + Custom claims set via this function can be used to define user roles and privilege levels. + These claims propagate to all the devices where the user is already signed in (after token + expiration or when token refresh is forced), and next time the user signs in. The claims + can be accessed via the user's ID token JWT. If a reserved OIDC claim is specified (sub, + iat, iss, etc), an error is thrown. Claims payload must also not be larger then 1000 + characters when serialized into a JSON string. + + Args: + uid: A user ID string. + custom_claims: A dictionary or a JSON string of custom claims. Pass None to unset any + claims set previously. + + Raises: + ValueError: If the specified user ID or the custom claims are invalid. + FirebaseError: If an error occurs while updating the user account. + """ + if custom_claims is None: + custom_claims = _user_mgt.DELETE_ATTRIBUTE + self._user_manager.update_user(uid, custom_claims=custom_claims) + + def delete_user(self, uid): + """Deletes the user identified by the specified user ID. + + Args: + uid: A user ID string. + + Raises: + ValueError: If the user ID is None, empty or malformed. + FirebaseError: If an error occurs while deleting the user account. + """ + self._user_manager.delete_user(uid) + + def delete_users(self, uids): + """Deletes the users specified by the given identifiers. + + Deleting a non-existing user does not generate an error (the method is + idempotent.) Non-existing users are considered to be successfully + deleted and are therefore included in the + `DeleteUserResult.success_count` value. + + A maximum of 1000 identifiers may be supplied. If more than 1000 + identifiers are supplied, this method raises a `ValueError`. + + Args: + uids: A list of strings indicating the uids of the users to be deleted. + Must have <= 1000 entries. + + Returns: + DeleteUsersResult: The total number of successful/failed deletions, as + well as the array of errors that correspond to the failed + deletions. + + Raises: + ValueError: If any of the identifiers are invalid or if more than 1000 + identifiers are specified. + """ + result = self._user_manager.delete_users(uids, force_delete=True) + return _user_mgt.DeleteUsersResult(result, len(uids)) + + def import_users(self, users, hash_alg=None): + """Imports the specified list of users into Firebase Auth. + + At most 1000 users can be imported at a time. This operation is optimized for bulk imports + and ignores checks on identifier uniqueness, which could result in duplications. The + ``hash_alg`` parameter must be specified when importing users with passwords. Refer to the + ``UserImportHash`` class for supported hash algorithms. + + Args: + users: A list of ``ImportUserRecord`` instances to import. Length of the list must not + exceed 1000. + hash_alg: A ``UserImportHash`` object (optional). Required when importing users with + passwords. + + Returns: + UserImportResult: An object summarizing the result of the import operation. + + Raises: + ValueError: If the provided arguments are invalid. + FirebaseError: If an error occurs while importing users. + """ + result = self._user_manager.import_users(users, hash_alg) + return _user_import.UserImportResult(result, len(users)) + + def generate_password_reset_link(self, email, action_code_settings=None): + """Generates the out-of-band email action link for password reset flows for the specified + email address. + + Args: + email: The email of the user whose password is to be reset. + action_code_settings: ``ActionCodeSettings`` instance (optional). Defines whether + the link is to be handled by a mobile app and the additional state information to + be passed in the deep link. + + Returns: + link: The password reset link created by the API + + Raises: + ValueError: If the provided arguments are invalid + FirebaseError: If an error occurs while generating the link + """ + return self._user_manager.generate_email_action_link( + 'PASSWORD_RESET', email, action_code_settings=action_code_settings) + + def generate_email_verification_link(self, email, action_code_settings=None): + """Generates the out-of-band email action link for email verification flows for the + specified email address. + + Args: + email: The email of the user to be verified. + action_code_settings: ``ActionCodeSettings`` instance (optional). Defines whether + the link is to be handled by a mobile app and the additional state information to + be passed in the deep link. + + Returns: + link: The email verification link created by the API + + Raises: + ValueError: If the provided arguments are invalid + FirebaseError: If an error occurs while generating the link + """ + return self._user_manager.generate_email_action_link( + 'VERIFY_EMAIL', email, action_code_settings=action_code_settings) + + def generate_sign_in_with_email_link(self, email, action_code_settings): + """Generates the out-of-band email action link for email link sign-in flows, using the + action code settings provided. + + Args: + email: The email of the user signing in. + action_code_settings: ``ActionCodeSettings`` instance. Defines whether + the link is to be handled by a mobile app and the additional state information to be + passed in the deep link. + + Returns: + link: The email sign-in link created by the API + + Raises: + ValueError: If the provided arguments are invalid + FirebaseError: If an error occurs while generating the link + """ + return self._user_manager.generate_email_action_link( + 'EMAIL_SIGNIN', email, action_code_settings=action_code_settings) + + def get_oidc_provider_config(self, provider_id): + """Returns the ``OIDCProviderConfig`` with the given ID. + + Args: + provider_id: Provider ID string. + + Returns: + SAMLProviderConfig: An OIDC provider config instance. + + Raises: + ValueError: If the provider ID is invalid, empty or does not have ``oidc.`` prefix. + ConfigurationNotFoundError: If no OIDC provider is available with the given identifier. + FirebaseError: If an error occurs while retrieving the OIDC provider. + """ + return self._provider_manager.get_oidc_provider_config(provider_id) + + def create_oidc_provider_config( + self, provider_id, client_id, issuer, display_name=None, enabled=None): + """Creates a new OIDC provider config from the given parameters. + + OIDC provider support requires Google Cloud's Identity Platform (GCIP). To learn more about + GCIP, including pricing and features, see https://cloud.google.com/identity-platform. + + Args: + provider_id: Provider ID string. Must have the prefix ``oidc.``. + client_id: Client ID of the new config. + issuer: Issuer of the new config. Must be a valid URL. + display_name: The user-friendly display name to the current configuration (optional). + This name is also used as the provider label in the Cloud Console. + enabled: A boolean indicating whether the provider configuration is enabled or disabled + (optional). A user cannot sign in using a disabled provider. + + Returns: + OIDCProviderConfig: The newly created OIDC provider config instance. + + Raises: + ValueError: If any of the specified input parameters are invalid. + FirebaseError: If an error occurs while creating the new OIDC provider config. + """ + return self._provider_manager.create_oidc_provider_config( + provider_id, client_id=client_id, issuer=issuer, display_name=display_name, + enabled=enabled) + + def update_oidc_provider_config( + self, provider_id, client_id=None, issuer=None, display_name=None, enabled=None): + """Updates an existing OIDC provider config with the given parameters. + + Args: + provider_id: Provider ID string. Must have the prefix ``oidc.``. + client_id: Client ID of the new config (optional). + issuer: Issuer of the new config (optional). Must be a valid URL. + display_name: The user-friendly display name to the current configuration (optional). + Pass ``auth.DELETE_ATTRIBUTE`` to delete the current display name. + enabled: A boolean indicating whether the provider configuration is enabled or disabled + (optional). + + Returns: + OIDCProviderConfig: The updated OIDC provider config instance. + + Raises: + ValueError: If any of the specified input parameters are invalid. + FirebaseError: If an error occurs while updating the OIDC provider config. + """ + return self._provider_manager.update_oidc_provider_config( + provider_id, client_id=client_id, issuer=issuer, display_name=display_name, + enabled=enabled) + + def delete_oidc_provider_config(self, provider_id): + """Deletes the ``OIDCProviderConfig`` with the given ID. + + Args: + provider_id: Provider ID string. + + Raises: + ValueError: If the provider ID is invalid, empty or does not have ``oidc.`` prefix. + ConfigurationNotFoundError: If no OIDC provider is available with the given identifier. + FirebaseError: If an error occurs while deleting the OIDC provider. + """ + self._provider_manager.delete_oidc_provider_config(provider_id) + + def list_oidc_provider_configs( + self, page_token=None, max_results=_auth_providers.MAX_LIST_CONFIGS_RESULTS): + """Retrieves a page of OIDC provider configs from a Firebase project. + + The ``page_token`` argument governs the starting point of the page. The ``max_results`` + argument governs the maximum number of configs that may be included in the returned + page. This function never returns ``None``. If there are no OIDC configs in the Firebase + project, this returns an empty page. + + Args: + page_token: A non-empty page token string, which indicates the starting point of the + page (optional). Defaults to ``None``, which will retrieve the first page of users. + max_results: A positive integer indicating the maximum number of users to include in + the returned page (optional). Defaults to 100, which is also the maximum number + allowed. + + Returns: + ListProviderConfigsPage: A page of OIDC provider config instances. + + Raises: + ValueError: If ``max_results`` or ``page_token`` are invalid. + FirebaseError: If an error occurs while retrieving the OIDC provider configs. + """ + return self._provider_manager.list_oidc_provider_configs(page_token, max_results) + + def get_saml_provider_config(self, provider_id): + """Returns the ``SAMLProviderConfig`` with the given ID. + + Args: + provider_id: Provider ID string. + + Returns: + SAMLProviderConfig: A SAML provider config instance. + + Raises: + ValueError: If the provider ID is invalid, empty or does not have ``saml.`` prefix. + ConfigurationNotFoundError: If no SAML provider is available with the given identifier. + FirebaseError: If an error occurs while retrieving the SAML provider. + """ + return self._provider_manager.get_saml_provider_config(provider_id) + + def create_saml_provider_config( + self, provider_id, idp_entity_id, sso_url, x509_certificates, rp_entity_id, + callback_url, display_name=None, enabled=None): + """Creates a new SAML provider config from the given parameters. + + SAML provider support requires Google Cloud's Identity Platform (GCIP). To learn more about + GCIP, including pricing and features, see https://cloud.google.com/identity-platform. + + Args: + provider_id: Provider ID string. Must have the prefix ``saml.``. + idp_entity_id: The SAML IdP entity identifier. + sso_url: The SAML IdP SSO URL. Must be a valid URL. + x509_certificates: The list of SAML IdP X.509 certificates issued by CA for this + provider. Multiple certificates are accepted to prevent outages during IdP key + rotation (for example ADFS rotates every 10 days). When the Auth server receives a + SAML response, it will match the SAML response with the certificate on record. + Otherwise the response is rejected. Developers are expected to manage the + certificate updates as keys are rotated. + rp_entity_id: The SAML relying party (service provider) entity ID. This is defined by + the developer but needs to be provided to the SAML IdP. + callback_url: Callback URL string. This is fixed and must always be the same as the + OAuth redirect URL provisioned by Firebase Auth, unless a custom authDomain is + used. + display_name: The user-friendly display name to the current configuration (optional). + This name is also used as the provider label in the Cloud Console. + enabled: A boolean indicating whether the provider configuration is enabled or disabled + (optional). A user cannot sign in using a disabled provider. + + Returns: + SAMLProviderConfig: The newly created SAML provider config instance. + + Raises: + ValueError: If any of the specified input parameters are invalid. + FirebaseError: If an error occurs while creating the new SAML provider config. + """ + return self._provider_manager.create_saml_provider_config( + provider_id, idp_entity_id=idp_entity_id, sso_url=sso_url, + x509_certificates=x509_certificates, rp_entity_id=rp_entity_id, + callback_url=callback_url, display_name=display_name, enabled=enabled) + + def update_saml_provider_config( + self, provider_id, idp_entity_id=None, sso_url=None, x509_certificates=None, + rp_entity_id=None, callback_url=None, display_name=None, enabled=None): + """Updates an existing SAML provider config with the given parameters. + + Args: + provider_id: Provider ID string. Must have the prefix ``saml.``. + idp_entity_id: The SAML IdP entity identifier (optional). + sso_url: The SAML IdP SSO URL. Must be a valid URL (optional). + x509_certificates: The list of SAML IdP X.509 certificates issued by CA for this + provider (optional). + rp_entity_id: The SAML relying party entity ID (optional). + callback_url: Callback URL string (optional). + display_name: The user-friendly display name of the current configuration (optional). + Pass ``auth.DELETE_ATTRIBUTE`` to delete the current display name. + enabled: A boolean indicating whether the provider configuration is enabled or disabled + (optional). + + Returns: + SAMLProviderConfig: The updated SAML provider config instance. + + Raises: + ValueError: If any of the specified input parameters are invalid. + FirebaseError: If an error occurs while updating the SAML provider config. + """ + return self._provider_manager.update_saml_provider_config( + provider_id, idp_entity_id=idp_entity_id, sso_url=sso_url, + x509_certificates=x509_certificates, rp_entity_id=rp_entity_id, + callback_url=callback_url, display_name=display_name, enabled=enabled) + + def delete_saml_provider_config(self, provider_id): + """Deletes the ``SAMLProviderConfig`` with the given ID. + + Args: + provider_id: Provider ID string. + + Raises: + ValueError: If the provider ID is invalid, empty or does not have ``saml.`` prefix. + ConfigurationNotFoundError: If no SAML provider is available with the given identifier. + FirebaseError: If an error occurs while deleting the SAML provider. + """ + self._provider_manager.delete_saml_provider_config(provider_id) + + def list_saml_provider_configs( + self, page_token=None, max_results=_auth_providers.MAX_LIST_CONFIGS_RESULTS): + """Retrieves a page of SAML provider configs from a Firebase project. + + The ``page_token`` argument governs the starting point of the page. The ``max_results`` + argument governs the maximum number of configs that may be included in the returned + page. This function never returns ``None``. If there are no SAML configs in the Firebase + project, this returns an empty page. + + Args: + page_token: A non-empty page token string, which indicates the starting point of the + page (optional). Defaults to ``None``, which will retrieve the first page of users. + max_results: A positive integer indicating the maximum number of users to include in + the returned page (optional). Defaults to 100, which is also the maximum number + allowed. + + Returns: + ListProviderConfigsPage: A page of SAML provider config instances. + + Raises: + ValueError: If ``max_results`` or ``page_token`` are invalid. + FirebaseError: If an error occurs while retrieving the SAML provider configs. + """ + return self._provider_manager.list_saml_provider_configs(page_token, max_results) + + def _check_jwt_revoked(self, verified_claims, exc_type, label): + user = self.get_user(verified_claims.get('uid')) + if verified_claims.get('iat') * 1000 < user.tokens_valid_after_timestamp: + raise exc_type('The Firebase {0} has been revoked.'.format(label)) diff --git a/venv/Lib/site-packages/firebase_admin/_auth_providers.py b/venv/Lib/site-packages/firebase_admin/_auth_providers.py new file mode 100644 index 000000000..46de6fe5f --- /dev/null +++ b/venv/Lib/site-packages/firebase_admin/_auth_providers.py @@ -0,0 +1,390 @@ +# Copyright 2020 Google Inc. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +"""Firebase auth providers management sub module.""" + +from urllib import parse + +import requests + +from firebase_admin import _auth_utils +from firebase_admin import _user_mgt + + +MAX_LIST_CONFIGS_RESULTS = 100 + + +class ProviderConfig: + """Parent type for all authentication provider config types.""" + + def __init__(self, data): + self._data = data + + @property + def provider_id(self): + name = self._data['name'] + return name.split('/')[-1] + + @property + def display_name(self): + return self._data.get('displayName') + + @property + def enabled(self): + return self._data.get('enabled', False) + + +class OIDCProviderConfig(ProviderConfig): + """Represents the OIDC auth provider configuration. + + See https://openid.net/specs/openid-connect-core-1_0-final.html. + """ + + @property + def issuer(self): + return self._data['issuer'] + + @property + def client_id(self): + return self._data['clientId'] + + +class SAMLProviderConfig(ProviderConfig): + """Represents he SAML auth provider configuration. + + See http://docs.oasis-open.org/security/saml/Post2.0/sstc-saml-tech-overview-2.0.html. + """ + + @property + def idp_entity_id(self): + return self._data.get('idpConfig', {})['idpEntityId'] + + @property + def sso_url(self): + return self._data.get('idpConfig', {})['ssoUrl'] + + @property + def x509_certificates(self): + certs = self._data.get('idpConfig', {})['idpCertificates'] + return [c['x509Certificate'] for c in certs] + + @property + def callback_url(self): + return self._data.get('spConfig', {})['callbackUri'] + + @property + def rp_entity_id(self): + return self._data.get('spConfig', {})['spEntityId'] + + +class ListProviderConfigsPage: + """Represents a page of AuthProviderConfig instances retrieved from a Firebase project. + + Provides methods for traversing the provider configs included in this page, as well as + retrieving subsequent pages. The iterator returned by ``iterate_all()`` can be used to iterate + through all provider configs in the Firebase project starting from this page. + """ + + def __init__(self, download, page_token, max_results): + self._download = download + self._max_results = max_results + self._current = download(page_token, max_results) + + @property + def provider_configs(self): + """A list of ``AuthProviderConfig`` instances available in this page.""" + raise NotImplementedError + + @property + def next_page_token(self): + """Page token string for the next page (empty string indicates no more pages).""" + return self._current.get('nextPageToken', '') + + @property + def has_next_page(self): + """A boolean indicating whether more pages are available.""" + return bool(self.next_page_token) + + def get_next_page(self): + """Retrieves the next page of provider configs, if available. + + Returns: + ListProviderConfigsPage: Next page of provider configs, or None if this is the last + page. + """ + if self.has_next_page: + return self.__class__(self._download, self.next_page_token, self._max_results) + return None + + def iterate_all(self): + """Retrieves an iterator for provider configs. + + Returned iterator will iterate through all the provider configs in the Firebase project + starting from this page. The iterator will never buffer more than one page of configs + in memory at a time. + + Returns: + iterator: An iterator of AuthProviderConfig instances. + """ + return _ProviderConfigIterator(self) + + +class _ListOIDCProviderConfigsPage(ListProviderConfigsPage): + + @property + def provider_configs(self): + return [OIDCProviderConfig(data) for data in self._current.get('oauthIdpConfigs', [])] + + +class _ListSAMLProviderConfigsPage(ListProviderConfigsPage): + + @property + def provider_configs(self): + return [SAMLProviderConfig(data) for data in self._current.get('inboundSamlConfigs', [])] + + +class _ProviderConfigIterator(_auth_utils.PageIterator): + + @property + def items(self): + return self._current_page.provider_configs + + +class ProviderConfigClient: + """Client for managing Auth provider configurations.""" + + PROVIDER_CONFIG_URL = 'https://identitytoolkit.googleapis.com/v2beta1' + + def __init__(self, http_client, project_id, tenant_id=None): + self.http_client = http_client + self.base_url = '{0}/projects/{1}'.format(self.PROVIDER_CONFIG_URL, project_id) + if tenant_id: + self.base_url += '/tenants/{0}'.format(tenant_id) + + def get_oidc_provider_config(self, provider_id): + _validate_oidc_provider_id(provider_id) + body = self._make_request('get', '/oauthIdpConfigs/{0}'.format(provider_id)) + return OIDCProviderConfig(body) + + def create_oidc_provider_config( + self, provider_id, client_id, issuer, display_name=None, enabled=None): + """Creates a new OIDC provider config from the given parameters.""" + _validate_oidc_provider_id(provider_id) + req = { + 'clientId': _validate_non_empty_string(client_id, 'client_id'), + 'issuer': _validate_url(issuer, 'issuer'), + } + if display_name is not None: + req['displayName'] = _auth_utils.validate_string(display_name, 'display_name') + if enabled is not None: + req['enabled'] = _auth_utils.validate_boolean(enabled, 'enabled') + + params = 'oauthIdpConfigId={0}'.format(provider_id) + body = self._make_request('post', '/oauthIdpConfigs', json=req, params=params) + return OIDCProviderConfig(body) + + def update_oidc_provider_config( + self, provider_id, client_id=None, issuer=None, display_name=None, enabled=None): + """Updates an existing OIDC provider config with the given parameters.""" + _validate_oidc_provider_id(provider_id) + req = {} + if display_name is not None: + if display_name == _user_mgt.DELETE_ATTRIBUTE: + req['displayName'] = None + else: + req['displayName'] = _auth_utils.validate_string(display_name, 'display_name') + if enabled is not None: + req['enabled'] = _auth_utils.validate_boolean(enabled, 'enabled') + if client_id: + req['clientId'] = _validate_non_empty_string(client_id, 'client_id') + if issuer: + req['issuer'] = _validate_url(issuer, 'issuer') + + if not req: + raise ValueError('At least one parameter must be specified for update.') + + update_mask = _auth_utils.build_update_mask(req) + params = 'updateMask={0}'.format(','.join(update_mask)) + url = '/oauthIdpConfigs/{0}'.format(provider_id) + body = self._make_request('patch', url, json=req, params=params) + return OIDCProviderConfig(body) + + def delete_oidc_provider_config(self, provider_id): + _validate_oidc_provider_id(provider_id) + self._make_request('delete', '/oauthIdpConfigs/{0}'.format(provider_id)) + + def list_oidc_provider_configs(self, page_token=None, max_results=MAX_LIST_CONFIGS_RESULTS): + return _ListOIDCProviderConfigsPage( + self._fetch_oidc_provider_configs, page_token, max_results) + + def _fetch_oidc_provider_configs(self, page_token=None, max_results=MAX_LIST_CONFIGS_RESULTS): + return self._fetch_provider_configs('/oauthIdpConfigs', page_token, max_results) + + def get_saml_provider_config(self, provider_id): + _validate_saml_provider_id(provider_id) + body = self._make_request('get', '/inboundSamlConfigs/{0}'.format(provider_id)) + return SAMLProviderConfig(body) + + def create_saml_provider_config( + self, provider_id, idp_entity_id, sso_url, x509_certificates, + rp_entity_id, callback_url, display_name=None, enabled=None): + """Creates a new SAML provider config from the given parameters.""" + _validate_saml_provider_id(provider_id) + req = { + 'idpConfig': { + 'idpEntityId': _validate_non_empty_string(idp_entity_id, 'idp_entity_id'), + 'ssoUrl': _validate_url(sso_url, 'sso_url'), + 'idpCertificates': _validate_x509_certificates(x509_certificates), + }, + 'spConfig': { + 'spEntityId': _validate_non_empty_string(rp_entity_id, 'rp_entity_id'), + 'callbackUri': _validate_url(callback_url, 'callback_url'), + }, + } + if display_name is not None: + req['displayName'] = _auth_utils.validate_string(display_name, 'display_name') + if enabled is not None: + req['enabled'] = _auth_utils.validate_boolean(enabled, 'enabled') + + params = 'inboundSamlConfigId={0}'.format(provider_id) + body = self._make_request('post', '/inboundSamlConfigs', json=req, params=params) + return SAMLProviderConfig(body) + + def update_saml_provider_config( + self, provider_id, idp_entity_id=None, sso_url=None, x509_certificates=None, + rp_entity_id=None, callback_url=None, display_name=None, enabled=None): + """Updates an existing SAML provider config with the given parameters.""" + _validate_saml_provider_id(provider_id) + idp_config = {} + if idp_entity_id is not None: + idp_config['idpEntityId'] = _validate_non_empty_string(idp_entity_id, 'idp_entity_id') + if sso_url is not None: + idp_config['ssoUrl'] = _validate_url(sso_url, 'sso_url') + if x509_certificates is not None: + idp_config['idpCertificates'] = _validate_x509_certificates(x509_certificates) + + sp_config = {} + if rp_entity_id is not None: + sp_config['spEntityId'] = _validate_non_empty_string(rp_entity_id, 'rp_entity_id') + if callback_url is not None: + sp_config['callbackUri'] = _validate_url(callback_url, 'callback_url') + + req = {} + if display_name is not None: + if display_name == _user_mgt.DELETE_ATTRIBUTE: + req['displayName'] = None + else: + req['displayName'] = _auth_utils.validate_string(display_name, 'display_name') + if enabled is not None: + req['enabled'] = _auth_utils.validate_boolean(enabled, 'enabled') + if idp_config: + req['idpConfig'] = idp_config + if sp_config: + req['spConfig'] = sp_config + + if not req: + raise ValueError('At least one parameter must be specified for update.') + + update_mask = _auth_utils.build_update_mask(req) + params = 'updateMask={0}'.format(','.join(update_mask)) + url = '/inboundSamlConfigs/{0}'.format(provider_id) + body = self._make_request('patch', url, json=req, params=params) + return SAMLProviderConfig(body) + + def delete_saml_provider_config(self, provider_id): + _validate_saml_provider_id(provider_id) + self._make_request('delete', '/inboundSamlConfigs/{0}'.format(provider_id)) + + def list_saml_provider_configs(self, page_token=None, max_results=MAX_LIST_CONFIGS_RESULTS): + return _ListSAMLProviderConfigsPage( + self._fetch_saml_provider_configs, page_token, max_results) + + def _fetch_saml_provider_configs(self, page_token=None, max_results=MAX_LIST_CONFIGS_RESULTS): + return self._fetch_provider_configs('/inboundSamlConfigs', page_token, max_results) + + def _fetch_provider_configs(self, path, page_token=None, max_results=MAX_LIST_CONFIGS_RESULTS): + """Fetches a page of auth provider configs""" + if page_token is not None: + if not isinstance(page_token, str) or not page_token: + raise ValueError('Page token must be a non-empty string.') + if not isinstance(max_results, int): + raise ValueError('Max results must be an integer.') + if max_results < 1 or max_results > MAX_LIST_CONFIGS_RESULTS: + raise ValueError( + 'Max results must be a positive integer less than or equal to ' + '{0}.'.format(MAX_LIST_CONFIGS_RESULTS)) + + params = 'pageSize={0}'.format(max_results) + if page_token: + params += '&pageToken={0}'.format(page_token) + return self._make_request('get', path, params=params) + + def _make_request(self, method, path, **kwargs): + url = '{0}{1}'.format(self.base_url, path) + try: + return self.http_client.body(method, url, **kwargs) + except requests.exceptions.RequestException as error: + raise _auth_utils.handle_auth_backend_error(error) + + +def _validate_oidc_provider_id(provider_id): + if not isinstance(provider_id, str): + raise ValueError( + 'Invalid OIDC provider ID: {0}. Provider ID must be a non-empty string.'.format( + provider_id)) + if not provider_id.startswith('oidc.'): + raise ValueError('Invalid OIDC provider ID: {0}.'.format(provider_id)) + return provider_id + + +def _validate_saml_provider_id(provider_id): + if not isinstance(provider_id, str): + raise ValueError( + 'Invalid SAML provider ID: {0}. Provider ID must be a non-empty string.'.format( + provider_id)) + if not provider_id.startswith('saml.'): + raise ValueError('Invalid SAML provider ID: {0}.'.format(provider_id)) + return provider_id + + +def _validate_non_empty_string(value, label): + """Validates that the given value is a non-empty string.""" + if not isinstance(value, str): + raise ValueError('Invalid type for {0}: {1}.'.format(label, value)) + if not value: + raise ValueError('{0} must not be empty.'.format(label)) + return value + + +def _validate_url(url, label): + """Validates that the given value is a well-formed URL string.""" + if not isinstance(url, str) or not url: + raise ValueError( + 'Invalid photo URL: "{0}". {1} must be a non-empty ' + 'string.'.format(url, label)) + try: + parsed = parse.urlparse(url) + if not parsed.netloc: + raise ValueError('Malformed {0}: "{1}".'.format(label, url)) + return url + except Exception: + raise ValueError('Malformed {0}: "{1}".'.format(label, url)) + + +def _validate_x509_certificates(x509_certificates): + if not isinstance(x509_certificates, list) or not x509_certificates: + raise ValueError('x509_certificates must be a non-empty list.') + if not all([isinstance(cert, str) and cert for cert in x509_certificates]): + raise ValueError('x509_certificates must only contain non-empty strings.') + return [{'x509Certificate': cert} for cert in x509_certificates] diff --git a/venv/Lib/site-packages/firebase_admin/_auth_utils.py b/venv/Lib/site-packages/firebase_admin/_auth_utils.py new file mode 100644 index 000000000..2226675f9 --- /dev/null +++ b/venv/Lib/site-packages/firebase_admin/_auth_utils.py @@ -0,0 +1,422 @@ +# Copyright 2018 Google Inc. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +"""Firebase auth utils.""" + +import json +import re +from urllib import parse + +from firebase_admin import exceptions +from firebase_admin import _utils + + +MAX_CLAIMS_PAYLOAD_SIZE = 1000 +RESERVED_CLAIMS = set([ + 'acr', 'amr', 'at_hash', 'aud', 'auth_time', 'azp', 'cnf', 'c_hash', 'exp', 'iat', + 'iss', 'jti', 'nbf', 'nonce', 'sub', 'firebase', +]) +VALID_EMAIL_ACTION_TYPES = set(['VERIFY_EMAIL', 'EMAIL_SIGNIN', 'PASSWORD_RESET']) + + +class PageIterator: + """An iterator that allows iterating over a sequence of items, one at a time. + + This implementation loads a page of items into memory, and iterates on them. When the whole + page has been traversed, it loads another page. This class never keeps more than one page + of entries in memory. + """ + + def __init__(self, current_page): + if not current_page: + raise ValueError('Current page must not be None.') + self._current_page = current_page + self._index = 0 + + def next(self): + if self._index == len(self.items): + if self._current_page.has_next_page: + self._current_page = self._current_page.get_next_page() + self._index = 0 + if self._index < len(self.items): + result = self.items[self._index] + self._index += 1 + return result + raise StopIteration + + @property + def items(self): + raise NotImplementedError + + def __next__(self): + return self.next() + + def __iter__(self): + return self + + +def validate_uid(uid, required=False): + if uid is None and not required: + return None + if not isinstance(uid, str) or not uid or len(uid) > 128: + raise ValueError( + 'Invalid uid: "{0}". The uid must be a non-empty string with no more than 128 ' + 'characters.'.format(uid)) + return uid + +def validate_email(email, required=False): + if email is None and not required: + return None + if not isinstance(email, str) or not email: + raise ValueError( + 'Invalid email: "{0}". Email must be a non-empty string.'.format(email)) + parts = email.split('@') + if len(parts) != 2 or not parts[0] or not parts[1]: + raise ValueError('Malformed email address string: "{0}".'.format(email)) + return email + +def validate_phone(phone, required=False): + """Validates the specified phone number. + + Phone number vlidation is very lax here. Backend will enforce E.164 spec compliance, and + normalize accordingly. Here we check if the number starts with + sign, and contains at + least one alphanumeric character. + """ + if phone is None and not required: + return None + if not isinstance(phone, str) or not phone: + raise ValueError('Invalid phone number: "{0}". Phone number must be a non-empty ' + 'string.'.format(phone)) + if not phone.startswith('+') or not re.search('[a-zA-Z0-9]', phone): + raise ValueError('Invalid phone number: "{0}". Phone number must be a valid, E.164 ' + 'compliant identifier.'.format(phone)) + return phone + +def validate_password(password, required=False): + if password is None and not required: + return None + if not isinstance(password, str) or len(password) < 6: + raise ValueError( + 'Invalid password string. Password must be a string at least 6 characters long.') + return password + +def validate_bytes(value, label, required=False): + if value is None and not required: + return None + if not isinstance(value, bytes) or not value: + raise ValueError('{0} must be a non-empty byte sequence.'.format(label)) + return value + +def validate_display_name(display_name, required=False): + if display_name is None and not required: + return None + if not isinstance(display_name, str) or not display_name: + raise ValueError( + 'Invalid display name: "{0}". Display name must be a non-empty ' + 'string.'.format(display_name)) + return display_name + +def validate_provider_id(provider_id, required=True): + if provider_id is None and not required: + return None + if not isinstance(provider_id, str) or not provider_id: + raise ValueError( + 'Invalid provider ID: "{0}". Provider ID must be a non-empty ' + 'string.'.format(provider_id)) + return provider_id + +def validate_provider_uid(provider_uid, required=True): + if provider_uid is None and not required: + return None + if not isinstance(provider_uid, str) or not provider_uid: + raise ValueError( + 'Invalid provider UID: "{0}". Provider UID must be a non-empty ' + 'string.'.format(provider_uid)) + return provider_uid + +def validate_photo_url(photo_url, required=False): + """Parses and validates the given URL string.""" + if photo_url is None and not required: + return None + if not isinstance(photo_url, str) or not photo_url: + raise ValueError( + 'Invalid photo URL: "{0}". Photo URL must be a non-empty ' + 'string.'.format(photo_url)) + try: + parsed = parse.urlparse(photo_url) + if not parsed.netloc: + raise ValueError('Malformed photo URL: "{0}".'.format(photo_url)) + return photo_url + except Exception: + raise ValueError('Malformed photo URL: "{0}".'.format(photo_url)) + +def validate_timestamp(timestamp, label, required=False): + """Validates the given timestamp value. Timestamps must be positive integers.""" + if timestamp is None and not required: + return None + if isinstance(timestamp, bool): + raise ValueError('Boolean value specified as timestamp.') + try: + timestamp_int = int(timestamp) + except TypeError: + raise ValueError('Invalid type for timestamp value: {0}.'.format(timestamp)) + else: + if timestamp_int != timestamp: + raise ValueError('{0} must be a numeric value and a whole number.'.format(label)) + if timestamp_int <= 0: + raise ValueError('{0} timestamp must be a positive interger.'.format(label)) + return timestamp_int + +def validate_int(value, label, low=None, high=None): + """Validates that the given value represents an integer. + + There are several ways to represent an integer in Python (e.g. 2, 2L, 2.0). This method allows + for all such representations except for booleans. Booleans also behave like integers, but + always translate to 1 and 0. Passing a boolean to an API that expects integers is most likely + a developer error. + """ + if value is None or isinstance(value, bool): + raise ValueError('Invalid type for integer value: {0}.'.format(value)) + try: + val_int = int(value) + except TypeError: + raise ValueError('Invalid type for integer value: {0}.'.format(value)) + else: + if val_int != value: + # This will be True for non-numeric values like '2' and non-whole numbers like 2.5. + raise ValueError('{0} must be a numeric value and a whole number.'.format(label)) + if low is not None and val_int < low: + raise ValueError('{0} must not be smaller than {1}.'.format(label, low)) + if high is not None and val_int > high: + raise ValueError('{0} must not be larger than {1}.'.format(label, high)) + return val_int + +def validate_string(value, label): + """Validates that the given value is a string.""" + if not isinstance(value, str): + raise ValueError('Invalid type for {0}: {1}.'.format(label, value)) + return value + +def validate_boolean(value, label): + """Validates that the given value is a boolean.""" + if not isinstance(value, bool): + raise ValueError('Invalid type for {0}: {1}.'.format(label, value)) + return value + +def validate_custom_claims(custom_claims, required=False): + """Validates the specified custom claims. + + Custom claims must be specified as a JSON string. The string must not exceed 1000 + characters, and the parsed JSON payload must not contain reserved JWT claims. + """ + if custom_claims is None and not required: + return None + claims_str = str(custom_claims) + if len(claims_str) > MAX_CLAIMS_PAYLOAD_SIZE: + raise ValueError( + 'Custom claims payload must not exceed {0} characters.'.format( + MAX_CLAIMS_PAYLOAD_SIZE)) + try: + parsed = json.loads(claims_str) + except Exception: + raise ValueError('Failed to parse custom claims string as JSON.') + + if not isinstance(parsed, dict): + raise ValueError('Custom claims must be parseable as a JSON object.') + invalid_claims = RESERVED_CLAIMS.intersection(set(parsed.keys())) + if len(invalid_claims) > 1: + joined = ', '.join(sorted(invalid_claims)) + raise ValueError('Claims "{0}" are reserved, and must not be set.'.format(joined)) + if len(invalid_claims) == 1: + raise ValueError( + 'Claim "{0}" is reserved, and must not be set.'.format(invalid_claims.pop())) + return claims_str + +def validate_action_type(action_type): + if action_type not in VALID_EMAIL_ACTION_TYPES: + raise ValueError('Invalid action type provided action_type: {0}. \ + Valid values are {1}'.format(action_type, ', '.join(VALID_EMAIL_ACTION_TYPES))) + return action_type + +def build_update_mask(params): + """Creates an update mask list from the given dictionary.""" + mask = [] + for key, value in params.items(): + if isinstance(value, dict): + child_mask = build_update_mask(value) + for child in child_mask: + mask.append('{0}.{1}'.format(key, child)) + else: + mask.append(key) + + return sorted(mask) + + +class UidAlreadyExistsError(exceptions.AlreadyExistsError): + """The user with the provided uid already exists.""" + + default_message = 'The user with the provided uid already exists' + + def __init__(self, message, cause, http_response): + exceptions.AlreadyExistsError.__init__(self, message, cause, http_response) + + +class EmailAlreadyExistsError(exceptions.AlreadyExistsError): + """The user with the provided email already exists.""" + + default_message = 'The user with the provided email already exists' + + def __init__(self, message, cause, http_response): + exceptions.AlreadyExistsError.__init__(self, message, cause, http_response) + + +class InsufficientPermissionError(exceptions.PermissionDeniedError): + """The credential used to initialize the SDK lacks required permissions.""" + + default_message = ('The credential used to initialize the SDK has insufficient ' + 'permissions to perform the requested operation. See ' + 'https://firebase.google.com/docs/admin/setup for details ' + 'on how to initialize the Admin SDK with appropriate permissions') + + def __init__(self, message, cause, http_response): + exceptions.PermissionDeniedError.__init__(self, message, cause, http_response) + + +class InvalidDynamicLinkDomainError(exceptions.InvalidArgumentError): + """Dynamic link domain in ActionCodeSettings is not authorized.""" + + default_message = 'Dynamic link domain specified in ActionCodeSettings is not authorized' + + def __init__(self, message, cause, http_response): + exceptions.InvalidArgumentError.__init__(self, message, cause, http_response) + + +class InvalidIdTokenError(exceptions.InvalidArgumentError): + """The provided ID token is not a valid Firebase ID token.""" + + default_message = 'The provided ID token is invalid' + + def __init__(self, message, cause=None, http_response=None): + exceptions.InvalidArgumentError.__init__(self, message, cause, http_response) + + +class PhoneNumberAlreadyExistsError(exceptions.AlreadyExistsError): + """The user with the provided phone number already exists.""" + + default_message = 'The user with the provided phone number already exists' + + def __init__(self, message, cause, http_response): + exceptions.AlreadyExistsError.__init__(self, message, cause, http_response) + + +class UnexpectedResponseError(exceptions.UnknownError): + """Backend service responded with an unexpected or malformed response.""" + + def __init__(self, message, cause=None, http_response=None): + exceptions.UnknownError.__init__(self, message, cause, http_response) + + +class UserNotFoundError(exceptions.NotFoundError): + """No user record found for the specified identifier.""" + + default_message = 'No user record found for the given identifier' + + def __init__(self, message, cause=None, http_response=None): + exceptions.NotFoundError.__init__(self, message, cause, http_response) + + +class TenantNotFoundError(exceptions.NotFoundError): + """No tenant found for the specified identifier.""" + + default_message = 'No tenant found for the given identifier' + + def __init__(self, message, cause=None, http_response=None): + exceptions.NotFoundError.__init__(self, message, cause, http_response) + + +class TenantIdMismatchError(exceptions.InvalidArgumentError): + """Missing or invalid tenant ID field in the given JWT.""" + + def __init__(self, message): + exceptions.InvalidArgumentError.__init__(self, message) + + +class ConfigurationNotFoundError(exceptions.NotFoundError): + """No auth provider found for the specified identifier.""" + + default_message = 'No auth provider found for the given identifier' + + def __init__(self, message, cause=None, http_response=None): + exceptions.NotFoundError.__init__(self, message, cause, http_response) + + +_CODE_TO_EXC_TYPE = { + 'CONFIGURATION_NOT_FOUND': ConfigurationNotFoundError, + 'DUPLICATE_EMAIL': EmailAlreadyExistsError, + 'DUPLICATE_LOCAL_ID': UidAlreadyExistsError, + 'EMAIL_EXISTS': EmailAlreadyExistsError, + 'INSUFFICIENT_PERMISSION': InsufficientPermissionError, + 'INVALID_DYNAMIC_LINK_DOMAIN': InvalidDynamicLinkDomainError, + 'INVALID_ID_TOKEN': InvalidIdTokenError, + 'PHONE_NUMBER_EXISTS': PhoneNumberAlreadyExistsError, + 'TENANT_NOT_FOUND': TenantNotFoundError, + 'USER_NOT_FOUND': UserNotFoundError, +} + + +def handle_auth_backend_error(error): + """Converts a requests error received from the Firebase Auth service into a FirebaseError.""" + if error.response is None: + return _utils.handle_requests_error(error) + + code, custom_message = _parse_error_body(error.response) + if not code: + msg = 'Unexpected error response: {0}'.format(error.response.content.decode()) + return _utils.handle_requests_error(error, message=msg) + + exc_type = _CODE_TO_EXC_TYPE.get(code) + msg = _build_error_message(code, exc_type, custom_message) + if not exc_type: + return _utils.handle_requests_error(error, message=msg) + + return exc_type(msg, cause=error, http_response=error.response) + + +def _parse_error_body(response): + """Parses the given error response to extract Auth error code and message.""" + error_dict = {} + try: + parsed_body = response.json() + if isinstance(parsed_body, dict): + error_dict = parsed_body.get('error', {}) + except ValueError: + pass + + # Auth error response format: {"error": {"message": "AUTH_ERROR_CODE: Optional text"}} + code = error_dict.get('message') if isinstance(error_dict, dict) else None + custom_message = None + if code: + separator = code.find(':') + if separator != -1: + custom_message = code[separator + 1:].strip() + code = code[:separator] + + return code, custom_message + + +def _build_error_message(code, exc_type, custom_message): + default_message = exc_type.default_message if ( + exc_type and hasattr(exc_type, 'default_message')) else 'Error while calling Auth service' + ext = ' {0}'.format(custom_message) if custom_message else '' + return '{0} ({1}).{2}'.format(default_message, code, ext) diff --git a/venv/Lib/site-packages/firebase_admin/_http_client.py b/venv/Lib/site-packages/firebase_admin/_http_client.py new file mode 100644 index 000000000..f6f0d89fa --- /dev/null +++ b/venv/Lib/site-packages/firebase_admin/_http_client.py @@ -0,0 +1,148 @@ +# Copyright 2017 Google Inc. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +"""Internal HTTP client module. + + This module provides utilities for making HTTP calls using the requests library. + """ + +from google.auth import transport +import requests +from requests.packages.urllib3.util import retry # pylint: disable=import-error + + +_ANY_METHOD = None + +# Default retry configuration: Retries once on low-level connection and socket read errors. +# Retries up to 4 times on HTTP 500 and 503 errors, with exponential backoff. Returns the +# last response upon exhausting all retries. +DEFAULT_RETRY_CONFIG = retry.Retry( + connect=1, read=1, status=4, status_forcelist=[500, 503], method_whitelist=_ANY_METHOD, + raise_on_status=False, backoff_factor=0.5) + + +DEFAULT_TIMEOUT_SECONDS = 120 + + +class HttpClient: + """Base HTTP client used to make HTTP calls. + + HttpClient maintains an HTTP session, and handles request authentication and retries if + necessary. + """ + + def __init__( + self, credential=None, session=None, base_url='', headers=None, + retries=DEFAULT_RETRY_CONFIG, timeout=DEFAULT_TIMEOUT_SECONDS): + """Creates a new HttpClient instance from the provided arguments. + + If a credential is provided, initializes a new HTTP session authorized with it. If neither + a credential nor a session is provided, initializes a new unauthorized session. + + Args: + credential: A Google credential that can be used to authenticate requests (optional). + session: A custom HTTP session (optional). + base_url: A URL prefix to be added to all outgoing requests (optional). + headers: A map of headers to be added to all outgoing requests (optional). + retries: A urllib retry configuration. Default settings would retry once for low-level + connection and socket read errors, and up to 4 times for HTTP 500 and 503 errors. + Pass a False value to disable retries (optional). + timeout: HTTP timeout in seconds. Defaults to 120 seconds when not specified. Set to + None to disable timeouts (optional). + """ + if credential: + self._session = transport.requests.AuthorizedSession(credential) + elif session: + self._session = session + else: + self._session = requests.Session() # pylint: disable=redefined-variable-type + + if headers: + self._session.headers.update(headers) + if retries: + self._session.mount('http://', requests.adapters.HTTPAdapter(max_retries=retries)) + self._session.mount('https://', requests.adapters.HTTPAdapter(max_retries=retries)) + self._base_url = base_url + self._timeout = timeout + + @property + def session(self): + return self._session + + @property + def base_url(self): + return self._base_url + + @property + def timeout(self): + return self._timeout + + def parse_body(self, resp): + raise NotImplementedError + + def request(self, method, url, **kwargs): + """Makes an HTTP call using the Python requests library. + + This is the sole entry point to the requests library. All other helper methods in this + class call this method to send HTTP requests out. Refer to + http://docs.python-requests.org/en/master/api/ for more information on supported options + and features. + + Args: + method: HTTP method name as a string (e.g. get, post). + url: URL of the remote endpoint. + kwargs: An additional set of keyword arguments to be passed into the requests API + (e.g. json, params, timeout). + + Returns: + Response: An HTTP response object. + + Raises: + RequestException: Any requests exceptions encountered while making the HTTP call. + """ + if 'timeout' not in kwargs: + kwargs['timeout'] = self.timeout + resp = self._session.request(method, self.base_url + url, **kwargs) + resp.raise_for_status() + return resp + + def headers(self, method, url, **kwargs): + resp = self.request(method, url, **kwargs) + return resp.headers + + def body_and_response(self, method, url, **kwargs): + resp = self.request(method, url, **kwargs) + return self.parse_body(resp), resp + + def body(self, method, url, **kwargs): + resp = self.request(method, url, **kwargs) + return self.parse_body(resp) + + def headers_and_body(self, method, url, **kwargs): + resp = self.request(method, url, **kwargs) + return resp.headers, self.parse_body(resp) + + def close(self): + self._session.close() + self._session = None + + +class JsonHttpClient(HttpClient): + """An HTTP client that parses response messages as JSON.""" + + def __init__(self, **kwargs): + HttpClient.__init__(self, **kwargs) + + def parse_body(self, resp): + return resp.json() diff --git a/venv/Lib/site-packages/firebase_admin/_messaging_encoder.py b/venv/Lib/site-packages/firebase_admin/_messaging_encoder.py new file mode 100644 index 000000000..48a3dd3cd --- /dev/null +++ b/venv/Lib/site-packages/firebase_admin/_messaging_encoder.py @@ -0,0 +1,696 @@ +# Copyright 2019 Google Inc. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +"""Encoding and validation utils for the messaging (FCM) module.""" + +import datetime +import json +import math +import numbers +import re + +import firebase_admin._messaging_utils as _messaging_utils + + +class Message: + """A message that can be sent via Firebase Cloud Messaging. + + Contains payload information as well as recipient information. In particular, the message must + contain exactly one of token, topic or condition fields. + + Args: + data: A dictionary of data fields (optional). All keys and values in the dictionary must be + strings. + notification: An instance of ``messaging.Notification`` (optional). + android: An instance of ``messaging.AndroidConfig`` (optional). + webpush: An instance of ``messaging.WebpushConfig`` (optional). + apns: An instance of ``messaging.ApnsConfig`` (optional). + fcm_options: An instance of ``messaging.FCMOptions`` (optional). + token: The registration token of the device to which the message should be sent (optional). + topic: Name of the FCM topic to which the message should be sent (optional). Topic name + may contain the ``/topics/`` prefix. + condition: The FCM condition to which the message should be sent (optional). + """ + + def __init__(self, data=None, notification=None, android=None, webpush=None, apns=None, + fcm_options=None, token=None, topic=None, condition=None): + self.data = data + self.notification = notification + self.android = android + self.webpush = webpush + self.apns = apns + self.fcm_options = fcm_options + self.token = token + self.topic = topic + self.condition = condition + + def __str__(self): + return json.dumps(self, cls=MessageEncoder, sort_keys=True) + + +class MulticastMessage: + """A message that can be sent to multiple tokens via Firebase Cloud Messaging. + + Args: + tokens: A list of registration tokens of targeted devices. + data: A dictionary of data fields (optional). All keys and values in the dictionary must be + strings. + notification: An instance of ``messaging.Notification`` (optional). + android: An instance of ``messaging.AndroidConfig`` (optional). + webpush: An instance of ``messaging.WebpushConfig`` (optional). + apns: An instance of ``messaging.ApnsConfig`` (optional). + fcm_options: An instance of ``messaging.FCMOptions`` (optional). + """ + def __init__(self, tokens, data=None, notification=None, android=None, webpush=None, apns=None, + fcm_options=None): + _Validators.check_string_list('MulticastMessage.tokens', tokens) + if len(tokens) > 500: + raise ValueError('MulticastMessage.tokens must not contain more than 500 tokens.') + self.tokens = tokens + self.data = data + self.notification = notification + self.android = android + self.webpush = webpush + self.apns = apns + self.fcm_options = fcm_options + + +class _Validators: + """A collection of data validation utilities. + + Methods provided in this class raise ``ValueErrors`` if any validations fail. + """ + + @classmethod + def check_string(cls, label, value, non_empty=False): + """Checks if the given value is a string.""" + if value is None: + return None + if not isinstance(value, str): + if non_empty: + raise ValueError('{0} must be a non-empty string.'.format(label)) + raise ValueError('{0} must be a string.'.format(label)) + if non_empty and not value: + raise ValueError('{0} must be a non-empty string.'.format(label)) + return value + + @classmethod + def check_number(cls, label, value): + if value is None: + return None + if not isinstance(value, numbers.Number): + raise ValueError('{0} must be a number.'.format(label)) + return value + + @classmethod + def check_string_dict(cls, label, value): + """Checks if the given value is a dictionary comprised only of string keys and values.""" + if value is None or value == {}: + return None + if not isinstance(value, dict): + raise ValueError('{0} must be a dictionary.'.format(label)) + non_str = [k for k in value if not isinstance(k, str)] + if non_str: + raise ValueError('{0} must not contain non-string keys.'.format(label)) + non_str = [v for v in value.values() if not isinstance(v, str)] + if non_str: + raise ValueError('{0} must not contain non-string values.'.format(label)) + return value + + @classmethod + def check_string_list(cls, label, value): + """Checks if the given value is a list comprised only of strings.""" + if value is None or value == []: + return None + if not isinstance(value, list): + raise ValueError('{0} must be a list of strings.'.format(label)) + non_str = [k for k in value if not isinstance(k, str)] + if non_str: + raise ValueError('{0} must not contain non-string values.'.format(label)) + return value + + @classmethod + def check_number_list(cls, label, value): + """Checks if the given value is a list comprised only of numbers.""" + if value is None or value == []: + return None + if not isinstance(value, list): + raise ValueError('{0} must be a list of numbers.'.format(label)) + non_number = [k for k in value if not isinstance(k, numbers.Number)] + if non_number: + raise ValueError('{0} must not contain non-number values.'.format(label)) + return value + + @classmethod + def check_analytics_label(cls, label, value): + """Checks if the given value is a valid analytics label.""" + value = _Validators.check_string(label, value) + if value is not None and not re.match(r'^[a-zA-Z0-9-_.~%]{1,50}$', value): + raise ValueError('Malformed {}.'.format(label)) + return value + + @classmethod + def check_datetime(cls, label, value): + """Checks if the given value is a datetime.""" + if value is None: + return None + if not isinstance(value, datetime.datetime): + raise ValueError('{0} must be a datetime.'.format(label)) + return value + + +class MessageEncoder(json.JSONEncoder): + """A custom ``JSONEncoder`` implementation for serializing Message instances into JSON.""" + + @classmethod + def remove_null_values(cls, dict_value): + return {k: v for k, v in dict_value.items() if v not in [None, [], {}]} + + @classmethod + def encode_android(cls, android): + """Encodes an ``AndroidConfig`` instance into JSON.""" + if android is None: + return None + if not isinstance(android, _messaging_utils.AndroidConfig): + raise ValueError('Message.android must be an instance of AndroidConfig class.') + result = { + 'collapse_key': _Validators.check_string( + 'AndroidConfig.collapse_key', android.collapse_key), + 'data': _Validators.check_string_dict( + 'AndroidConfig.data', android.data), + 'notification': cls.encode_android_notification(android.notification), + 'priority': _Validators.check_string( + 'AndroidConfig.priority', android.priority, non_empty=True), + 'restricted_package_name': _Validators.check_string( + 'AndroidConfig.restricted_package_name', android.restricted_package_name), + 'ttl': cls.encode_ttl(android.ttl), + 'fcm_options': cls.encode_android_fcm_options(android.fcm_options), + } + result = cls.remove_null_values(result) + priority = result.get('priority') + if priority and priority not in ('high', 'normal'): + raise ValueError('AndroidConfig.priority must be "high" or "normal".') + return result + + @classmethod + def encode_android_fcm_options(cls, fcm_options): + """Encodes an ``AndroidFCMOptions`` instance into JSON.""" + if fcm_options is None: + return None + if not isinstance(fcm_options, _messaging_utils.AndroidFCMOptions): + raise ValueError('AndroidConfig.fcm_options must be an instance of ' + 'AndroidFCMOptions class.') + result = { + 'analytics_label': _Validators.check_analytics_label( + 'AndroidFCMOptions.analytics_label', fcm_options.analytics_label), + } + result = cls.remove_null_values(result) + return result + + @classmethod + def encode_ttl(cls, ttl): + """Encodes an ``AndroidConfig`` ``TTL`` duration into a string.""" + if ttl is None: + return None + if isinstance(ttl, numbers.Number): + ttl = datetime.timedelta(seconds=ttl) + if not isinstance(ttl, datetime.timedelta): + raise ValueError('AndroidConfig.ttl must be a duration in seconds or an instance of ' + 'datetime.timedelta.') + total_seconds = ttl.total_seconds() + if total_seconds < 0: + raise ValueError('AndroidConfig.ttl must not be negative.') + seconds = int(math.floor(total_seconds)) + nanos = int((total_seconds - seconds) * 1e9) + if nanos: + return '{0}.{1}s'.format(seconds, str(nanos).zfill(9)) + return '{0}s'.format(seconds) + + @classmethod + def encode_milliseconds(cls, label, msec): + """Encodes a duration in milliseconds into a string.""" + if msec is None: + return None + if isinstance(msec, numbers.Number): + msec = datetime.timedelta(milliseconds=msec) + if not isinstance(msec, datetime.timedelta): + raise ValueError('{0} must be a duration in milliseconds or an instance of ' + 'datetime.timedelta.'.format(label)) + total_seconds = msec.total_seconds() + if total_seconds < 0: + raise ValueError('{0} must not be negative.'.format(label)) + seconds = int(math.floor(total_seconds)) + nanos = int((total_seconds - seconds) * 1e9) + if nanos: + return '{0}.{1}s'.format(seconds, str(nanos).zfill(9)) + return '{0}s'.format(seconds) + + @classmethod + def encode_android_notification(cls, notification): + """Encodes an ``AndroidNotification`` instance into JSON.""" + if notification is None: + return None + if not isinstance(notification, _messaging_utils.AndroidNotification): + raise ValueError('AndroidConfig.notification must be an instance of ' + 'AndroidNotification class.') + result = { + 'body': _Validators.check_string( + 'AndroidNotification.body', notification.body), + 'body_loc_args': _Validators.check_string_list( + 'AndroidNotification.body_loc_args', notification.body_loc_args), + 'body_loc_key': _Validators.check_string( + 'AndroidNotification.body_loc_key', notification.body_loc_key), + 'click_action': _Validators.check_string( + 'AndroidNotification.click_action', notification.click_action), + 'color': _Validators.check_string( + 'AndroidNotification.color', notification.color, non_empty=True), + 'icon': _Validators.check_string( + 'AndroidNotification.icon', notification.icon), + 'sound': _Validators.check_string( + 'AndroidNotification.sound', notification.sound), + 'tag': _Validators.check_string( + 'AndroidNotification.tag', notification.tag), + 'title': _Validators.check_string( + 'AndroidNotification.title', notification.title), + 'title_loc_args': _Validators.check_string_list( + 'AndroidNotification.title_loc_args', notification.title_loc_args), + 'title_loc_key': _Validators.check_string( + 'AndroidNotification.title_loc_key', notification.title_loc_key), + 'channel_id': _Validators.check_string( + 'AndroidNotification.channel_id', notification.channel_id), + 'image': _Validators.check_string( + 'image', notification.image), + 'ticker': _Validators.check_string( + 'AndroidNotification.ticker', notification.ticker), + 'sticky': notification.sticky, + 'event_time': _Validators.check_datetime( + 'AndroidNotification.event_timestamp', notification.event_timestamp), + 'local_only': notification.local_only, + 'notification_priority': _Validators.check_string( + 'AndroidNotification.priority', notification.priority, non_empty=True), + 'vibrate_timings': _Validators.check_number_list( + 'AndroidNotification.vibrate_timings_millis', notification.vibrate_timings_millis), + 'default_vibrate_timings': notification.default_vibrate_timings, + 'default_sound': notification.default_sound, + 'default_light_settings': notification.default_light_settings, + 'light_settings': cls.encode_light_settings(notification.light_settings), + 'visibility': _Validators.check_string( + 'AndroidNotification.visibility', notification.visibility, non_empty=True), + 'notification_count': _Validators.check_number( + 'AndroidNotification.notification_count', notification.notification_count) + } + result = cls.remove_null_values(result) + color = result.get('color') + if color and not re.match(r'^#[0-9a-fA-F]{6}$', color): + raise ValueError( + 'AndroidNotification.color must be in the form #RRGGBB.') + if result.get('body_loc_args') and not result.get('body_loc_key'): + raise ValueError( + 'AndroidNotification.body_loc_key is required when specifying body_loc_args.') + if result.get('title_loc_args') and not result.get('title_loc_key'): + raise ValueError( + 'AndroidNotification.title_loc_key is required when specifying title_loc_args.') + + event_time = result.get('event_time') + if event_time: + # if the datetime instance is not naive (tzinfo is present), convert to UTC + # otherwise (tzinfo is None) assume the datetime instance is already in UTC + if event_time.tzinfo is not None: + event_time = event_time.astimezone(datetime.timezone.utc) + result['event_time'] = event_time.strftime('%Y-%m-%dT%H:%M:%S.%fZ') + + priority = result.get('notification_priority') + if priority: + if priority not in ('min', 'low', 'default', 'high', 'max'): + raise ValueError('AndroidNotification.priority must be "default", "min", "low", ' + '"high" or "max".') + result['notification_priority'] = 'PRIORITY_' + priority.upper() + + visibility = result.get('visibility') + if visibility: + if visibility not in ('private', 'public', 'secret'): + raise ValueError( + 'AndroidNotification.visibility must be "private", "public" or "secret".') + result['visibility'] = visibility.upper() + + vibrate_timings_millis = result.get('vibrate_timings') + if vibrate_timings_millis: + vibrate_timing_strings = [] + for msec in vibrate_timings_millis: + formated_string = cls.encode_milliseconds( + 'AndroidNotification.vibrate_timings_millis', msec) + vibrate_timing_strings.append(formated_string) + result['vibrate_timings'] = vibrate_timing_strings + return result + + @classmethod + def encode_light_settings(cls, light_settings): + """Encodes a ``LightSettings`` instance into JSON.""" + if light_settings is None: + return None + if not isinstance(light_settings, _messaging_utils.LightSettings): + raise ValueError( + 'AndroidNotification.light_settings must be an instance of LightSettings class.') + result = { + 'color': _Validators.check_string( + 'LightSettings.color', light_settings.color, non_empty=True), + 'light_on_duration': cls.encode_milliseconds( + 'LightSettings.light_on_duration_millis', light_settings.light_on_duration_millis), + 'light_off_duration': cls.encode_milliseconds( + 'LightSettings.light_off_duration_millis', + light_settings.light_off_duration_millis), + } + result = cls.remove_null_values(result) + light_on_duration = result.get('light_on_duration') + if not light_on_duration: + raise ValueError( + 'LightSettings.light_on_duration_millis is required.') + + light_off_duration = result.get('light_off_duration') + if not light_off_duration: + raise ValueError( + 'LightSettings.light_off_duration_millis is required.') + + color = result.get('color') + if not color: + raise ValueError('LightSettings.color is required.') + if not re.match(r'^#[0-9a-fA-F]{6}$', color) and not re.match(r'^#[0-9a-fA-F]{8}$', color): + raise ValueError( + 'LightSettings.color must be in the form #RRGGBB or #RRGGBBAA.') + if len(color) == 7: + color = (color+'FF') + rgba = [int(color[i:i + 2], 16) / 255.0 for i in (1, 3, 5, 7)] + result['color'] = {'red': rgba[0], 'green': rgba[1], + 'blue': rgba[2], 'alpha': rgba[3]} + return result + + @classmethod + def encode_webpush(cls, webpush): + """Encodes a ``WebpushConfig`` instance into JSON.""" + if webpush is None: + return None + if not isinstance(webpush, _messaging_utils.WebpushConfig): + raise ValueError('Message.webpush must be an instance of WebpushConfig class.') + result = { + 'data': _Validators.check_string_dict( + 'WebpushConfig.data', webpush.data), + 'headers': _Validators.check_string_dict( + 'WebpushConfig.headers', webpush.headers), + 'notification': cls.encode_webpush_notification(webpush.notification), + 'fcm_options': cls.encode_webpush_fcm_options(webpush.fcm_options), + } + return cls.remove_null_values(result) + + @classmethod + def encode_webpush_notification(cls, notification): + """Encodes a ``WebpushNotification`` instance into JSON.""" + if notification is None: + return None + if not isinstance(notification, _messaging_utils.WebpushNotification): + raise ValueError('WebpushConfig.notification must be an instance of ' + 'WebpushNotification class.') + result = { + 'actions': cls.encode_webpush_notification_actions(notification.actions), + 'badge': _Validators.check_string( + 'WebpushNotification.badge', notification.badge), + 'body': _Validators.check_string( + 'WebpushNotification.body', notification.body), + 'data': notification.data, + 'dir': _Validators.check_string( + 'WebpushNotification.direction', notification.direction), + 'icon': _Validators.check_string( + 'WebpushNotification.icon', notification.icon), + 'image': _Validators.check_string( + 'WebpushNotification.image', notification.image), + 'lang': _Validators.check_string( + 'WebpushNotification.language', notification.language), + 'renotify': notification.renotify, + 'requireInteraction': notification.require_interaction, + 'silent': notification.silent, + 'tag': _Validators.check_string( + 'WebpushNotification.tag', notification.tag), + 'timestamp': _Validators.check_number( + 'WebpushNotification.timestamp_millis', notification.timestamp_millis), + 'title': _Validators.check_string( + 'WebpushNotification.title', notification.title), + 'vibrate': notification.vibrate, + } + direction = result.get('dir') + if direction and direction not in ('auto', 'ltr', 'rtl'): + raise ValueError('WebpushNotification.direction must be "auto", "ltr" or "rtl".') + if notification.custom_data is not None: + if not isinstance(notification.custom_data, dict): + raise ValueError('WebpushNotification.custom_data must be a dict.') + for key, value in notification.custom_data.items(): + if key in result: + raise ValueError( + 'Multiple specifications for {0} in WebpushNotification.'.format(key)) + result[key] = value + return cls.remove_null_values(result) + + @classmethod + def encode_webpush_notification_actions(cls, actions): + """Encodes a list of ``WebpushNotificationActions`` into JSON.""" + if actions is None: + return None + if not isinstance(actions, list): + raise ValueError('WebpushConfig.notification.actions must be a list of ' + 'WebpushNotificationAction instances.') + results = [] + for action in actions: + if not isinstance(action, _messaging_utils.WebpushNotificationAction): + raise ValueError('WebpushConfig.notification.actions must be a list of ' + 'WebpushNotificationAction instances.') + result = { + 'action': _Validators.check_string( + 'WebpushNotificationAction.action', action.action), + 'title': _Validators.check_string( + 'WebpushNotificationAction.title', action.title), + 'icon': _Validators.check_string( + 'WebpushNotificationAction.icon', action.icon), + } + results.append(cls.remove_null_values(result)) + return results + + @classmethod + def encode_webpush_fcm_options(cls, options): + """Encodes a ``WebpushFCMOptions`` instance into JSON.""" + if options is None: + return None + result = { + 'link': _Validators.check_string('WebpushConfig.fcm_options.link', options.link), + } + result = cls.remove_null_values(result) + link = result.get('link') + if link is not None and not link.startswith('https://'): + raise ValueError('WebpushFCMOptions.link must be a HTTPS URL.') + return result + + @classmethod + def encode_apns(cls, apns): + """Encodes an ``APNSConfig`` instance into JSON.""" + if apns is None: + return None + if not isinstance(apns, _messaging_utils.APNSConfig): + raise ValueError('Message.apns must be an instance of APNSConfig class.') + result = { + 'headers': _Validators.check_string_dict( + 'APNSConfig.headers', apns.headers), + 'payload': cls.encode_apns_payload(apns.payload), + 'fcm_options': cls.encode_apns_fcm_options(apns.fcm_options), + } + return cls.remove_null_values(result) + + @classmethod + def encode_apns_payload(cls, payload): + """Encodes an ``APNSPayload`` instance into JSON.""" + if payload is None: + return None + if not isinstance(payload, _messaging_utils.APNSPayload): + raise ValueError('APNSConfig.payload must be an instance of APNSPayload class.') + result = { + 'aps': cls.encode_aps(payload.aps) + } + for key, value in payload.custom_data.items(): + result[key] = value + return cls.remove_null_values(result) + + @classmethod + def encode_apns_fcm_options(cls, fcm_options): + """Encodes an ``APNSFCMOptions`` instance into JSON.""" + if fcm_options is None: + return None + if not isinstance(fcm_options, _messaging_utils.APNSFCMOptions): + raise ValueError('APNSConfig.fcm_options must be an instance of APNSFCMOptions class.') + result = { + 'analytics_label': _Validators.check_analytics_label( + 'APNSFCMOptions.analytics_label', fcm_options.analytics_label), + 'image': _Validators.check_string('APNSFCMOptions.image', fcm_options.image) + } + result = cls.remove_null_values(result) + return result + + @classmethod + def encode_aps(cls, aps): + """Encodes an ``Aps`` instance into JSON.""" + if not isinstance(aps, _messaging_utils.Aps): + raise ValueError('APNSPayload.aps must be an instance of Aps class.') + result = { + 'alert': cls.encode_aps_alert(aps.alert), + 'badge': _Validators.check_number('Aps.badge', aps.badge), + 'sound': cls.encode_aps_sound(aps.sound), + 'category': _Validators.check_string('Aps.category', aps.category), + 'thread-id': _Validators.check_string('Aps.thread_id', aps.thread_id), + } + if aps.content_available is True: + result['content-available'] = 1 + if aps.mutable_content is True: + result['mutable-content'] = 1 + if aps.custom_data is not None: + if not isinstance(aps.custom_data, dict): + raise ValueError('Aps.custom_data must be a dict.') + for key, val in aps.custom_data.items(): + _Validators.check_string('Aps.custom_data key', key) + if key in result: + raise ValueError('Multiple specifications for {0} in Aps.'.format(key)) + result[key] = val + return cls.remove_null_values(result) + + @classmethod + def encode_aps_sound(cls, sound): + """Encodes an APNs sound configuration into JSON.""" + if sound is None: + return None + if sound and isinstance(sound, str): + return sound + if not isinstance(sound, _messaging_utils.CriticalSound): + raise ValueError( + 'Aps.sound must be a non-empty string or an instance of CriticalSound class.') + result = { + 'name': _Validators.check_string('CriticalSound.name', sound.name, non_empty=True), + 'volume': _Validators.check_number('CriticalSound.volume', sound.volume), + } + if sound.critical: + result['critical'] = 1 + if not result['name']: + raise ValueError('CriticalSond.name must be a non-empty string.') + volume = result['volume'] + if volume is not None and (volume < 0 or volume > 1): + raise ValueError('CriticalSound.volume must be in the interval [0,1].') + return cls.remove_null_values(result) + + @classmethod + def encode_aps_alert(cls, alert): + """Encodes an ``ApsAlert`` instance into JSON.""" + if alert is None: + return None + if isinstance(alert, str): + return alert + if not isinstance(alert, _messaging_utils.ApsAlert): + raise ValueError('Aps.alert must be a string or an instance of ApsAlert class.') + result = { + 'title': _Validators.check_string('ApsAlert.title', alert.title), + 'subtitle': _Validators.check_string('ApsAlert.subtitle', alert.subtitle), + 'body': _Validators.check_string('ApsAlert.body', alert.body), + 'title-loc-key': _Validators.check_string( + 'ApsAlert.title_loc_key', alert.title_loc_key), + 'title-loc-args': _Validators.check_string_list( + 'ApsAlert.title_loc_args', alert.title_loc_args), + 'loc-key': _Validators.check_string( + 'ApsAlert.loc_key', alert.loc_key), + 'loc-args': _Validators.check_string_list( + 'ApsAlert.loc_args', alert.loc_args), + 'action-loc-key': _Validators.check_string( + 'ApsAlert.action_loc_key', alert.action_loc_key), + 'launch-image': _Validators.check_string( + 'ApsAlert.launch_image', alert.launch_image), + } + if result.get('loc-args') and not result.get('loc-key'): + raise ValueError( + 'ApsAlert.loc_key is required when specifying loc_args.') + if result.get('title-loc-args') and not result.get('title-loc-key'): + raise ValueError( + 'ApsAlert.title_loc_key is required when specifying title_loc_args.') + if alert.custom_data is not None: + if not isinstance(alert.custom_data, dict): + raise ValueError('ApsAlert.custom_data must be a dict.') + for key, val in alert.custom_data.items(): + _Validators.check_string('ApsAlert.custom_data key', key) + # allow specifying key override because Apple could update API so that key + # could have unexpected value type + result[key] = val + return cls.remove_null_values(result) + + @classmethod + def encode_notification(cls, notification): + """Encodes a ``Notification`` instance into JSON.""" + if notification is None: + return None + if not isinstance(notification, _messaging_utils.Notification): + raise ValueError('Message.notification must be an instance of Notification class.') + result = { + 'body': _Validators.check_string('Notification.body', notification.body), + 'title': _Validators.check_string('Notification.title', notification.title), + 'image': _Validators.check_string('Notification.image', notification.image) + } + return cls.remove_null_values(result) + + @classmethod + def sanitize_topic_name(cls, topic): + """Removes the /topics/ prefix from the topic name, if present.""" + if not topic: + return None + prefix = '/topics/' + if topic.startswith(prefix): + topic = topic[len(prefix):] + # Checks for illegal characters and empty string. + if not re.match(r'^[a-zA-Z0-9-_\.~%]+$', topic): + raise ValueError('Malformed topic name.') + return topic + + def default(self, o): # pylint: disable=method-hidden + if not isinstance(o, Message): + return json.JSONEncoder.default(self, o) + result = { + 'android': MessageEncoder.encode_android(o.android), + 'apns': MessageEncoder.encode_apns(o.apns), + 'condition': _Validators.check_string( + 'Message.condition', o.condition, non_empty=True), + 'data': _Validators.check_string_dict('Message.data', o.data), + 'notification': MessageEncoder.encode_notification(o.notification), + 'token': _Validators.check_string('Message.token', o.token, non_empty=True), + 'topic': _Validators.check_string('Message.topic', o.topic, non_empty=True), + 'webpush': MessageEncoder.encode_webpush(o.webpush), + 'fcm_options': MessageEncoder.encode_fcm_options(o.fcm_options), + } + result['topic'] = MessageEncoder.sanitize_topic_name(result.get('topic')) + result = MessageEncoder.remove_null_values(result) + target_count = sum([t in result for t in ['token', 'topic', 'condition']]) + if target_count != 1: + raise ValueError('Exactly one of token, topic or condition must be specified.') + return result + + @classmethod + def encode_fcm_options(cls, fcm_options): + """Encodes an ``FCMOptions`` instance into JSON.""" + if fcm_options is None: + return None + if not isinstance(fcm_options, _messaging_utils.FCMOptions): + raise ValueError('Message.fcm_options must be an instance of FCMOptions class.') + result = { + 'analytics_label': _Validators.check_analytics_label( + 'FCMOptions.analytics_label', fcm_options.analytics_label), + } + result = cls.remove_null_values(result) + return result diff --git a/venv/Lib/site-packages/firebase_admin/_messaging_utils.py b/venv/Lib/site-packages/firebase_admin/_messaging_utils.py new file mode 100644 index 000000000..d25ba5520 --- /dev/null +++ b/venv/Lib/site-packages/firebase_admin/_messaging_utils.py @@ -0,0 +1,494 @@ +# Copyright 2017 Google Inc. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +"""Types and utilities used by the messaging (FCM) module.""" + +from firebase_admin import exceptions + + +class Notification: + """A notification that can be included in a message. + + Args: + title: Title of the notification (optional). + body: Body of the notification (optional). + image: Image url of the notification (optional) + """ + + def __init__(self, title=None, body=None, image=None): + self.title = title + self.body = body + self.image = image + + +class AndroidConfig: + """Android-specific options that can be included in a message. + + Args: + collapse_key: Collapse key string for the message (optional). This is an identifier for a + group of messages that can be collapsed, so that only the last message is sent when + delivery can be resumed. A maximum of 4 different collapse keys may be active at a + given time. + priority: Priority of the message (optional). Must be one of ``high`` or ``normal``. + ttl: The time-to-live duration of the message (optional). This can be specified + as a numeric seconds value or a ``datetime.timedelta`` instance. + restricted_package_name: The package name of the application where the registration tokens + must match in order to receive the message (optional). + data: A dictionary of data fields (optional). All keys and values in the dictionary must be + strings. When specified, overrides any data fields set via ``Message.data``. + notification: A ``messaging.AndroidNotification`` to be included in the message (optional). + fcm_options: A ``messaging.AndroidFCMOptions`` to be included in the message (optional). + """ + + def __init__(self, collapse_key=None, priority=None, ttl=None, restricted_package_name=None, + data=None, notification=None, fcm_options=None): + self.collapse_key = collapse_key + self.priority = priority + self.ttl = ttl + self.restricted_package_name = restricted_package_name + self.data = data + self.notification = notification + self.fcm_options = fcm_options + + +class AndroidNotification: + """Android-specific notification parameters. + + Args: + title: Title of the notification (optional). If specified, overrides the title set via + ``messaging.Notification``. + body: Body of the notification (optional). If specified, overrides the body set via + ``messaging.Notification``. + icon: Icon of the notification (optional). + color: Color of the notification icon expressed in ``#rrggbb`` form (optional). + sound: Sound to be played when the device receives the notification (optional). This is + usually the file name of the sound resource. + tag: Tag of the notification (optional). This is an identifier used to replace existing + notifications in the notification drawer. If not specified, each request creates a new + notification. + click_action: The action associated with a user click on the notification (optional). If + specified, an activity with a matching intent filter is launched when a user clicks on + the notification. + body_loc_key: Key of the body string in the app's string resources to use to localize the + body text (optional). + body_loc_args: A list of resource keys that will be used in place of the format specifiers + in ``body_loc_key`` (optional). + title_loc_key: Key of the title string in the app's string resources to use to localize the + title text (optional). + title_loc_args: A list of resource keys that will be used in place of the format specifiers + in ``title_loc_key`` (optional). + channel_id: channel_id of the notification (optional). + image: Image url of the notification (optional). + ticker: Sets the ``ticker`` text, which is sent to accessibility services. Prior to API + level 21 (Lollipop), sets the text that is displayed in the status bar when the + notification first arrives (optional). + sticky: When set to ``False`` or unset, the notification is automatically dismissed when the + user clicks it in the panel. When set to ``True``, the notification persists even when + the user clicks it (optional). + event_timestamp: For notifications that inform users about events with an absolute time + reference, sets the time that the event in the notification occurred as a + ``datetime.datetime`` instance. If the ``datetime.datetime`` instance is naive, it + defaults to be in the UTC timezone. Notifications in the panel are sorted by this time + (optional). + local_only: Sets whether or not this notification is relevant only to the current device. + Some notifications can be bridged to other devices for remote display, such as a Wear OS + watch. This hint can be set to recommend this notification not be bridged (optional). + See Wear OS guides: + https://developer.android.com/training/wearables/notifications/bridger#existing-method-of-preventing-bridging + priority: Sets the relative priority for this notification. Low-priority notifications may + be hidden from the user in certain situations. Note this priority differs from + ``AndroidMessagePriority``. This priority is processed by the client after the message + has been delivered. Whereas ``AndroidMessagePriority`` is an FCM concept that controls + when the message is delivered (optional). Must be one of ``default``, ``min``, ``low``, + ``high``, ``max`` or ``normal``. + vibrate_timings_millis: Sets the vibration pattern to use. Pass in an array of milliseconds + to turn the vibrator on or off. The first value indicates the duration to wait before + turning the vibrator on. The next value indicates the duration to keep the vibrator on. + Subsequent values alternate between duration to turn the vibrator off and to turn the + vibrator on. If ``vibrate_timings`` is set and ``default_vibrate_timings`` is set to + ``True``, the default value is used instead of the user-specified ``vibrate_timings``. + default_vibrate_timings: If set to ``True``, use the Android framework's default vibrate + pattern for the notification (optional). Default values are specified in ``config.xml`` + https://android.googlesource.com/platform/frameworks/base/+/master/core/res/res/values/config.xml. + If ``default_vibrate_timings`` is set to ``True`` and ``vibrate_timings`` is also set, + the default value is used instead of the user-specified ``vibrate_timings``. + default_sound: If set to ``True``, use the Android framework's default sound for the + notification (optional). Default values are specified in ``config.xml`` + https://android.googlesource.com/platform/frameworks/base/+/master/core/res/res/values/config.xml + light_settings: Settings to control the notification's LED blinking rate and color if LED is + available on the device. The total blinking time is controlled by the OS (optional). + default_light_settings: If set to ``True``, use the Android framework's default LED light + settings for the notification. Default values are specified in ``config.xml`` + https://android.googlesource.com/platform/frameworks/base/+/master/core/res/res/values/config.xml. + If ``default_light_settings`` is set to ``True`` and ``light_settings`` is also set, the + user-specified ``light_settings`` is used instead of the default value. + visibility: Sets the visibility of the notification. Must be either ``private``, ``public``, + or ``secret``. If unspecified, default to ``private``. + notification_count: Sets the number of items this notification represents. May be displayed + as a badge count for Launchers that support badging. See ``NotificationBadge`` + https://developer.android.com/training/notify-user/badges. For example, this might be + useful if you're using just one notification to represent multiple new messages but you + want the count here to represent the number of total new messages. If zero or + unspecified, systems that support badging use the default, which is to increment a + number displayed on the long-press menu each time a new notification arrives. + + + """ + + def __init__(self, title=None, body=None, icon=None, color=None, sound=None, tag=None, + click_action=None, body_loc_key=None, body_loc_args=None, title_loc_key=None, + title_loc_args=None, channel_id=None, image=None, ticker=None, sticky=None, + event_timestamp=None, local_only=None, priority=None, vibrate_timings_millis=None, + default_vibrate_timings=None, default_sound=None, light_settings=None, + default_light_settings=None, visibility=None, notification_count=None): + self.title = title + self.body = body + self.icon = icon + self.color = color + self.sound = sound + self.tag = tag + self.click_action = click_action + self.body_loc_key = body_loc_key + self.body_loc_args = body_loc_args + self.title_loc_key = title_loc_key + self.title_loc_args = title_loc_args + self.channel_id = channel_id + self.image = image + self.ticker = ticker + self.sticky = sticky + self.event_timestamp = event_timestamp + self.local_only = local_only + self.priority = priority + self.vibrate_timings_millis = vibrate_timings_millis + self.default_vibrate_timings = default_vibrate_timings + self.default_sound = default_sound + self.light_settings = light_settings + self.default_light_settings = default_light_settings + self.visibility = visibility + self.notification_count = notification_count + + +class LightSettings: + """Represents settings to control notification LED that can be included in a + ``messaging.AndroidNotification``. + + Args: + color: Sets the color of the LED in ``#rrggbb`` or ``#rrggbbaa`` format. + light_on_duration_millis: Along with ``light_off_duration``, defines the blink rate of LED + flashes. + light_off_duration_millis: Along with ``light_on_duration``, defines the blink rate of LED + flashes. + """ + def __init__(self, color, light_on_duration_millis, + light_off_duration_millis): + self.color = color + self.light_on_duration_millis = light_on_duration_millis + self.light_off_duration_millis = light_off_duration_millis + + +class AndroidFCMOptions: + """Options for features provided by the FCM SDK for Android. + + Args: + analytics_label: contains additional options for features provided by the FCM Android SDK + (optional). + """ + + def __init__(self, analytics_label=None): + self.analytics_label = analytics_label + + +class WebpushConfig: + """Webpush-specific options that can be included in a message. + + Args: + headers: A dictionary of headers (optional). Refer `Webpush Specification`_ for supported + headers. + data: A dictionary of data fields (optional). All keys and values in the dictionary must be + strings. When specified, overrides any data fields set via ``Message.data``. + notification: A ``messaging.WebpushNotification`` to be included in the message (optional). + fcm_options: A ``messaging.WebpushFCMOptions`` instance to be included in the message + (optional). + + .. _Webpush Specification: https://tools.ietf.org/html/rfc8030#section-5 + """ + + def __init__(self, headers=None, data=None, notification=None, fcm_options=None): + self.headers = headers + self.data = data + self.notification = notification + self.fcm_options = fcm_options + + +class WebpushNotificationAction: + """An action available to the users when the notification is presented. + + Args: + action: Action string. + title: Title string. + icon: Icon URL for the action (optional). + """ + + def __init__(self, action, title, icon=None): + self.action = action + self.title = title + self.icon = icon + + +class WebpushNotification: + """Webpush-specific notification parameters. + + Refer to the `Notification Reference`_ for more information. + + Args: + title: Title of the notification (optional). If specified, overrides the title set via + ``messaging.Notification``. + body: Body of the notification (optional). If specified, overrides the body set via + ``messaging.Notification``. + icon: Icon URL of the notification (optional). + actions: A list of ``messaging.WebpushNotificationAction`` instances (optional). + badge: URL of the image used to represent the notification when there is + not enough space to display the notification itself (optional). + data: Any arbitrary JSON data that should be associated with the notification (optional). + direction: The direction in which to display the notification (optional). Must be either + 'auto', 'ltr' or 'rtl'. + image: The URL of an image to be displayed in the notification (optional). + language: Notification language (optional). + renotify: A boolean indicating whether the user should be notified after a new + notification replaces an old one (optional). + require_interaction: A boolean indicating whether a notification should remain active + until the user clicks or dismisses it, rather than closing automatically (optional). + silent: ``True`` to indicate that the notification should be silent (optional). + tag: An identifying tag on the notification (optional). + timestamp_millis: A timestamp value in milliseconds on the notification (optional). + vibrate: A vibration pattern for the device's vibration hardware to emit when the + notification fires (optional). The pattern is specified as an integer array. + custom_data: A dict of custom key-value pairs to be included in the notification + (optional) + + .. _Notification Reference: https://developer.mozilla.org/en-US/docs/Web/API\ + /notification/Notification + """ + + def __init__(self, title=None, body=None, icon=None, actions=None, badge=None, data=None, + direction=None, image=None, language=None, renotify=None, + require_interaction=None, silent=None, tag=None, timestamp_millis=None, + vibrate=None, custom_data=None): + self.title = title + self.body = body + self.icon = icon + self.actions = actions + self.badge = badge + self.data = data + self.direction = direction + self.image = image + self.language = language + self.renotify = renotify + self.require_interaction = require_interaction + self.silent = silent + self.tag = tag + self.timestamp_millis = timestamp_millis + self.vibrate = vibrate + self.custom_data = custom_data + + +class WebpushFCMOptions: + """Options for features provided by the FCM SDK for Web. + + Args: + link: The link to open when the user clicks on the notification. Must be an HTTPS URL + (optional). + """ + + def __init__(self, link=None): + self.link = link + + +class APNSConfig: + """APNS-specific options that can be included in a message. + + Refer to `APNS Documentation`_ for more information. + + Args: + headers: A dictionary of headers (optional). + payload: A ``messaging.APNSPayload`` to be included in the message (optional). + fcm_options: A ``messaging.APNSFCMOptions`` instance to be included in the message + (optional). + + .. _APNS Documentation: https://developer.apple.com/library/content/documentation\ + /NetworkingInternet/Conceptual/RemoteNotificationsPG/CommunicatingwithAPNs.html + """ + + def __init__(self, headers=None, payload=None, fcm_options=None): + self.headers = headers + self.payload = payload + self.fcm_options = fcm_options + + +class APNSPayload: + """Payload of an APNS message. + + Args: + aps: A ``messaging.Aps`` instance to be included in the payload. + kwargs: Arbitrary keyword arguments to be included as custom fields in the payload + (optional). + """ + + def __init__(self, aps, **kwargs): + self.aps = aps + self.custom_data = kwargs + + +class Aps: + """Aps dictionary to be included in an APNS payload. + + Args: + alert: A string or a ``messaging.ApsAlert`` instance (optional). + badge: A number representing the badge to be displayed with the message (optional). + sound: Name of the sound file to be played with the message or a + ``messaging.CriticalSound`` instance (optional). + content_available: A boolean indicating whether to configure a background update + notification (optional). + category: String identifier representing the message type (optional). + thread_id: An app-specific string identifier for grouping messages (optional). + mutable_content: A boolean indicating whether to support mutating notifications at + the client using app extensions (optional). + custom_data: A dict of custom key-value pairs to be included in the Aps dictionary + (optional). + """ + + def __init__(self, alert=None, badge=None, sound=None, content_available=None, category=None, + thread_id=None, mutable_content=None, custom_data=None): + self.alert = alert + self.badge = badge + self.sound = sound + self.content_available = content_available + self.category = category + self.thread_id = thread_id + self.mutable_content = mutable_content + self.custom_data = custom_data + + +class CriticalSound: + """Critical alert sound configuration that can be included in ``messaging.Aps``. + + Args: + name: The name of a sound file in your app's main bundle or in the ``Library/Sounds`` + folder of your app's container directory. Specify the string ``default`` to play the + system sound. + critical: Set to ``True`` to set the critical alert flag on the sound configuration + (optional). + volume: The volume for the critical alert's sound. Must be a value between 0.0 (silent) + and 1.0 (full volume) (optional). + """ + + def __init__(self, name, critical=None, volume=None): + self.name = name + self.critical = critical + self.volume = volume + + +class ApsAlert: + """An alert that can be included in ``messaging.Aps``. + + Args: + title: Title of the alert (optional). If specified, overrides the title set via + ``messaging.Notification``. + subtitle: Subtitle of the alert (optional). + body: Body of the alert (optional). If specified, overrides the body set via + ``messaging.Notification``. + loc_key: Key of the body string in the app's string resources to use to localize the + body text (optional). + loc_args: A list of resource keys that will be used in place of the format specifiers + in ``loc_key`` (optional). + title_loc_key: Key of the title string in the app's string resources to use to localize the + title text (optional). + title_loc_args: A list of resource keys that will be used in place of the format specifiers + in ``title_loc_key`` (optional). + action_loc_key: Key of the text in the app's string resources to use to localize the + action button text (optional). + launch_image: Image for the notification action (optional). + custom_data: A dict of custom key-value pairs to be included in the ApsAlert dictionary + (optional) + """ + + def __init__(self, title=None, subtitle=None, body=None, loc_key=None, loc_args=None, + title_loc_key=None, title_loc_args=None, action_loc_key=None, launch_image=None, + custom_data=None): + self.title = title + self.subtitle = subtitle + self.body = body + self.loc_key = loc_key + self.loc_args = loc_args + self.title_loc_key = title_loc_key + self.title_loc_args = title_loc_args + self.action_loc_key = action_loc_key + self.launch_image = launch_image + self.custom_data = custom_data + + +class APNSFCMOptions: + """Options for features provided by the FCM SDK for iOS. + + Args: + analytics_label: contains additional options for features provided by the FCM iOS SDK + (optional). + image: contains the URL of an image that is going to be displayed in a notification + (optional). + """ + + def __init__(self, analytics_label=None, image=None): + self.analytics_label = analytics_label + self.image = image + + +class FCMOptions: + """Options for features provided by SDK. + + Args: + analytics_label: contains additional options to use across all platforms (optional). + """ + + def __init__(self, analytics_label=None): + self.analytics_label = analytics_label + + +class ThirdPartyAuthError(exceptions.UnauthenticatedError): + """APNs certificate or web push auth key was invalid or missing.""" + + def __init__(self, message, cause=None, http_response=None): + exceptions.UnauthenticatedError.__init__(self, message, cause, http_response) + + +class QuotaExceededError(exceptions.ResourceExhaustedError): + """Sending limit exceeded for the message target.""" + + def __init__(self, message, cause=None, http_response=None): + exceptions.ResourceExhaustedError.__init__(self, message, cause, http_response) + + +class SenderIdMismatchError(exceptions.PermissionDeniedError): + """The authenticated sender ID is different from the sender ID for the registration token.""" + + def __init__(self, message, cause=None, http_response=None): + exceptions.PermissionDeniedError.__init__(self, message, cause, http_response) + + +class UnregisteredError(exceptions.NotFoundError): + """App instance was unregistered from FCM. + + This usually means that the token used is no longer valid and a new one must be used.""" + + def __init__(self, message, cause=None, http_response=None): + exceptions.NotFoundError.__init__(self, message, cause, http_response) diff --git a/venv/Lib/site-packages/firebase_admin/_rfc3339.py b/venv/Lib/site-packages/firebase_admin/_rfc3339.py new file mode 100644 index 000000000..2c720bdd1 --- /dev/null +++ b/venv/Lib/site-packages/firebase_admin/_rfc3339.py @@ -0,0 +1,87 @@ +# Copyright 2020 Google Inc. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +"""Parse RFC3339 date strings""" + +from datetime import datetime, timezone +import re + +def parse_to_epoch(datestr): + """Parse an RFC3339 date string and return the number of seconds since the + epoch (as a float). + + In particular, this method is meant to parse the strings returned by the + JSON mapping of protobuf google.protobuf.timestamp.Timestamp instances: + https://github.com/protocolbuffers/protobuf/blob/4cf5bfee9546101d98754d23ff378ff718ba8438/src/google/protobuf/timestamp.proto#L99 + + This method has microsecond precision; nanoseconds will be truncated. + + Args: + datestr: A string in RFC3339 format. + Returns: + Float: The number of seconds since the Unix epoch. + Raises: + ValueError: Raised if the `datestr` is not a valid RFC3339 date string. + """ + return _parse_to_datetime(datestr).timestamp() + + +def _parse_to_datetime(datestr): + """Parse an RFC3339 date string and return a python datetime instance. + + Args: + datestr: A string in RFC3339 format. + Returns: + datetime: The corresponding `datetime` (with timezone information). + Raises: + ValueError: Raised if the `datestr` is not a valid RFC3339 date string. + """ + # If more than 6 digits appear in the fractional seconds position, truncate + # to just the most significant 6. (i.e. we only have microsecond precision; + # nanos are truncated.) + datestr_modified = re.sub(r'(\.\d{6})\d*', r'\1', datestr) + + # This format is the one we actually expect to occur from our backend. The + # others are only present because the spec says we *should* accept them. + try: + return datetime.strptime( + datestr_modified, '%Y-%m-%dT%H:%M:%S.%fZ' + ).replace(tzinfo=timezone.utc) + except ValueError: + pass + + try: + return datetime.strptime( + datestr_modified, '%Y-%m-%dT%H:%M:%SZ' + ).replace(tzinfo=timezone.utc) + except ValueError: + pass + + # Note: %z parses timezone offsets, but requires the timezone offset *not* + # include a separating ':'. As of python 3.7, this was relaxed. + # TODO(rsgowman): Once python3.7 becomes our floor, we can drop the regex + # replacement. + datestr_modified = re.sub(r'(\d\d):(\d\d)$', r'\1\2', datestr_modified) + + try: + return datetime.strptime(datestr_modified, '%Y-%m-%dT%H:%M:%S.%f%z') + except ValueError: + pass + + try: + return datetime.strptime(datestr_modified, '%Y-%m-%dT%H:%M:%S%z') + except ValueError: + pass + + raise ValueError('time data {0} does not match RFC3339 format'.format(datestr)) diff --git a/venv/Lib/site-packages/firebase_admin/_sseclient.py b/venv/Lib/site-packages/firebase_admin/_sseclient.py new file mode 100644 index 000000000..6585dfc80 --- /dev/null +++ b/venv/Lib/site-packages/firebase_admin/_sseclient.py @@ -0,0 +1,208 @@ +# Copyright 2017 Google Inc. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +"""SSEClient module to stream realtime updates from the Firebase Database. + +Based on a similar implementation from Pyrebase. +""" + +import re +import time +import warnings + +from google.auth import transport +import requests + + +# Technically, we should support streams that mix line endings. This regex, +# however, assumes that a system will provide consistent line endings. +end_of_field = re.compile(r'\r\n\r\n|\r\r|\n\n') + + +class KeepAuthSession(transport.requests.AuthorizedSession): + """A session that does not drop authentication on redirects between domains.""" + + def __init__(self, credential): + super(KeepAuthSession, self).__init__(credential) + + def rebuild_auth(self, prepared_request, response): + pass + + +class _EventBuffer: + """A helper class for buffering and parsing raw SSE data.""" + + def __init__(self): + self._buffer = [] + self._tail = '' + + def append(self, char): + self._buffer.append(char) + self._tail += char + self._tail = self._tail[-4:] + + def truncate(self): + head, sep, _ = self.buffer_string.rpartition('\n') + rem = head + sep + self._buffer = list(rem) + self._tail = rem[-4:] + + @property + def is_end_of_field(self): + last_two_chars = self._tail[-2:] + return last_two_chars == '\n\n' or last_two_chars == '\r\r' or self._tail == '\r\n\r\n' + + @property + def buffer_string(self): + return ''.join(self._buffer) + + +class SSEClient: + """SSE client implementation.""" + + def __init__(self, url, session, retry=3000, **kwargs): + """Initializes the SSEClient. + + Args: + url: The remote url to connect to. + session: The requests session. + retry: The retry interval in milliseconds (optional). + **kwargs: Extra kwargs that will be sent to ``requests.get()`` (optional). + """ + self.url = url + self.session = session + self.retry = retry + self.requests_kwargs = kwargs + self.should_connect = True + self.last_id = None + self.buf = u'' # Keep data here as it streams in + + headers = self.requests_kwargs.get('headers', {}) + # The SSE spec requires making requests with Cache-Control: no-cache + headers['Cache-Control'] = 'no-cache' + # The 'Accept' header is not required, but explicit > implicit + headers['Accept'] = 'text/event-stream' + self.requests_kwargs['headers'] = headers + self._connect() + + def close(self): + """Closes the SSEClient instance.""" + self.should_connect = False + self.retry = 0 + self.resp.close() + + def _connect(self): + """Connects to the server using requests.""" + if self.should_connect: + if self.last_id: + self.requests_kwargs['headers']['Last-Event-ID'] = self.last_id + self.resp = self.session.get(self.url, stream=True, **self.requests_kwargs) + self.resp_iterator = self.resp.iter_content(decode_unicode=True) + self.resp.raise_for_status() + else: + raise StopIteration() + + def __iter__(self): + return self + + def __next__(self): + if not re.search(end_of_field, self.buf): + temp_buffer = _EventBuffer() + while not temp_buffer.is_end_of_field: + try: + nextchar = next(self.resp_iterator) + temp_buffer.append(nextchar) + except (StopIteration, requests.RequestException): + time.sleep(self.retry / 1000.0) + self._connect() + # The SSE spec only supports resuming from a whole message, so + # if we have half a message we should throw it out. + temp_buffer.truncate() + continue + self.buf = temp_buffer.buffer_string + + split = re.split(end_of_field, self.buf) + head = split[0] + self.buf = '\n\n'.join(split[1:]) + event = Event.parse(head) + + if event.data == 'credential is no longer valid': + self._connect() + return None + if event.data == 'null': + return None + + # If the server requests a specific retry delay, we need to honor it. + if event.retry: + self.retry = event.retry + + # last_id should only be set if included in the message. It's not + # forgotten if a message omits it. + if event.event_id: + self.last_id = event.event_id + return event + + def next(self): + return self.__next__() + + +class Event: + """Event represents the events fired by SSE.""" + + sse_line_pattern = re.compile('(?P[^:]*):?( ?(?P.*))?') + + def __init__(self, data='', event_type='message', event_id=None, retry=None): + self.data = data + self.event_type = event_type + self.event_id = event_id + self.retry = retry + + @classmethod + def parse(cls, raw): + """Given a possibly-multiline string representing an SSE message, parses it + and returns an Event object. + + Args: + raw: the raw data to parse. + + Returns: + Event: A new ``Event`` with the parameters initialized. + """ + event = cls() + for line in raw.split('\n'): + match = cls.sse_line_pattern.match(line) + if match is None: + # Malformed line. Discard but warn. + warnings.warn('Invalid SSE line: "%s"' % line, SyntaxWarning) + continue + + name = match.groupdict()['name'] + value = match.groupdict()['value'] + if name == '': + # line began with a ":", so is a comment. Ignore + continue + if name == 'data': + # If we already have some data, then join to it with a newline. + # Else this is it. + if event.data: + event.data = '%s\n%s' % (event.data, value) + else: + event.data = value + elif name == 'event': + event.event_type = value + elif name == 'id': + event.event_id = value + elif name == 'retry': + event.retry = int(value) + return event diff --git a/venv/Lib/site-packages/firebase_admin/_token_gen.py b/venv/Lib/site-packages/firebase_admin/_token_gen.py new file mode 100644 index 000000000..18a8008c7 --- /dev/null +++ b/venv/Lib/site-packages/firebase_admin/_token_gen.py @@ -0,0 +1,401 @@ +# Copyright 2018 Google Inc. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +"""Firebase token minting and validation sub module.""" + +import datetime +import time + +import cachecontrol +import requests +from google.auth import credentials +from google.auth import iam +from google.auth import jwt +from google.auth import transport +import google.auth.exceptions +import google.oauth2.id_token +import google.oauth2.service_account + +from firebase_admin import exceptions +from firebase_admin import _auth_utils + + +# ID token constants +ID_TOKEN_ISSUER_PREFIX = 'https://securetoken.google.com/' +ID_TOKEN_CERT_URI = ('https://www.googleapis.com/robot/v1/metadata/x509/' + 'securetoken@system.gserviceaccount.com') + +# Session cookie constants +COOKIE_ISSUER_PREFIX = 'https://session.firebase.google.com/' +COOKIE_CERT_URI = 'https://www.googleapis.com/identitytoolkit/v3/relyingparty/publicKeys' +MIN_SESSION_COOKIE_DURATION_SECONDS = int(datetime.timedelta(minutes=5).total_seconds()) +MAX_SESSION_COOKIE_DURATION_SECONDS = int(datetime.timedelta(days=14).total_seconds()) + +# Custom token constants +MAX_TOKEN_LIFETIME_SECONDS = int(datetime.timedelta(hours=1).total_seconds()) +FIREBASE_AUDIENCE = ('https://identitytoolkit.googleapis.com/google.' + 'identity.identitytoolkit.v1.IdentityToolkit') +RESERVED_CLAIMS = set([ + 'acr', 'amr', 'at_hash', 'aud', 'auth_time', 'azp', 'cnf', 'c_hash', + 'exp', 'firebase', 'iat', 'iss', 'jti', 'nbf', 'nonce', 'sub' +]) +METADATA_SERVICE_URL = ('http://metadata.google.internal/computeMetadata/v1/instance/' + 'service-accounts/default/email') + + +class _SigningProvider: + """Stores a reference to a google.auth.crypto.Signer.""" + + def __init__(self, signer, signer_email): + self._signer = signer + self._signer_email = signer_email + + @property + def signer(self): + return self._signer + + @property + def signer_email(self): + return self._signer_email + + @classmethod + def from_credential(cls, google_cred): + return _SigningProvider(google_cred.signer, google_cred.signer_email) + + @classmethod + def from_iam(cls, request, google_cred, service_account): + signer = iam.Signer(request, google_cred, service_account) + return _SigningProvider(signer, service_account) + + +class TokenGenerator: + """Generates custom tokens and session cookies.""" + + ID_TOOLKIT_URL = 'https://identitytoolkit.googleapis.com/v1' + + def __init__(self, app, http_client): + self.app = app + self.http_client = http_client + self.request = transport.requests.Request() + self.base_url = '{0}/projects/{1}'.format(self.ID_TOOLKIT_URL, app.project_id) + self._signing_provider = None + + def _init_signing_provider(self): + """Initializes a signing provider by following the go/firebase-admin-sign protocol.""" + # If the SDK was initialized with a service account, use it to sign bytes. + google_cred = self.app.credential.get_credential() + if isinstance(google_cred, google.oauth2.service_account.Credentials): + return _SigningProvider.from_credential(google_cred) + + # If the SDK was initialized with a service account email, use it with the IAM service + # to sign bytes. + service_account = self.app.options.get('serviceAccountId') + if service_account: + return _SigningProvider.from_iam(self.request, google_cred, service_account) + + # If the SDK was initialized with some other credential type that supports signing + # (e.g. GAE credentials), use it to sign bytes. + if isinstance(google_cred, credentials.Signing): + return _SigningProvider.from_credential(google_cred) + + # Attempt to discover a service account email from the local Metadata service. Use it + # with the IAM service to sign bytes. + resp = self.request(url=METADATA_SERVICE_URL, headers={'Metadata-Flavor': 'Google'}) + if resp.status != 200: + raise ValueError( + 'Failed to contact the local metadata service: {0}.'.format(resp.data.decode())) + service_account = resp.data.decode() + return _SigningProvider.from_iam(self.request, google_cred, service_account) + + @property + def signing_provider(self): + """Initializes and returns the SigningProvider instance to be used.""" + if not self._signing_provider: + try: + self._signing_provider = self._init_signing_provider() + except Exception as error: + url = 'https://firebase.google.com/docs/auth/admin/create-custom-tokens' + raise ValueError( + 'Failed to determine service account: {0}. Make sure to initialize the SDK ' + 'with service account credentials or specify a service account ID with ' + 'iam.serviceAccounts.signBlob permission. Please refer to {1} for more ' + 'details on creating custom tokens.'.format(error, url)) + return self._signing_provider + + def create_custom_token(self, uid, developer_claims=None, tenant_id=None): + """Builds and signs a Firebase custom auth token.""" + if developer_claims is not None: + if not isinstance(developer_claims, dict): + raise ValueError('developer_claims must be a dictionary') + + disallowed_keys = set(developer_claims.keys()) & RESERVED_CLAIMS + if disallowed_keys: + if len(disallowed_keys) > 1: + error_message = ('Developer claims {0} are reserved and ' + 'cannot be specified.'.format( + ', '.join(disallowed_keys))) + else: + error_message = ('Developer claim {0} is reserved and ' + 'cannot be specified.'.format( + ', '.join(disallowed_keys))) + raise ValueError(error_message) + + if not uid or not isinstance(uid, str) or len(uid) > 128: + raise ValueError('uid must be a string between 1 and 128 characters.') + + signing_provider = self.signing_provider + now = int(time.time()) + payload = { + 'iss': signing_provider.signer_email, + 'sub': signing_provider.signer_email, + 'aud': FIREBASE_AUDIENCE, + 'uid': uid, + 'iat': now, + 'exp': now + MAX_TOKEN_LIFETIME_SECONDS, + } + if tenant_id: + payload['tenant_id'] = tenant_id + + if developer_claims is not None: + payload['claims'] = developer_claims + try: + return jwt.encode(signing_provider.signer, payload) + except google.auth.exceptions.TransportError as error: + msg = 'Failed to sign custom token. {0}'.format(error) + raise TokenSignError(msg, error) + + + def create_session_cookie(self, id_token, expires_in): + """Creates a session cookie from the provided ID token.""" + id_token = id_token.decode('utf-8') if isinstance(id_token, bytes) else id_token + if not isinstance(id_token, str) or not id_token: + raise ValueError( + 'Illegal ID token provided: {0}. ID token must be a non-empty ' + 'string.'.format(id_token)) + + if isinstance(expires_in, datetime.timedelta): + expires_in = int(expires_in.total_seconds()) + if isinstance(expires_in, bool) or not isinstance(expires_in, int): + raise ValueError('Illegal expiry duration: {0}.'.format(expires_in)) + if expires_in < MIN_SESSION_COOKIE_DURATION_SECONDS: + raise ValueError('Illegal expiry duration: {0}. Duration must be at least {1} ' + 'seconds.'.format(expires_in, MIN_SESSION_COOKIE_DURATION_SECONDS)) + if expires_in > MAX_SESSION_COOKIE_DURATION_SECONDS: + raise ValueError('Illegal expiry duration: {0}. Duration must be at most {1} ' + 'seconds.'.format(expires_in, MAX_SESSION_COOKIE_DURATION_SECONDS)) + + url = '{0}:createSessionCookie'.format(self.base_url) + payload = { + 'idToken': id_token, + 'validDuration': expires_in, + } + try: + body, http_resp = self.http_client.body_and_response('post', url, json=payload) + except requests.exceptions.RequestException as error: + raise _auth_utils.handle_auth_backend_error(error) + else: + if not body or not body.get('sessionCookie'): + raise _auth_utils.UnexpectedResponseError( + 'Failed to create session cookie.', http_response=http_resp) + return body.get('sessionCookie') + + +class TokenVerifier: + """Verifies ID tokens and session cookies.""" + + def __init__(self, app): + session = cachecontrol.CacheControl(requests.Session()) + self.request = transport.requests.Request(session=session) + self.id_token_verifier = _JWTVerifier( + project_id=app.project_id, short_name='ID token', + operation='verify_id_token()', + doc_url='https://firebase.google.com/docs/auth/admin/verify-id-tokens', + cert_url=ID_TOKEN_CERT_URI, + issuer=ID_TOKEN_ISSUER_PREFIX, + invalid_token_error=_auth_utils.InvalidIdTokenError, + expired_token_error=ExpiredIdTokenError) + self.cookie_verifier = _JWTVerifier( + project_id=app.project_id, short_name='session cookie', + operation='verify_session_cookie()', + doc_url='https://firebase.google.com/docs/auth/admin/verify-id-tokens', + cert_url=COOKIE_CERT_URI, + issuer=COOKIE_ISSUER_PREFIX, + invalid_token_error=InvalidSessionCookieError, + expired_token_error=ExpiredSessionCookieError) + + def verify_id_token(self, id_token): + return self.id_token_verifier.verify(id_token, self.request) + + def verify_session_cookie(self, cookie): + return self.cookie_verifier.verify(cookie, self.request) + + +class _JWTVerifier: + """Verifies Firebase JWTs (ID tokens or session cookies).""" + + def __init__(self, **kwargs): + self.project_id = kwargs.pop('project_id') + self.short_name = kwargs.pop('short_name') + self.operation = kwargs.pop('operation') + self.url = kwargs.pop('doc_url') + self.cert_url = kwargs.pop('cert_url') + self.issuer = kwargs.pop('issuer') + if self.short_name[0].lower() in 'aeiou': + self.articled_short_name = 'an {0}'.format(self.short_name) + else: + self.articled_short_name = 'a {0}'.format(self.short_name) + self._invalid_token_error = kwargs.pop('invalid_token_error') + self._expired_token_error = kwargs.pop('expired_token_error') + + def verify(self, token, request): + """Verifies the signature and data for the provided JWT.""" + token = token.encode('utf-8') if isinstance(token, str) else token + if not isinstance(token, bytes) or not token: + raise ValueError( + 'Illegal {0} provided: {1}. {0} must be a non-empty ' + 'string.'.format(self.short_name, token)) + + if not self.project_id: + raise ValueError( + 'Failed to ascertain project ID from the credential or the environment. Project ' + 'ID is required to call {0}. Initialize the app with a credentials.Certificate ' + 'or set your Firebase project ID as an app option. Alternatively set the ' + 'GOOGLE_CLOUD_PROJECT environment variable.'.format(self.operation)) + + header, payload = self._decode_unverified(token) + issuer = payload.get('iss') + audience = payload.get('aud') + subject = payload.get('sub') + expected_issuer = self.issuer + self.project_id + + project_id_match_msg = ( + 'Make sure the {0} comes from the same Firebase project as the service account used ' + 'to authenticate this SDK.'.format(self.short_name)) + verify_id_token_msg = ( + 'See {0} for details on how to retrieve {1}.'.format(self.url, self.short_name)) + + error_message = None + if audience == FIREBASE_AUDIENCE: + error_message = ( + '{0} expects {1}, but was given a custom ' + 'token.'.format(self.operation, self.articled_short_name)) + elif not header.get('kid'): + if header.get('alg') == 'HS256' and payload.get( + 'v') == 0 and 'uid' in payload.get('d', {}): + error_message = ( + '{0} expects {1}, but was given a legacy custom ' + 'token.'.format(self.operation, self.articled_short_name)) + else: + error_message = 'Firebase {0} has no "kid" claim.'.format(self.short_name) + elif header.get('alg') != 'RS256': + error_message = ( + 'Firebase {0} has incorrect algorithm. Expected "RS256" but got ' + '"{1}". {2}'.format(self.short_name, header.get('alg'), verify_id_token_msg)) + elif audience != self.project_id: + error_message = ( + 'Firebase {0} has incorrect "aud" (audience) claim. Expected "{1}" but ' + 'got "{2}". {3} {4}'.format(self.short_name, self.project_id, audience, + project_id_match_msg, verify_id_token_msg)) + elif issuer != expected_issuer: + error_message = ( + 'Firebase {0} has incorrect "iss" (issuer) claim. Expected "{1}" but ' + 'got "{2}". {3} {4}'.format(self.short_name, expected_issuer, issuer, + project_id_match_msg, verify_id_token_msg)) + elif subject is None or not isinstance(subject, str): + error_message = ( + 'Firebase {0} has no "sub" (subject) claim. ' + '{1}'.format(self.short_name, verify_id_token_msg)) + elif not subject: + error_message = ( + 'Firebase {0} has an empty string "sub" (subject) claim. ' + '{1}'.format(self.short_name, verify_id_token_msg)) + elif len(subject) > 128: + error_message = ( + 'Firebase {0} has a "sub" (subject) claim longer than 128 characters. ' + '{1}'.format(self.short_name, verify_id_token_msg)) + + if error_message: + raise self._invalid_token_error(error_message) + + try: + verified_claims = google.oauth2.id_token.verify_token( + token, + request=request, + audience=self.project_id, + certs_url=self.cert_url) + verified_claims['uid'] = verified_claims['sub'] + return verified_claims + except google.auth.exceptions.TransportError as error: + raise CertificateFetchError(str(error), cause=error) + except ValueError as error: + if 'Token expired' in str(error): + raise self._expired_token_error(str(error), cause=error) + raise self._invalid_token_error(str(error), cause=error) + + def _decode_unverified(self, token): + try: + header = jwt.decode_header(token) + payload = jwt.decode(token, verify=False) + return header, payload + except ValueError as error: + raise self._invalid_token_error(str(error), cause=error) + + +class TokenSignError(exceptions.UnknownError): + """Unexpected error while signing a Firebase custom token.""" + + def __init__(self, message, cause): + exceptions.UnknownError.__init__(self, message, cause) + + +class CertificateFetchError(exceptions.UnknownError): + """Failed to fetch some public key certificates required to verify a token.""" + + def __init__(self, message, cause): + exceptions.UnknownError.__init__(self, message, cause) + + +class ExpiredIdTokenError(_auth_utils.InvalidIdTokenError): + """The provided ID token is expired.""" + + def __init__(self, message, cause): + _auth_utils.InvalidIdTokenError.__init__(self, message, cause) + + +class RevokedIdTokenError(_auth_utils.InvalidIdTokenError): + """The provided ID token has been revoked.""" + + def __init__(self, message): + _auth_utils.InvalidIdTokenError.__init__(self, message) + + +class InvalidSessionCookieError(exceptions.InvalidArgumentError): + """The provided string is not a valid Firebase session cookie.""" + + def __init__(self, message, cause=None): + exceptions.InvalidArgumentError.__init__(self, message, cause) + + +class ExpiredSessionCookieError(InvalidSessionCookieError): + """The provided session cookie is expired.""" + + def __init__(self, message, cause): + InvalidSessionCookieError.__init__(self, message, cause) + + +class RevokedSessionCookieError(InvalidSessionCookieError): + """The provided session cookie has been revoked.""" + + def __init__(self, message): + InvalidSessionCookieError.__init__(self, message) diff --git a/venv/Lib/site-packages/firebase_admin/_user_identifier.py b/venv/Lib/site-packages/firebase_admin/_user_identifier.py new file mode 100644 index 000000000..85a224e0b --- /dev/null +++ b/venv/Lib/site-packages/firebase_admin/_user_identifier.py @@ -0,0 +1,103 @@ +# Copyright 2020 Google Inc. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +"""Classes to uniquely identify a user.""" + +from firebase_admin import _auth_utils + +class UserIdentifier: + """Identifies a user to be looked up.""" + + +class UidIdentifier(UserIdentifier): + """Used for looking up an account by uid. + + See ``auth.get_user()``. + """ + + def __init__(self, uid): + """Constructs a new `UidIdentifier` object. + + Args: + uid: A user ID string. + """ + self._uid = _auth_utils.validate_uid(uid, required=True) + + @property + def uid(self): + return self._uid + + +class EmailIdentifier(UserIdentifier): + """Used for looking up an account by email. + + See ``auth.get_user()``. + """ + + def __init__(self, email): + """Constructs a new `EmailIdentifier` object. + + Args: + email: A user email address string. + """ + self._email = _auth_utils.validate_email(email, required=True) + + @property + def email(self): + return self._email + + +class PhoneIdentifier(UserIdentifier): + """Used for looking up an account by phone number. + + See ``auth.get_user()``. + """ + + def __init__(self, phone_number): + """Constructs a new `PhoneIdentifier` object. + + Args: + phone_number: A phone number string. + """ + self._phone_number = _auth_utils.validate_phone(phone_number, required=True) + + @property + def phone_number(self): + return self._phone_number + + +class ProviderIdentifier(UserIdentifier): + """Used for looking up an account by provider. + + See ``auth.get_user()``. + """ + + def __init__(self, provider_id, provider_uid): + """Constructs a new `ProviderIdentifier` object. + +   Args: +     provider_id: A provider ID string. +     provider_uid: A provider UID string. + """ + self._provider_id = _auth_utils.validate_provider_id(provider_id, required=True) + self._provider_uid = _auth_utils.validate_provider_uid( + provider_uid, required=True) + + @property + def provider_id(self): + return self._provider_id + + @property + def provider_uid(self): + return self._provider_uid diff --git a/venv/Lib/site-packages/firebase_admin/_user_import.py b/venv/Lib/site-packages/firebase_admin/_user_import.py new file mode 100644 index 000000000..7834b232a --- /dev/null +++ b/venv/Lib/site-packages/firebase_admin/_user_import.py @@ -0,0 +1,520 @@ +# Copyright 2018 Google Inc. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +"""Firebase user import sub module.""" + +import base64 +import json + +from firebase_admin import _auth_utils + + +def b64_encode(bytes_value): + return base64.urlsafe_b64encode(bytes_value).decode() + + +class UserProvider: + """Represents a user identity provider that can be associated with a Firebase user. + + One or more providers can be specified in an ``ImportUserRecord`` when importing users via + ``auth.import_users()``. + + Args: + uid: User's unique ID assigned by the identity provider. + provider_id: ID of the identity provider. This can be a short domain name or the identifier + of an OpenID identity provider. + email: User's email address (optional). + display_name: User's display name (optional). + photo_url: User's photo URL (optional). + """ + + def __init__(self, uid, provider_id, email=None, display_name=None, photo_url=None): + self.uid = uid + self.provider_id = provider_id + self.email = email + self.display_name = display_name + self.photo_url = photo_url + + @property + def uid(self): + return self._uid + + @uid.setter + def uid(self, uid): + self._uid = _auth_utils.validate_uid(uid, required=True) + + @property + def provider_id(self): + return self._provider_id + + @provider_id.setter + def provider_id(self, provider_id): + self._provider_id = _auth_utils.validate_provider_id(provider_id, required=True) + + @property + def email(self): + return self._email + + @email.setter + def email(self, email): + self._email = _auth_utils.validate_email(email) + + @property + def display_name(self): + return self._display_name + + @display_name.setter + def display_name(self, display_name): + self._display_name = _auth_utils.validate_display_name(display_name) + + @property + def photo_url(self): + return self._photo_url + + @photo_url.setter + def photo_url(self, photo_url): + self._photo_url = _auth_utils.validate_photo_url(photo_url) + + def to_dict(self): + payload = { + 'rawId': self.uid, + 'providerId': self.provider_id, + 'displayName': self.display_name, + 'email': self.email, + 'photoUrl': self.photo_url, + } + return {k: v for k, v in payload.items() if v is not None} + + +class ImportUserRecord: + """Represents a user account to be imported to Firebase Auth. + + Must specify the ``uid`` field at a minimum. A sequence of ``ImportUserRecord`` objects can be + passed to the ``auth.import_users()`` function, in order to import those users into Firebase + Auth in bulk. If the ``password_hash`` is set on a user, a hash configuration must be + specified when calling ``import_users()``. + + Args: + uid: User's unique ID. Must be a non-empty string not longer than 128 characters. + email: User's email address (optional). + email_verified: A boolean indicating whether the user's email has been verified (optional). + display_name: User's display name (optional). + phone_number: User's phone number (optional). + photo_url: User's photo URL (optional). + disabled: A boolean indicating whether this user account has been disabled (optional). + user_metadata: An ``auth.UserMetadata`` instance with additional user metadata (optional). + provider_data: A list of ``auth.UserProvider`` instances (optional). + custom_claims: A ``dict`` of custom claims to be set on the user account (optional). + password_hash: User's password hash as a ``bytes`` sequence (optional). + password_salt: User's password salt as a ``bytes`` sequence (optional). + + Raises: + ValueError: If provided arguments are invalid. + """ + + def __init__(self, uid, email=None, email_verified=None, display_name=None, phone_number=None, + photo_url=None, disabled=None, user_metadata=None, provider_data=None, + custom_claims=None, password_hash=None, password_salt=None): + self.uid = uid + self.email = email + self.display_name = display_name + self.phone_number = phone_number + self.photo_url = photo_url + self.password_hash = password_hash + self.password_salt = password_salt + self.email_verified = email_verified + self.disabled = disabled + self.user_metadata = user_metadata + self.provider_data = provider_data + self.custom_claims = custom_claims + + @property + def uid(self): + return self._uid + + @uid.setter + def uid(self, uid): + self._uid = _auth_utils.validate_uid(uid, required=True) + + @property + def email(self): + return self._email + + @email.setter + def email(self, email): + self._email = _auth_utils.validate_email(email) + + @property + def display_name(self): + return self._display_name + + @display_name.setter + def display_name(self, display_name): + self._display_name = _auth_utils.validate_display_name(display_name) + + @property + def phone_number(self): + return self._phone_number + + @phone_number.setter + def phone_number(self, phone_number): + self._phone_number = _auth_utils.validate_phone(phone_number) + + @property + def photo_url(self): + return self._photo_url + + @photo_url.setter + def photo_url(self, photo_url): + self._photo_url = _auth_utils.validate_photo_url(photo_url) + + @property + def password_hash(self): + return self._password_hash + + @password_hash.setter + def password_hash(self, password_hash): + self._password_hash = _auth_utils.validate_bytes(password_hash, 'password_hash') + + @property + def password_salt(self): + return self._password_salt + + @password_salt.setter + def password_salt(self, password_salt): + self._password_salt = _auth_utils.validate_bytes(password_salt, 'password_salt') + + @property + def user_metadata(self): + return self._user_metadata + + @user_metadata.setter + def user_metadata(self, user_metadata): + created_at = user_metadata.creation_timestamp if user_metadata is not None else None + last_login_at = user_metadata.last_sign_in_timestamp if user_metadata is not None else None + self._created_at = _auth_utils.validate_timestamp(created_at, 'creation_timestamp') + self._last_login_at = _auth_utils.validate_timestamp( + last_login_at, 'last_sign_in_timestamp') + self._user_metadata = user_metadata + + @property + def provider_data(self): + return self._provider_data + + @provider_data.setter + def provider_data(self, provider_data): + if provider_data is not None: + try: + if any([not isinstance(p, UserProvider) for p in provider_data]): + raise ValueError('One or more provider data instances are invalid.') + except TypeError: + raise ValueError('provider_data must be iterable.') + self._provider_data = provider_data + + @property + def custom_claims(self): + return self._custom_claims + + @custom_claims.setter + def custom_claims(self, custom_claims): + json_claims = json.dumps(custom_claims) if isinstance( + custom_claims, dict) else custom_claims + self._custom_claims_str = _auth_utils.validate_custom_claims(json_claims) + self._custom_claims = custom_claims + + def to_dict(self): + """Returns a dict representation of the user. For internal use only.""" + payload = { + 'localId': self.uid, + 'email': self.email, + 'displayName': self.display_name, + 'phoneNumber': self.phone_number, + 'photoUrl': self.photo_url, + 'emailVerified': (bool(self.email_verified) + if self.email_verified is not None else None), + 'disabled': bool(self.disabled) if self.disabled is not None else None, + 'customAttributes': self._custom_claims_str, + 'createdAt': self._created_at, + 'lastLoginAt': self._last_login_at, + 'passwordHash': b64_encode(self.password_hash) if self.password_hash else None, + 'salt': b64_encode(self.password_salt) if self.password_salt else None, + } + if self.provider_data: + payload['providerUserInfo'] = [p.to_dict() for p in self.provider_data] + return {k: v for k, v in payload.items() if v is not None} + + +class UserImportHash: + """Represents a hash algorithm used to hash user passwords. + + An instance of this class must be specified when importing users with passwords via the + ``auth.import_users()`` API. Use one of the provided class methods to obtain new + instances when required. Refer to `documentation`_ for more details. + + .. _documentation: https://firebase.google.com/docs/auth/admin/import-users + """ + + def __init__(self, name, data=None): + self._name = name + self._data = data + + def to_dict(self): + payload = {'hashAlgorithm': self._name} + if self._data: + payload.update(self._data) + return payload + + @classmethod + def _hmac(cls, name, key): + data = { + 'signerKey': b64_encode(_auth_utils.validate_bytes(key, 'key', required=True)) + } + return UserImportHash(name, data) + + @classmethod + def hmac_sha512(cls, key): + """Creates a new HMAC SHA512 algorithm instance. + + Args: + key: Signer key as a byte sequence. + + Returns: + UserImportHash: A new ``UserImportHash``. + """ + return cls._hmac('HMAC_SHA512', key) + + @classmethod + def hmac_sha256(cls, key): + """Creates a new HMAC SHA256 algorithm instance. + + Args: + key: Signer key as a byte sequence. + + Returns: + UserImportHash: A new ``UserImportHash``. + """ + return cls._hmac('HMAC_SHA256', key) + + @classmethod + def hmac_sha1(cls, key): + """Creates a new HMAC SHA1 algorithm instance. + + Args: + key: Signer key as a byte sequence. + + Returns: + UserImportHash: A new ``UserImportHash``. + """ + return cls._hmac('HMAC_SHA1', key) + + @classmethod + def hmac_md5(cls, key): + """Creates a new HMAC MD5 algorithm instance. + + Args: + key: Signer key as a byte sequence. + + Returns: + UserImportHash: A new ``UserImportHash``. + """ + return cls._hmac('HMAC_MD5', key) + + @classmethod + def md5(cls, rounds): + """Creates a new MD5 algorithm instance. + + Args: + rounds: Number of rounds. Must be an integer between 0 and 8192. + + Returns: + UserImportHash: A new ``UserImportHash``. + """ + return UserImportHash( + 'MD5', + {'rounds': _auth_utils.validate_int(rounds, 'rounds', 0, 8192)}) + + @classmethod + def sha1(cls, rounds): + """Creates a new SHA1 algorithm instance. + + Args: + rounds: Number of rounds. Must be an integer between 1 and 8192. + + Returns: + UserImportHash: A new ``UserImportHash``. + """ + return UserImportHash( + 'SHA1', + {'rounds': _auth_utils.validate_int(rounds, 'rounds', 1, 8192)}) + + @classmethod + def sha256(cls, rounds): + """Creates a new SHA256 algorithm instance. + + Args: + rounds: Number of rounds. Must be an integer between 1 and 8192. + + Returns: + UserImportHash: A new ``UserImportHash``. + """ + return UserImportHash( + 'SHA256', + {'rounds': _auth_utils.validate_int(rounds, 'rounds', 1, 8192)}) + + @classmethod + def sha512(cls, rounds): + """Creates a new SHA512 algorithm instance. + + Args: + rounds: Number of rounds. Must be an integer between 1 and 8192. + + Returns: + UserImportHash: A new ``UserImportHash``. + """ + return UserImportHash( + 'SHA512', + {'rounds': _auth_utils.validate_int(rounds, 'rounds', 1, 8192)}) + + @classmethod + def pbkdf_sha1(cls, rounds): + """Creates a new PBKDF SHA1 algorithm instance. + + Args: + rounds: Number of rounds. Must be an integer between 0 and 120000. + + Returns: + UserImportHash: A new ``UserImportHash``. + """ + return UserImportHash( + 'PBKDF_SHA1', + {'rounds': _auth_utils.validate_int(rounds, 'rounds', 0, 120000)}) + + @classmethod + def pbkdf2_sha256(cls, rounds): + """Creates a new PBKDF2 SHA256 algorithm instance. + + Args: + rounds: Number of rounds. Must be an integer between 0 and 120000. + + Returns: + UserImportHash: A new ``UserImportHash``. + """ + return UserImportHash( + 'PBKDF2_SHA256', + {'rounds': _auth_utils.validate_int(rounds, 'rounds', 0, 120000)}) + + @classmethod + def scrypt(cls, key, rounds, memory_cost, salt_separator=None): + """Creates a new Scrypt algorithm instance. + + This is the modified Scrypt algorithm used by Firebase Auth. See ``standard_scrypt()`` + function for the standard Scrypt algorith, + + Args: + key: Signer key as a byte sequence. + rounds: Number of rounds. Must be an integer between 1 and 8. + memory_cost: Memory cost as an integer between 1 and 14. + salt_separator: Salt separator as a byte sequence (optional). + + Returns: + UserImportHash: A new ``UserImportHash``. + """ + data = { + 'signerKey': b64_encode(_auth_utils.validate_bytes(key, 'key', required=True)), + 'rounds': _auth_utils.validate_int(rounds, 'rounds', 1, 8), + 'memoryCost': _auth_utils.validate_int(memory_cost, 'memory_cost', 1, 14), + } + if salt_separator: + data['saltSeparator'] = b64_encode(_auth_utils.validate_bytes( + salt_separator, 'salt_separator')) + return UserImportHash('SCRYPT', data) + + @classmethod + def bcrypt(cls): + """Creates a new Bcrypt algorithm instance. + + Returns: + UserImportHash: A new ``UserImportHash``. + """ + return UserImportHash('BCRYPT') + + @classmethod + def standard_scrypt(cls, memory_cost, parallelization, block_size, derived_key_length): + """Creates a new standard Scrypt algorithm instance. + + Args: + memory_cost: Memory cost as a non-negaive integer. + parallelization: Parallelization as a non-negative integer. + block_size: Block size as a non-negative integer. + derived_key_length: Derived key length as a non-negative integer. + + Returns: + UserImportHash: A new ``UserImportHash``. + """ + data = { + 'memoryCost': _auth_utils.validate_int(memory_cost, 'memory_cost', low=0), + 'parallelization': _auth_utils.validate_int(parallelization, 'parallelization', low=0), + 'blockSize': _auth_utils.validate_int(block_size, 'block_size', low=0), + 'dkLen': _auth_utils.validate_int(derived_key_length, 'derived_key_length', low=0), + } + return UserImportHash('STANDARD_SCRYPT', data) + + +class ErrorInfo: + """Represents an error encountered while performing a batch operation such + as importing users or deleting multiple user accounts. + """ + # TODO(rsgowman): This class used to be specific to importing users (hence + # it's home in _user_import.py). It's now also used by bulk deletion of + # users. Move this to a more common location. + + def __init__(self, error): + self._index = error['index'] + self._reason = error['message'] + + @property + def index(self): + return self._index + + @property + def reason(self): + return self._reason + + +class UserImportResult: + """Represents the result of a bulk user import operation. + + See ``auth.import_users()`` API for more details. + """ + + def __init__(self, result, total): + errors = result.get('error', []) + self._success_count = total - len(errors) + self._failure_count = len(errors) + self._errors = [ErrorInfo(err) for err in errors] + + @property + def success_count(self): + """Returns the number of users successfully imported.""" + return self._success_count + + @property + def failure_count(self): + """Returns the number of users that failed to be imported.""" + return self._failure_count + + @property + def errors(self): + """Returns a list of ``auth.ErrorInfo`` instances describing the errors encountered.""" + return self._errors diff --git a/venv/Lib/site-packages/firebase_admin/_user_mgt.py b/venv/Lib/site-packages/firebase_admin/_user_mgt.py new file mode 100644 index 000000000..1d97dd504 --- /dev/null +++ b/venv/Lib/site-packages/firebase_admin/_user_mgt.py @@ -0,0 +1,846 @@ +# Copyright 2017 Google Inc. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +"""Firebase user management sub module.""" + +import base64 +from collections import defaultdict +import json +from urllib import parse + +import requests + +from firebase_admin import _auth_utils +from firebase_admin import _rfc3339 +from firebase_admin import _user_identifier +from firebase_admin import _user_import +from firebase_admin._user_import import ErrorInfo + + +MAX_LIST_USERS_RESULTS = 1000 +MAX_IMPORT_USERS_SIZE = 1000 +B64_REDACTED = base64.b64encode(b'REDACTED') + + +class Sentinel: + + def __init__(self, description): + self.description = description + + +DELETE_ATTRIBUTE = Sentinel('Value used to delete an attribute from a user profile') + + +class UserMetadata: + """Contains additional metadata associated with a user account.""" + + def __init__(self, creation_timestamp=None, last_sign_in_timestamp=None, + last_refresh_timestamp=None): + self._creation_timestamp = _auth_utils.validate_timestamp( + creation_timestamp, 'creation_timestamp') + self._last_sign_in_timestamp = _auth_utils.validate_timestamp( + last_sign_in_timestamp, 'last_sign_in_timestamp') + self._last_refresh_timestamp = _auth_utils.validate_timestamp( + last_refresh_timestamp, 'last_refresh_timestamp') + + @property + def creation_timestamp(self): + """ Creation timestamp in milliseconds since the epoch. + + Returns: + integer: The user creation timestamp in milliseconds since the epoch. + """ + return self._creation_timestamp + + @property + def last_sign_in_timestamp(self): + """ Last sign in timestamp in milliseconds since the epoch. + + Returns: + integer: The last sign in timestamp in milliseconds since the epoch. + """ + return self._last_sign_in_timestamp + + @property + def last_refresh_timestamp(self): + """The time at which the user was last active (ID token refreshed). + + Returns: + integer: Milliseconds since epoch timestamp, or `None` if the user was + never active. + """ + return self._last_refresh_timestamp + + +class UserInfo: + """A collection of standard profile information for a user. + + Used to expose profile information returned by an identity provider. + """ + + @property + def uid(self): + """Returns the user ID of this user.""" + raise NotImplementedError + + @property + def display_name(self): + """Returns the display name of this user.""" + raise NotImplementedError + + @property + def email(self): + """Returns the email address associated with this user.""" + raise NotImplementedError + + @property + def phone_number(self): + """Returns the phone number associated with this user.""" + raise NotImplementedError + + @property + def photo_url(self): + """Returns the photo URL of this user.""" + raise NotImplementedError + + @property + def provider_id(self): + """Returns the ID of the identity provider. + + This can be a short domain name (e.g. google.com), or the identity of an OpenID + identity provider. + """ + raise NotImplementedError + + +class UserRecord(UserInfo): + """Contains metadata associated with a Firebase user account.""" + + def __init__(self, data): + super(UserRecord, self).__init__() + if not isinstance(data, dict): + raise ValueError('Invalid data argument: {0}. Must be a dictionary.'.format(data)) + if not data.get('localId'): + raise ValueError('User ID must not be None or empty.') + self._data = data + + @property + def uid(self): + """Returns the user ID of this user. + + Returns: + string: A user ID string. This value is never None or empty. + """ + return self._data.get('localId') + + @property + def display_name(self): + """Returns the display name of this user. + + Returns: + string: A display name string or None. + """ + return self._data.get('displayName') + + @property + def email(self): + """Returns the email address associated with this user. + + Returns: + string: An email address string or None. + """ + return self._data.get('email') + + @property + def phone_number(self): + """Returns the phone number associated with this user. + + Returns: + string: A phone number string or None. + """ + return self._data.get('phoneNumber') + + @property + def photo_url(self): + """Returns the photo URL of this user. + + Returns: + string: A URL string or None. + """ + return self._data.get('photoUrl') + + @property + def provider_id(self): + """Returns the provider ID of this user. + + Returns: + string: A constant provider ID value. + """ + return 'firebase' + + @property + def email_verified(self): + """Returns whether the email address of this user has been verified. + + Returns: + bool: True if the email has been verified, and False otherwise. + """ + return bool(self._data.get('emailVerified')) + + @property + def disabled(self): + """Returns whether this user account is disabled. + + Returns: + bool: True if the user account is disabled, and False otherwise. + """ + return bool(self._data.get('disabled')) + + @property + def tokens_valid_after_timestamp(self): + """Returns the time, in milliseconds since the epoch, before which tokens are invalid. + + Note: this is truncated to 1 second accuracy. + + Returns: + int: Timestamp in milliseconds since the epoch, truncated to the second. + All tokens issued before that time are considered revoked. + """ + valid_since = self._data.get('validSince') + if valid_since is not None: + return 1000 * int(valid_since) + return 0 + + @property + def user_metadata(self): + """Returns additional metadata associated with this user. + + Returns: + UserMetadata: A UserMetadata instance. Does not return None. + """ + def _int_or_none(key): + if key in self._data: + return int(self._data[key]) + return None + last_refresh_at_millis = None + last_refresh_at_rfc3339 = self._data.get('lastRefreshAt', None) + if last_refresh_at_rfc3339: + last_refresh_at_millis = int(_rfc3339.parse_to_epoch(last_refresh_at_rfc3339) * 1000) + return UserMetadata( + _int_or_none('createdAt'), _int_or_none('lastLoginAt'), last_refresh_at_millis) + + @property + def provider_data(self): + """Returns a list of UserInfo instances. + + Each object represents an identity from an identity provider that is linked to this user. + + Returns: + list: A list of UserInfo objects, which may be empty. + """ + providers = self._data.get('providerUserInfo', []) + return [ProviderUserInfo(entry) for entry in providers] + + @property + def custom_claims(self): + """Returns any custom claims set on this user account. + + Returns: + dict: A dictionary of claims or None. + """ + claims = self._data.get('customAttributes') + if claims: + parsed = json.loads(claims) + if parsed != {}: + return parsed + return None + + @property + def tenant_id(self): + """Returns the tenant ID of this user. + + Returns: + string: A tenant ID string or None. + """ + return self._data.get('tenantId') + + +class ExportedUserRecord(UserRecord): + """Contains metadata associated with a user including password hash and salt.""" + + @property + def password_hash(self): + """The user's password hash as a base64-encoded string. + + If the Firebase Auth hashing algorithm (SCRYPT) was used to create the user account, this + is the base64-encoded password hash of the user. If a different hashing algorithm was + used to create this user, as is typical when migrating from another Auth system, this + is an empty string. If no password is set, or if the service account doesn't have permission + to read the password, then this is ``None``. + """ + password_hash = self._data.get('passwordHash') + + # If the password hash is redacted (probably due to missing permissions) then clear it out, + # similar to how the salt is returned. (Otherwise, it *looks* like a b64-encoded hash is + # present, which is confusing.) + if password_hash == B64_REDACTED: + return None + return password_hash + + @property + def password_salt(self): + """The user's password salt as a base64-encoded string. + + If the Firebase Auth hashing algorithm (SCRYPT) was used to create the user account, this + is the base64-encoded password salt of the user. If a different hashing algorithm was + used to create this user, as is typical when migrating from another Auth system, this is + an empty string. If no password is set, or if the service account doesn't have permission to + read the password, then this is ``None``. + """ + return self._data.get('salt') + + +class GetUsersResult: + """Represents the result of the ``auth.get_users()`` API.""" + + def __init__(self, users, not_found): + """Constructs a `GetUsersResult` object. + + Args: + users: List of `UserRecord` instances. + not_found: List of `UserIdentifier` instances. + """ + self._users = users + self._not_found = not_found + + @property + def users(self): + """Set of `UserRecord` instances, corresponding to the set of users + that were requested. Only users that were found are listed here. The + result set is unordered. + """ + return self._users + + @property + def not_found(self): + """Set of `UserIdentifier` instances that were requested, but not + found. + """ + return self._not_found + + +class ListUsersPage: + """Represents a page of user records exported from a Firebase project. + + Provides methods for traversing the user accounts included in this page, as well as retrieving + subsequent pages of users. The iterator returned by ``iterate_all()`` can be used to iterate + through all users in the Firebase project starting from this page. + """ + + def __init__(self, download, page_token, max_results): + self._download = download + self._max_results = max_results + self._current = download(page_token, max_results) + + @property + def users(self): + """A list of ``ExportedUserRecord`` instances available in this page.""" + return [ExportedUserRecord(user) for user in self._current.get('users', [])] + + @property + def next_page_token(self): + """Page token string for the next page (empty string indicates no more pages).""" + return self._current.get('nextPageToken', '') + + @property + def has_next_page(self): + """A boolean indicating whether more pages are available.""" + return bool(self.next_page_token) + + def get_next_page(self): + """Retrieves the next page of user accounts, if available. + + Returns: + ListUsersPage: Next page of users, or None if this is the last page. + """ + if self.has_next_page: + return ListUsersPage(self._download, self.next_page_token, self._max_results) + return None + + def iterate_all(self): + """Retrieves an iterator for user accounts. + + Returned iterator will iterate through all the user accounts in the Firebase project + starting from this page. The iterator will never buffer more than one page of users + in memory at a time. + + Returns: + iterator: An iterator of ExportedUserRecord instances. + """ + return _UserIterator(self) + + +class DeleteUsersResult: + """Represents the result of the ``auth.delete_users()`` API.""" + + def __init__(self, result, total): + """Constructs a `DeleteUsersResult` object. + + Args: + result: The proto response, wrapped in a + `BatchDeleteAccountsResponse` instance. + total: Total integer number of deletion attempts. + """ + errors = result.errors + self._success_count = total - len(errors) + self._failure_count = len(errors) + self._errors = errors + + @property + def success_count(self): + """Returns the number of users that were deleted successfully (possibly + zero). + + Users that did not exist prior to calling `delete_users()` are + considered to be successfully deleted. + """ + return self._success_count + + @property + def failure_count(self): + """Returns the number of users that failed to be deleted (possibly + zero). + """ + return self._failure_count + + @property + def errors(self): + """A list of `auth.ErrorInfo` instances describing the errors that + were encountered during the deletion. Length of this list is equal to + `failure_count`. + """ + return self._errors + + +class BatchDeleteAccountsResponse: + """Represents the results of a `delete_users()` call.""" + + def __init__(self, errors=None): + """Constructs a `BatchDeleteAccountsResponse` instance, corresponding to + the JSON representing the `BatchDeleteAccountsResponse` proto. + + Args: + errors: List of dictionaries, with each dictionary representing an + `ErrorInfo` instance as returned by the server. `None` implies + an empty list. + """ + self.errors = [ErrorInfo(err) for err in errors] if errors else [] + + +class ProviderUserInfo(UserInfo): + """Contains metadata regarding how a user is known by a particular identity provider.""" + + def __init__(self, data): + super(ProviderUserInfo, self).__init__() + if not isinstance(data, dict): + raise ValueError('Invalid data argument: {0}. Must be a dictionary.'.format(data)) + if not data.get('rawId'): + raise ValueError('User ID must not be None or empty.') + self._data = data + + @property + def uid(self): + return self._data.get('rawId') + + @property + def display_name(self): + return self._data.get('displayName') + + @property + def email(self): + return self._data.get('email') + + @property + def phone_number(self): + return self._data.get('phoneNumber') + + @property + def photo_url(self): + return self._data.get('photoUrl') + + @property + def provider_id(self): + return self._data.get('providerId') + + +class ActionCodeSettings: + """Contains required continue/state URL with optional Android and iOS settings. + Used when invoking the email action link generation APIs. + """ + + def __init__(self, url, handle_code_in_app=None, dynamic_link_domain=None, ios_bundle_id=None, + android_package_name=None, android_install_app=None, android_minimum_version=None): + self.url = url + self.handle_code_in_app = handle_code_in_app + self.dynamic_link_domain = dynamic_link_domain + self.ios_bundle_id = ios_bundle_id + self.android_package_name = android_package_name + self.android_install_app = android_install_app + self.android_minimum_version = android_minimum_version + + +def encode_action_code_settings(settings): + """ Validates the provided action code settings for email link generation and + populates the REST api parameters. + + settings - ``ActionCodeSettings`` object provided to be encoded + returns - dict of parameters to be passed for link gereration. + """ + + parameters = {} + # url + if not settings.url: + raise ValueError("Dynamic action links url is mandatory") + + try: + parsed = parse.urlparse(settings.url) + if not parsed.netloc: + raise ValueError('Malformed dynamic action links url: "{0}".'.format(settings.url)) + parameters['continueUrl'] = settings.url + except Exception: + raise ValueError('Malformed dynamic action links url: "{0}".'.format(settings.url)) + + # handle_code_in_app + if settings.handle_code_in_app is not None: + if not isinstance(settings.handle_code_in_app, bool): + raise ValueError('Invalid value provided for handle_code_in_app: {0}' + .format(settings.handle_code_in_app)) + parameters['canHandleCodeInApp'] = settings.handle_code_in_app + + # dynamic_link_domain + if settings.dynamic_link_domain is not None: + if not isinstance(settings.dynamic_link_domain, str): + raise ValueError('Invalid value provided for dynamic_link_domain: {0}' + .format(settings.dynamic_link_domain)) + parameters['dynamicLinkDomain'] = settings.dynamic_link_domain + + # ios_bundle_id + if settings.ios_bundle_id is not None: + if not isinstance(settings.ios_bundle_id, str): + raise ValueError('Invalid value provided for ios_bundle_id: {0}' + .format(settings.ios_bundle_id)) + parameters['iosBundleId'] = settings.ios_bundle_id + + # android_* attributes + if (settings.android_minimum_version or settings.android_install_app) \ + and not settings.android_package_name: + raise ValueError("Android package name is required when specifying other Android settings") + + if settings.android_package_name is not None: + if not isinstance(settings.android_package_name, str): + raise ValueError('Invalid value provided for android_package_name: {0}' + .format(settings.android_package_name)) + parameters['androidPackageName'] = settings.android_package_name + + if settings.android_minimum_version is not None: + if not isinstance(settings.android_minimum_version, str): + raise ValueError('Invalid value provided for android_minimum_version: {0}' + .format(settings.android_minimum_version)) + parameters['androidMinimumVersion'] = settings.android_minimum_version + + if settings.android_install_app is not None: + if not isinstance(settings.android_install_app, bool): + raise ValueError('Invalid value provided for android_install_app: {0}' + .format(settings.android_install_app)) + parameters['androidInstallApp'] = settings.android_install_app + + return parameters + + +class UserManager: + """Provides methods for interacting with the Google Identity Toolkit.""" + + ID_TOOLKIT_URL = 'https://identitytoolkit.googleapis.com/v1' + + def __init__(self, http_client, project_id, tenant_id=None): + self.http_client = http_client + self.base_url = '{0}/projects/{1}'.format(self.ID_TOOLKIT_URL, project_id) + if tenant_id: + self.base_url += '/tenants/{0}'.format(tenant_id) + + def get_user(self, **kwargs): + """Gets the user data corresponding to the provided key.""" + if 'uid' in kwargs: + key, key_type = kwargs.pop('uid'), 'user ID' + payload = {'localId' : [_auth_utils.validate_uid(key, required=True)]} + elif 'email' in kwargs: + key, key_type = kwargs.pop('email'), 'email' + payload = {'email' : [_auth_utils.validate_email(key, required=True)]} + elif 'phone_number' in kwargs: + key, key_type = kwargs.pop('phone_number'), 'phone number' + payload = {'phoneNumber' : [_auth_utils.validate_phone(key, required=True)]} + else: + raise TypeError('Unsupported keyword arguments: {0}.'.format(kwargs)) + + body, http_resp = self._make_request('post', '/accounts:lookup', json=payload) + if not body or not body.get('users'): + raise _auth_utils.UserNotFoundError( + 'No user record found for the provided {0}: {1}.'.format(key_type, key), + http_response=http_resp) + return body['users'][0] + + def get_users(self, identifiers): + """Looks up multiple users by their identifiers (uid, email, etc.) + + Args: + identifiers: UserIdentifier[]: The identifiers indicating the user + to be looked up. Must have <= 100 entries. + + Returns: + list[dict[string, string]]: List of dicts representing the JSON + `UserInfo` responses from the server. + + Raises: + ValueError: If any of the identifiers are invalid or if more than + 100 identifiers are specified. + UnexpectedResponseError: If the backend server responds with an + unexpected message. + """ + if not identifiers: + return [] + if len(identifiers) > 100: + raise ValueError('`identifiers` parameter must have <= 100 entries.') + + payload = defaultdict(list) + for identifier in identifiers: + if isinstance(identifier, _user_identifier.UidIdentifier): + payload['localId'].append(identifier.uid) + elif isinstance(identifier, _user_identifier.EmailIdentifier): + payload['email'].append(identifier.email) + elif isinstance(identifier, _user_identifier.PhoneIdentifier): + payload['phoneNumber'].append(identifier.phone_number) + elif isinstance(identifier, _user_identifier.ProviderIdentifier): + payload['federatedUserId'].append({ + 'providerId': identifier.provider_id, + 'rawId': identifier.provider_uid + }) + else: + raise ValueError( + 'Invalid entry in "identifiers" list. Unsupported type: {}' + .format(type(identifier))) + + body, http_resp = self._make_request( + 'post', '/accounts:lookup', json=payload) + if not http_resp.ok: + raise _auth_utils.UnexpectedResponseError( + 'Failed to get users.', http_response=http_resp) + return body.get('users', []) + + def list_users(self, page_token=None, max_results=MAX_LIST_USERS_RESULTS): + """Retrieves a batch of users.""" + if page_token is not None: + if not isinstance(page_token, str) or not page_token: + raise ValueError('Page token must be a non-empty string.') + if not isinstance(max_results, int): + raise ValueError('Max results must be an integer.') + if max_results < 1 or max_results > MAX_LIST_USERS_RESULTS: + raise ValueError( + 'Max results must be a positive integer less than ' + '{0}.'.format(MAX_LIST_USERS_RESULTS)) + + payload = {'maxResults': max_results} + if page_token: + payload['nextPageToken'] = page_token + body, _ = self._make_request('get', '/accounts:batchGet', params=payload) + return body + + def create_user(self, uid=None, display_name=None, email=None, phone_number=None, + photo_url=None, password=None, disabled=None, email_verified=None): + """Creates a new user account with the specified properties.""" + payload = { + 'localId': _auth_utils.validate_uid(uid), + 'displayName': _auth_utils.validate_display_name(display_name), + 'email': _auth_utils.validate_email(email), + 'phoneNumber': _auth_utils.validate_phone(phone_number), + 'photoUrl': _auth_utils.validate_photo_url(photo_url), + 'password': _auth_utils.validate_password(password), + 'emailVerified': bool(email_verified) if email_verified is not None else None, + 'disabled': bool(disabled) if disabled is not None else None, + } + payload = {k: v for k, v in payload.items() if v is not None} + body, http_resp = self._make_request('post', '/accounts', json=payload) + if not body or not body.get('localId'): + raise _auth_utils.UnexpectedResponseError( + 'Failed to create new user.', http_response=http_resp) + return body.get('localId') + + def update_user(self, uid, display_name=None, email=None, phone_number=None, + photo_url=None, password=None, disabled=None, email_verified=None, + valid_since=None, custom_claims=None): + """Updates an existing user account with the specified properties""" + payload = { + 'localId': _auth_utils.validate_uid(uid, required=True), + 'email': _auth_utils.validate_email(email), + 'password': _auth_utils.validate_password(password), + 'validSince': _auth_utils.validate_timestamp(valid_since, 'valid_since'), + 'emailVerified': bool(email_verified) if email_verified is not None else None, + 'disableUser': bool(disabled) if disabled is not None else None, + } + + remove = [] + if display_name is not None: + if display_name is DELETE_ATTRIBUTE: + remove.append('DISPLAY_NAME') + else: + payload['displayName'] = _auth_utils.validate_display_name(display_name) + if photo_url is not None: + if photo_url is DELETE_ATTRIBUTE: + remove.append('PHOTO_URL') + else: + payload['photoUrl'] = _auth_utils.validate_photo_url(photo_url) + if remove: + payload['deleteAttribute'] = remove + + if phone_number is not None: + if phone_number is DELETE_ATTRIBUTE: + payload['deleteProvider'] = ['phone'] + else: + payload['phoneNumber'] = _auth_utils.validate_phone(phone_number) + + if custom_claims is not None: + if custom_claims is DELETE_ATTRIBUTE: + custom_claims = {} + json_claims = json.dumps(custom_claims) if isinstance( + custom_claims, dict) else custom_claims + payload['customAttributes'] = _auth_utils.validate_custom_claims(json_claims) + + payload = {k: v for k, v in payload.items() if v is not None} + body, http_resp = self._make_request('post', '/accounts:update', json=payload) + if not body or not body.get('localId'): + raise _auth_utils.UnexpectedResponseError( + 'Failed to update user: {0}.'.format(uid), http_response=http_resp) + return body.get('localId') + + def delete_user(self, uid): + """Deletes the user identified by the specified user ID.""" + _auth_utils.validate_uid(uid, required=True) + body, http_resp = self._make_request('post', '/accounts:delete', json={'localId' : uid}) + if not body or not body.get('kind'): + raise _auth_utils.UnexpectedResponseError( + 'Failed to delete user: {0}.'.format(uid), http_response=http_resp) + + def delete_users(self, uids, force_delete=False): + """Deletes the users identified by the specified user ids. + + Args: + uids: A list of strings indicating the uids of the users to be deleted. + Must have <= 1000 entries. + force_delete: Optional parameter that indicates if users should be + deleted, even if they're not disabled. Defaults to False. + + + Returns: + BatchDeleteAccountsResponse: Server's proto response, wrapped in a + python object. + + Raises: + ValueError: If any of the identifiers are invalid or if more than 1000 + identifiers are specified. + UnexpectedResponseError: If the backend server responds with an + unexpected message. + """ + if not uids: + return BatchDeleteAccountsResponse() + + if len(uids) > 1000: + raise ValueError("`uids` paramter must have <= 1000 entries.") + for uid in uids: + _auth_utils.validate_uid(uid, required=True) + + body, http_resp = self._make_request('post', '/accounts:batchDelete', + json={'localIds': uids, 'force': force_delete}) + if not isinstance(body, dict): + raise _auth_utils.UnexpectedResponseError( + 'Unexpected response from server while attempting to delete users.', + http_response=http_resp) + return BatchDeleteAccountsResponse(body.get('errors', [])) + + def import_users(self, users, hash_alg=None): + """Imports the given list of users to Firebase Auth.""" + try: + if not users or len(users) > MAX_IMPORT_USERS_SIZE: + raise ValueError( + 'Users must be a non-empty list with no more than {0} elements.'.format( + MAX_IMPORT_USERS_SIZE)) + if any([not isinstance(u, _user_import.ImportUserRecord) for u in users]): + raise ValueError('One or more user objects are invalid.') + except TypeError: + raise ValueError('users must be iterable') + + payload = {'users': [u.to_dict() for u in users]} + if any(['passwordHash' in u for u in payload['users']]): + if not isinstance(hash_alg, _user_import.UserImportHash): + raise ValueError('A UserImportHash is required to import users with passwords.') + payload.update(hash_alg.to_dict()) + body, http_resp = self._make_request('post', '/accounts:batchCreate', json=payload) + if not isinstance(body, dict): + raise _auth_utils.UnexpectedResponseError( + 'Failed to import users.', http_response=http_resp) + return body + + def generate_email_action_link(self, action_type, email, action_code_settings=None): + """Fetches the email action links for types + + Args: + action_type: String. Valid values ['VERIFY_EMAIL', 'EMAIL_SIGNIN', 'PASSWORD_RESET'] + email: Email of the user for which the action is performed + action_code_settings: ``ActionCodeSettings`` object or dict (optional). Defines whether + the link is to be handled by a mobile app and the additional state information to be + passed in the deep link, etc. + Returns: + link_url: action url to be emailed to the user + + Raises: + UnexpectedResponseError: If the backend server responds with an unexpected message + FirebaseError: If an error occurs while generating the link + ValueError: If the provided arguments are invalid + """ + payload = { + 'requestType': _auth_utils.validate_action_type(action_type), + 'email': _auth_utils.validate_email(email), + 'returnOobLink': True + } + + if action_code_settings: + payload.update(encode_action_code_settings(action_code_settings)) + + body, http_resp = self._make_request('post', '/accounts:sendOobCode', json=payload) + if not body or not body.get('oobLink'): + raise _auth_utils.UnexpectedResponseError( + 'Failed to generate email action link.', http_response=http_resp) + return body.get('oobLink') + + def _make_request(self, method, path, **kwargs): + url = '{0}{1}'.format(self.base_url, path) + try: + return self.http_client.body_and_response(method, url, **kwargs) + except requests.exceptions.RequestException as error: + raise _auth_utils.handle_auth_backend_error(error) + + +class _UserIterator(_auth_utils.PageIterator): + + @property + def items(self): + return self._current_page.users diff --git a/venv/Lib/site-packages/firebase_admin/_utils.py b/venv/Lib/site-packages/firebase_admin/_utils.py new file mode 100644 index 000000000..a5fc8d022 --- /dev/null +++ b/venv/Lib/site-packages/firebase_admin/_utils.py @@ -0,0 +1,341 @@ +# Copyright 2017 Google Inc. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +"""Internal utilities common to all modules.""" + +import io +import json +import socket + +import googleapiclient +import httplib2 +import requests + +import firebase_admin +from firebase_admin import exceptions + + +_ERROR_CODE_TO_EXCEPTION_TYPE = { + exceptions.INVALID_ARGUMENT: exceptions.InvalidArgumentError, + exceptions.FAILED_PRECONDITION: exceptions.FailedPreconditionError, + exceptions.OUT_OF_RANGE: exceptions.OutOfRangeError, + exceptions.UNAUTHENTICATED: exceptions.UnauthenticatedError, + exceptions.PERMISSION_DENIED: exceptions.PermissionDeniedError, + exceptions.NOT_FOUND: exceptions.NotFoundError, + exceptions.ABORTED: exceptions.AbortedError, + exceptions.ALREADY_EXISTS: exceptions.AlreadyExistsError, + exceptions.CONFLICT: exceptions.ConflictError, + exceptions.RESOURCE_EXHAUSTED: exceptions.ResourceExhaustedError, + exceptions.CANCELLED: exceptions.CancelledError, + exceptions.DATA_LOSS: exceptions.DataLossError, + exceptions.UNKNOWN: exceptions.UnknownError, + exceptions.INTERNAL: exceptions.InternalError, + exceptions.UNAVAILABLE: exceptions.UnavailableError, + exceptions.DEADLINE_EXCEEDED: exceptions.DeadlineExceededError, +} + + +_HTTP_STATUS_TO_ERROR_CODE = { + 400: exceptions.INVALID_ARGUMENT, + 401: exceptions.UNAUTHENTICATED, + 403: exceptions.PERMISSION_DENIED, + 404: exceptions.NOT_FOUND, + 409: exceptions.CONFLICT, + 412: exceptions.FAILED_PRECONDITION, + 429: exceptions.RESOURCE_EXHAUSTED, + 500: exceptions.INTERNAL, + 503: exceptions.UNAVAILABLE, +} + + +# See https://github.com/googleapis/googleapis/blob/master/google/rpc/code.proto +_RPC_CODE_TO_ERROR_CODE = { + 1: exceptions.CANCELLED, + 2: exceptions.UNKNOWN, + 3: exceptions.INVALID_ARGUMENT, + 4: exceptions.DEADLINE_EXCEEDED, + 5: exceptions.NOT_FOUND, + 6: exceptions.ALREADY_EXISTS, + 7: exceptions.PERMISSION_DENIED, + 8: exceptions.RESOURCE_EXHAUSTED, + 9: exceptions.FAILED_PRECONDITION, + 10: exceptions.ABORTED, + 11: exceptions.OUT_OF_RANGE, + 13: exceptions.INTERNAL, + 14: exceptions.UNAVAILABLE, + 15: exceptions.DATA_LOSS, + 16: exceptions.UNAUTHENTICATED, +} + + +def _get_initialized_app(app): + """Returns a reference to an initialized App instance.""" + if app is None: + return firebase_admin.get_app() + + if isinstance(app, firebase_admin.App): + initialized_app = firebase_admin.get_app(app.name) + if app is not initialized_app: + raise ValueError('Illegal app argument. App instance not ' + 'initialized via the firebase module.') + return app + + raise ValueError('Illegal app argument. Argument must be of type ' + ' firebase_admin.App, but given "{0}".'.format(type(app))) + + + +def get_app_service(app, name, initializer): + app = _get_initialized_app(app) + return app._get_service(name, initializer) # pylint: disable=protected-access + + +def handle_platform_error_from_requests(error, handle_func=None): + """Constructs a ``FirebaseError`` from the given requests error. + + This can be used to handle errors returned by Google Cloud Platform (GCP) APIs. + + Args: + error: An error raised by the requests module while making an HTTP call to a GCP API. + handle_func: A function that can be used to handle platform errors in a custom way. When + specified, this function will be called with three arguments. It has the same + signature as ```_handle_func_requests``, but may return ``None``. + + Returns: + FirebaseError: A ``FirebaseError`` that can be raised to the user code. + """ + if error.response is None: + return handle_requests_error(error) + + response = error.response + content = response.content.decode() + status_code = response.status_code + error_dict, message = _parse_platform_error(content, status_code) + exc = None + if handle_func: + exc = handle_func(error, message, error_dict) + + return exc if exc else _handle_func_requests(error, message, error_dict) + + +def handle_operation_error(error): + """Constructs a ``FirebaseError`` from the given operation error. + + Args: + error: An error returned by a long running operation. + + Returns: + FirebaseError: A ``FirebaseError`` that can be raised to the user code. + """ + if not isinstance(error, dict): + return exceptions.UnknownError( + message='Unknown error while making a remote service call: {0}'.format(error), + cause=error) + + rpc_code = error.get('code') + message = error.get('message') + error_code = _rpc_code_to_error_code(rpc_code) + err_type = _error_code_to_exception_type(error_code) + return err_type(message=message) + + +def _handle_func_requests(error, message, error_dict): + """Constructs a ``FirebaseError`` from the given GCP error. + + Args: + error: An error raised by the requests module while making an HTTP call. + message: A message to be included in the resulting ``FirebaseError``. + error_dict: Parsed GCP error response. + + Returns: + FirebaseError: A ``FirebaseError`` that can be raised to the user code or None. + """ + code = error_dict.get('status') + return handle_requests_error(error, message, code) + + +def handle_requests_error(error, message=None, code=None): + """Constructs a ``FirebaseError`` from the given requests error. + + This method is agnostic of the remote service that produced the error, whether it is a GCP + service or otherwise. Therefore, this method does not attempt to parse the error response in + any way. + + Args: + error: An error raised by the requests module while making an HTTP call. + message: A message to be included in the resulting ``FirebaseError`` (optional). If not + specified the string representation of the ``error`` argument is used as the message. + code: A GCP error code that will be used to determine the resulting error type (optional). + If not specified the HTTP status code on the error response is used to determine a + suitable error code. + + Returns: + FirebaseError: A ``FirebaseError`` that can be raised to the user code. + """ + if isinstance(error, requests.exceptions.Timeout): + return exceptions.DeadlineExceededError( + message='Timed out while making an API call: {0}'.format(error), + cause=error) + if isinstance(error, requests.exceptions.ConnectionError): + return exceptions.UnavailableError( + message='Failed to establish a connection: {0}'.format(error), + cause=error) + if error.response is None: + return exceptions.UnknownError( + message='Unknown error while making a remote service call: {0}'.format(error), + cause=error) + + if not code: + code = _http_status_to_error_code(error.response.status_code) + if not message: + message = str(error) + + err_type = _error_code_to_exception_type(code) + return err_type(message=message, cause=error, http_response=error.response) + + +def handle_platform_error_from_googleapiclient(error, handle_func=None): + """Constructs a ``FirebaseError`` from the given googleapiclient error. + + This can be used to handle errors returned by Google Cloud Platform (GCP) APIs. + + Args: + error: An error raised by the googleapiclient while making an HTTP call to a GCP API. + handle_func: A function that can be used to handle platform errors in a custom way. When + specified, this function will be called with three arguments. It has the same + signature as ```_handle_func_googleapiclient``, but may return ``None``. + + Returns: + FirebaseError: A ``FirebaseError`` that can be raised to the user code. + """ + if not isinstance(error, googleapiclient.errors.HttpError): + return handle_googleapiclient_error(error) + + content = error.content.decode() + status_code = error.resp.status + error_dict, message = _parse_platform_error(content, status_code) + http_response = _http_response_from_googleapiclient_error(error) + exc = None + if handle_func: + exc = handle_func(error, message, error_dict, http_response) + + return exc if exc else _handle_func_googleapiclient(error, message, error_dict, http_response) + + +def _handle_func_googleapiclient(error, message, error_dict, http_response): + """Constructs a ``FirebaseError`` from the given GCP error. + + Args: + error: An error raised by the googleapiclient module while making an HTTP call. + message: A message to be included in the resulting ``FirebaseError``. + error_dict: Parsed GCP error response. + http_response: A requests HTTP response object to associate with the exception. + + Returns: + FirebaseError: A ``FirebaseError`` that can be raised to the user code or None. + """ + code = error_dict.get('status') + return handle_googleapiclient_error(error, message, code, http_response) + + +def handle_googleapiclient_error(error, message=None, code=None, http_response=None): + """Constructs a ``FirebaseError`` from the given googleapiclient error. + + This method is agnostic of the remote service that produced the error, whether it is a GCP + service or otherwise. Therefore, this method does not attempt to parse the error response in + any way. + + Args: + error: An error raised by the googleapiclient module while making an HTTP call. + message: A message to be included in the resulting ``FirebaseError`` (optional). If not + specified the string representation of the ``error`` argument is used as the message. + code: A GCP error code that will be used to determine the resulting error type (optional). + If not specified the HTTP status code on the error response is used to determine a + suitable error code. + http_response: A requests HTTP response object to associate with the exception (optional). + If not specified, one will be created from the ``error``. + + Returns: + FirebaseError: A ``FirebaseError`` that can be raised to the user code. + """ + if isinstance(error, socket.timeout) or ( + isinstance(error, socket.error) and 'timed out' in str(error)): + return exceptions.DeadlineExceededError( + message='Timed out while making an API call: {0}'.format(error), + cause=error) + if isinstance(error, httplib2.ServerNotFoundError): + return exceptions.UnavailableError( + message='Failed to establish a connection: {0}'.format(error), + cause=error) + if not isinstance(error, googleapiclient.errors.HttpError): + return exceptions.UnknownError( + message='Unknown error while making a remote service call: {0}'.format(error), + cause=error) + + if not code: + code = _http_status_to_error_code(error.resp.status) + if not message: + message = str(error) + if not http_response: + http_response = _http_response_from_googleapiclient_error(error) + + err_type = _error_code_to_exception_type(code) + return err_type(message=message, cause=error, http_response=http_response) + + +def _http_response_from_googleapiclient_error(error): + """Creates a requests HTTP Response object from the given googleapiclient error.""" + resp = requests.models.Response() + resp.raw = io.BytesIO(error.content) + resp.status_code = error.resp.status + return resp + + +def _http_status_to_error_code(status): + """Maps an HTTP status to a platform error code.""" + return _HTTP_STATUS_TO_ERROR_CODE.get(status, exceptions.UNKNOWN) + +def _rpc_code_to_error_code(rpc_code): + """Maps an RPC code to a platform error code.""" + return _RPC_CODE_TO_ERROR_CODE.get(rpc_code, exceptions.UNKNOWN) + +def _error_code_to_exception_type(code): + """Maps a platform error code to an exception type.""" + return _ERROR_CODE_TO_EXCEPTION_TYPE.get(code, exceptions.UnknownError) + + +def _parse_platform_error(content, status_code): + """Parses an HTTP error response from a Google Cloud Platform API and extracts the error code + and message fields. + + Args: + content: Decoded content of the response body. + status_code: HTTP status code. + + Returns: + tuple: A tuple containing error code and message. + """ + data = {} + try: + parsed_body = json.loads(content) + if isinstance(parsed_body, dict): + data = parsed_body + except ValueError: + pass + + error_dict = data.get('error', {}) + msg = error_dict.get('message') + if not msg: + msg = 'Unexpected HTTP response with status: {0}; body: {1}'.format(status_code, content) + return error_dict, msg diff --git a/venv/Lib/site-packages/firebase_admin/auth.py b/venv/Lib/site-packages/firebase_admin/auth.py new file mode 100644 index 000000000..5154bb495 --- /dev/null +++ b/venv/Lib/site-packages/firebase_admin/auth.py @@ -0,0 +1,883 @@ +# Copyright 2017 Google Inc. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +"""Firebase Authentication module. + +This module contains functions for minting and verifying JWTs used for +authenticating against Firebase services. It also provides functions for +creating and managing user accounts in Firebase projects. +""" + +from firebase_admin import _auth_client +from firebase_admin import _auth_providers +from firebase_admin import _auth_utils +from firebase_admin import _user_identifier +from firebase_admin import _token_gen +from firebase_admin import _user_import +from firebase_admin import _user_mgt +from firebase_admin import _utils + + +_AUTH_ATTRIBUTE = '_auth' + + +__all__ = [ + 'ActionCodeSettings', + 'CertificateFetchError', + 'Client', + 'ConfigurationNotFoundError', + 'DELETE_ATTRIBUTE', + 'EmailAlreadyExistsError', + 'ErrorInfo', + 'ExpiredIdTokenError', + 'ExpiredSessionCookieError', + 'ExportedUserRecord', + 'DeleteUsersResult', + 'GetUsersResult', + 'ImportUserRecord', + 'InsufficientPermissionError', + 'InvalidDynamicLinkDomainError', + 'InvalidIdTokenError', + 'InvalidSessionCookieError', + 'ListProviderConfigsPage', + 'ListUsersPage', + 'OIDCProviderConfig', + 'PhoneNumberAlreadyExistsError', + 'ProviderConfig', + 'RevokedIdTokenError', + 'RevokedSessionCookieError', + 'SAMLProviderConfig', + 'TokenSignError', + 'UidAlreadyExistsError', + 'UnexpectedResponseError', + 'UserImportHash', + 'UserImportResult', + 'UserInfo', + 'UserMetadata', + 'UserNotFoundError', + 'UserProvider', + 'UserRecord', + + 'UserIdentifier', + 'UidIdentifier', + 'EmailIdentifier', + 'PhoneIdentifier', + 'ProviderIdentifier', + + 'create_custom_token', + 'create_oidc_provider_config', + 'create_saml_provider_config', + 'create_session_cookie', + 'create_user', + 'delete_oidc_provider_config', + 'delete_saml_provider_config', + 'delete_user', + 'delete_users', + 'generate_email_verification_link', + 'generate_password_reset_link', + 'generate_sign_in_with_email_link', + 'get_oidc_provider_config', + 'get_saml_provider_config', + 'get_user', + 'get_user_by_email', + 'get_user_by_phone_number', + 'get_users', + 'import_users', + 'list_saml_provider_configs', + 'list_users', + 'revoke_refresh_tokens', + 'set_custom_user_claims', + 'update_oidc_provider_config', + 'update_saml_provider_config', + 'update_user', + 'verify_id_token', + 'verify_session_cookie', +] + +ActionCodeSettings = _user_mgt.ActionCodeSettings +CertificateFetchError = _token_gen.CertificateFetchError +Client = _auth_client.Client +ConfigurationNotFoundError = _auth_utils.ConfigurationNotFoundError +DELETE_ATTRIBUTE = _user_mgt.DELETE_ATTRIBUTE +DeleteUsersResult = _user_mgt.DeleteUsersResult +EmailAlreadyExistsError = _auth_utils.EmailAlreadyExistsError +ErrorInfo = _user_import.ErrorInfo +ExpiredIdTokenError = _token_gen.ExpiredIdTokenError +ExpiredSessionCookieError = _token_gen.ExpiredSessionCookieError +ExportedUserRecord = _user_mgt.ExportedUserRecord +GetUsersResult = _user_mgt.GetUsersResult +ImportUserRecord = _user_import.ImportUserRecord +InsufficientPermissionError = _auth_utils.InsufficientPermissionError +InvalidDynamicLinkDomainError = _auth_utils.InvalidDynamicLinkDomainError +InvalidIdTokenError = _auth_utils.InvalidIdTokenError +InvalidSessionCookieError = _token_gen.InvalidSessionCookieError +ListProviderConfigsPage = _auth_providers.ListProviderConfigsPage +ListUsersPage = _user_mgt.ListUsersPage +OIDCProviderConfig = _auth_providers.OIDCProviderConfig +PhoneNumberAlreadyExistsError = _auth_utils.PhoneNumberAlreadyExistsError +ProviderConfig = _auth_providers.ProviderConfig +RevokedIdTokenError = _token_gen.RevokedIdTokenError +RevokedSessionCookieError = _token_gen.RevokedSessionCookieError +SAMLProviderConfig = _auth_providers.SAMLProviderConfig +TokenSignError = _token_gen.TokenSignError +UidAlreadyExistsError = _auth_utils.UidAlreadyExistsError +UnexpectedResponseError = _auth_utils.UnexpectedResponseError +UserImportHash = _user_import.UserImportHash +UserImportResult = _user_import.UserImportResult +UserInfo = _user_mgt.UserInfo +UserMetadata = _user_mgt.UserMetadata +UserNotFoundError = _auth_utils.UserNotFoundError +UserProvider = _user_import.UserProvider +UserRecord = _user_mgt.UserRecord + +UserIdentifier = _user_identifier.UserIdentifier +UidIdentifier = _user_identifier.UidIdentifier +EmailIdentifier = _user_identifier.EmailIdentifier +PhoneIdentifier = _user_identifier.PhoneIdentifier +ProviderIdentifier = _user_identifier.ProviderIdentifier + + +def _get_client(app): + """Returns a client instance for an App. + + If the App already has a client associated with it, simply returns + it. Otherwise creates a new client, and adds it to the App before + returning it. + + Args: + app: A Firebase App instance (or ``None`` to use the default App). + + Returns: + Client: A client for the specified App instance. + + Raises: + ValueError: If the app argument is invalid. + """ + return _utils.get_app_service(app, _AUTH_ATTRIBUTE, Client) + + +def create_custom_token(uid, developer_claims=None, app=None): + """Builds and signs a Firebase custom auth token. + + Args: + uid: ID of the user for whom the token is created. + developer_claims: A dictionary of claims to be included in the token + (optional). + app: An App instance (optional). + + Returns: + bytes: A token minted from the input parameters. + + Raises: + ValueError: If input parameters are invalid. + TokenSignError: If an error occurs while signing the token using the remote IAM service. + """ + client = _get_client(app) + return client.create_custom_token(uid, developer_claims) + + +def verify_id_token(id_token, app=None, check_revoked=False): + """Verifies the signature and data for the provided JWT. + + Accepts a signed token string, verifies that it is current, and issued + to this project, and that it was correctly signed by Google. + + Args: + id_token: A string of the encoded JWT. + app: An App instance (optional). + check_revoked: Boolean, If true, checks whether the token has been revoked (optional). + + Returns: + dict: A dictionary of key-value pairs parsed from the decoded JWT. + + Raises: + ValueError: If ``id_token`` is a not a string or is empty. + InvalidIdTokenError: If ``id_token`` is not a valid Firebase ID token. + ExpiredIdTokenError: If the specified ID token has expired. + RevokedIdTokenError: If ``check_revoked`` is ``True`` and the ID token has been revoked. + CertificateFetchError: If an error occurs while fetching the public key certificates + required to verify the ID token. + """ + client = _get_client(app) + return client.verify_id_token(id_token, check_revoked=check_revoked) + + +def create_session_cookie(id_token, expires_in, app=None): + """Creates a new Firebase session cookie from the given ID token and options. + + The returned JWT can be set as a server-side session cookie with a custom cookie policy. + + Args: + id_token: The Firebase ID token to exchange for a session cookie. + expires_in: Duration until the cookie is expired. This can be specified + as a numeric seconds value or a ``datetime.timedelta`` instance. + app: An App instance (optional). + + Returns: + bytes: A session cookie generated from the input parameters. + + Raises: + ValueError: If input parameters are invalid. + FirebaseError: If an error occurs while creating the cookie. + """ + client = _get_client(app) + # pylint: disable=protected-access + return client._token_generator.create_session_cookie(id_token, expires_in) + + +def verify_session_cookie(session_cookie, check_revoked=False, app=None): + """Verifies a Firebase session cookie. + + Accepts a session cookie string, verifies that it is current, and issued + to this project, and that it was correctly signed by Google. + + Args: + session_cookie: A session cookie string to verify. + check_revoked: Boolean, if true, checks whether the cookie has been revoked (optional). + app: An App instance (optional). + + Returns: + dict: A dictionary of key-value pairs parsed from the decoded JWT. + + Raises: + ValueError: If ``session_cookie`` is a not a string or is empty. + InvalidSessionCookieError: If ``session_cookie`` is not a valid Firebase session cookie. + ExpiredSessionCookieError: If the specified session cookie has expired. + RevokedSessionCookieError: If ``check_revoked`` is ``True`` and the cookie has been revoked. + CertificateFetchError: If an error occurs while fetching the public key certificates + required to verify the session cookie. + """ + client = _get_client(app) + # pylint: disable=protected-access + verified_claims = client._token_verifier.verify_session_cookie(session_cookie) + if check_revoked: + client._check_jwt_revoked(verified_claims, RevokedSessionCookieError, 'session cookie') + return verified_claims + + +def revoke_refresh_tokens(uid, app=None): + """Revokes all refresh tokens for an existing user. + + This function updates the user's ``tokens_valid_after_timestamp`` to the current UTC + in seconds since the epoch. It is important that the server on which this is called has its + clock set correctly and synchronized. + + While this revokes all sessions for a specified user and disables any new ID tokens for + existing sessions from getting minted, existing ID tokens may remain active until their + natural expiration (one hour). To verify that ID tokens are revoked, use + ``verify_id_token(idToken, check_revoked=True)``. + + Args: + uid: A user ID string. + app: An App instance (optional). + + Raises: + ValueError: If the user ID is None, empty or malformed. + FirebaseError: If an error occurs while revoking the refresh token. + """ + client = _get_client(app) + client.revoke_refresh_tokens(uid) + + +def get_user(uid, app=None): + """Gets the user data corresponding to the specified user ID. + + Args: + uid: A user ID string. + app: An App instance (optional). + + Returns: + UserRecord: A user record instance. + + Raises: + ValueError: If the user ID is None, empty or malformed. + UserNotFoundError: If the specified user ID does not exist. + FirebaseError: If an error occurs while retrieving the user. + """ + client = _get_client(app) + return client.get_user(uid=uid) + + +def get_user_by_email(email, app=None): + """Gets the user data corresponding to the specified user email. + + Args: + email: A user email address string. + app: An App instance (optional). + + Returns: + UserRecord: A user record instance. + + Raises: + ValueError: If the email is None, empty or malformed. + UserNotFoundError: If no user exists by the specified email address. + FirebaseError: If an error occurs while retrieving the user. + """ + client = _get_client(app) + return client.get_user_by_email(email=email) + + +def get_user_by_phone_number(phone_number, app=None): + """Gets the user data corresponding to the specified phone number. + + Args: + phone_number: A phone number string. + app: An App instance (optional). + + Returns: + UserRecord: A user record instance. + + Raises: + ValueError: If the phone number is None, empty or malformed. + UserNotFoundError: If no user exists by the specified phone number. + FirebaseError: If an error occurs while retrieving the user. + """ + client = _get_client(app) + return client.get_user_by_phone_number(phone_number=phone_number) + + +def get_users(identifiers, app=None): + """Gets the user data corresponding to the specified identifiers. + + There are no ordering guarantees; in particular, the nth entry in the + result list is not guaranteed to correspond to the nth entry in the input + parameters list. + + A maximum of 100 identifiers may be supplied. If more than 100 + identifiers are supplied, this method raises a `ValueError`. + + Args: + identifiers (list[UserIdentifier]): A list of ``UserIdentifier`` + instances used to indicate which user records should be returned. + Must have <= 100 entries. + app: An App instance (optional). + + Returns: + GetUsersResult: A ``GetUsersResult`` instance corresponding to the + specified identifiers. + + Raises: + ValueError: If any of the identifiers are invalid or if more than 100 + identifiers are specified. + """ + client = _get_client(app) + return client.get_users(identifiers) + + +def list_users(page_token=None, max_results=_user_mgt.MAX_LIST_USERS_RESULTS, app=None): + """Retrieves a page of user accounts from a Firebase project. + + The ``page_token`` argument governs the starting point of the page. The ``max_results`` + argument governs the maximum number of user accounts that may be included in the returned page. + This function never returns None. If there are no user accounts in the Firebase project, this + returns an empty page. + + Args: + page_token: A non-empty page token string, which indicates the starting point of the page + (optional). Defaults to ``None``, which will retrieve the first page of users. + max_results: A positive integer indicating the maximum number of users to include in the + returned page (optional). Defaults to 1000, which is also the maximum number allowed. + app: An App instance (optional). + + Returns: + ListUsersPage: A page of user accounts. + + Raises: + ValueError: If ``max_results`` or ``page_token`` are invalid. + FirebaseError: If an error occurs while retrieving the user accounts. + """ + client = _get_client(app) + return client.list_users(page_token=page_token, max_results=max_results) + + +def create_user(**kwargs): # pylint: disable=differing-param-doc + """Creates a new user account with the specified properties. + + Args: + kwargs: A series of keyword arguments (optional). + + Keyword Args: + uid: User ID to assign to the newly created user (optional). + display_name: The user's display name (optional). + email: The user's primary email (optional). + email_verified: A boolean indicating whether or not the user's primary email is + verified (optional). + phone_number: The user's primary phone number (optional). + photo_url: The user's photo URL (optional). + password: The user's raw, unhashed password. (optional). + disabled: A boolean indicating whether or not the user account is disabled (optional). + app: An App instance (optional). + + Returns: + UserRecord: A user record instance for the newly created user. + + Raises: + ValueError: If the specified user properties are invalid. + FirebaseError: If an error occurs while creating the user account. + """ + app = kwargs.pop('app', None) + client = _get_client(app) + return client.create_user(**kwargs) + + +def update_user(uid, **kwargs): # pylint: disable=differing-param-doc + """Updates an existing user account with the specified properties. + + Args: + uid: A user ID string. + kwargs: A series of keyword arguments (optional). + + Keyword Args: + display_name: The user's display name (optional). Can be removed by explicitly passing + ``auth.DELETE_ATTRIBUTE``. + email: The user's primary email (optional). + email_verified: A boolean indicating whether or not the user's primary email is + verified (optional). + phone_number: The user's primary phone number (optional). Can be removed by explicitly + passing ``auth.DELETE_ATTRIBUTE``. + photo_url: The user's photo URL (optional). Can be removed by explicitly passing + ``auth.DELETE_ATTRIBUTE``. + password: The user's raw, unhashed password. (optional). + disabled: A boolean indicating whether or not the user account is disabled (optional). + custom_claims: A dictionary or a JSON string containing the custom claims to be set on the + user account (optional). To remove all custom claims, pass ``auth.DELETE_ATTRIBUTE``. + valid_since: An integer signifying the seconds since the epoch (optional). This field is + set by ``revoke_refresh_tokens`` and it is discouraged to set this field directly. + app: An App instance (optional). + + Returns: + UserRecord: An updated user record instance for the user. + + Raises: + ValueError: If the specified user ID or properties are invalid. + FirebaseError: If an error occurs while updating the user account. + """ + app = kwargs.pop('app', None) + client = _get_client(app) + return client.update_user(uid, **kwargs) + + +def set_custom_user_claims(uid, custom_claims, app=None): + """Sets additional claims on an existing user account. + + Custom claims set via this function can be used to define user roles and privilege levels. + These claims propagate to all the devices where the user is already signed in (after token + expiration or when token refresh is forced), and next time the user signs in. The claims + can be accessed via the user's ID token JWT. If a reserved OIDC claim is specified (sub, iat, + iss, etc), an error is thrown. Claims payload must also not be larger then 1000 characters + when serialized into a JSON string. + + Args: + uid: A user ID string. + custom_claims: A dictionary or a JSON string of custom claims. Pass None to unset any + claims set previously. + app: An App instance (optional). + + Raises: + ValueError: If the specified user ID or the custom claims are invalid. + FirebaseError: If an error occurs while updating the user account. + """ + client = _get_client(app) + client.set_custom_user_claims(uid, custom_claims=custom_claims) + + +def delete_user(uid, app=None): + """Deletes the user identified by the specified user ID. + + Args: + uid: A user ID string. + app: An App instance (optional). + + Raises: + ValueError: If the user ID is None, empty or malformed. + FirebaseError: If an error occurs while deleting the user account. + """ + client = _get_client(app) + client.delete_user(uid) + + +def delete_users(uids, app=None): + """Deletes the users specified by the given identifiers. + + Deleting a non-existing user does not generate an error (the method is + idempotent.) Non-existing users are considered to be successfully deleted + and are therefore included in the `DeleteUserResult.success_count` value. + + A maximum of 1000 identifiers may be supplied. If more than 1000 + identifiers are supplied, this method raises a `ValueError`. + + Args: + uids: A list of strings indicating the uids of the users to be deleted. + Must have <= 1000 entries. + app: An App instance (optional). + + Returns: + DeleteUsersResult: The total number of successful/failed deletions, as + well as the array of errors that correspond to the failed deletions. + + Raises: + ValueError: If any of the identifiers are invalid or if more than 1000 + identifiers are specified. + """ + client = _get_client(app) + return client.delete_users(uids) + + +def import_users(users, hash_alg=None, app=None): + """Imports the specified list of users into Firebase Auth. + + At most 1000 users can be imported at a time. This operation is optimized for bulk imports and + will ignore checks on identifier uniqueness which could result in duplications. The + ``hash_alg`` parameter must be specified when importing users with passwords. Refer to the + ``UserImportHash`` class for supported hash algorithms. + + Args: + users: A list of ``ImportUserRecord`` instances to import. Length of the list must not + exceed 1000. + hash_alg: A ``UserImportHash`` object (optional). Required when importing users with + passwords. + app: An App instance (optional). + + Returns: + UserImportResult: An object summarizing the result of the import operation. + + Raises: + ValueError: If the provided arguments are invalid. + FirebaseError: If an error occurs while importing users. + """ + client = _get_client(app) + return client.import_users(users, hash_alg) + + +def generate_password_reset_link(email, action_code_settings=None, app=None): + """Generates the out-of-band email action link for password reset flows for the specified email + address. + + Args: + email: The email of the user whose password is to be reset. + action_code_settings: ``ActionCodeSettings`` instance (optional). Defines whether + the link is to be handled by a mobile app and the additional state information to be + passed in the deep link. + app: An App instance (optional). + Returns: + link: The password reset link created by the API + + Raises: + ValueError: If the provided arguments are invalid + FirebaseError: If an error occurs while generating the link + """ + client = _get_client(app) + return client.generate_password_reset_link(email, action_code_settings=action_code_settings) + + +def generate_email_verification_link(email, action_code_settings=None, app=None): + """Generates the out-of-band email action link for email verification flows for the specified + email address. + + Args: + email: The email of the user to be verified. + action_code_settings: ``ActionCodeSettings`` instance (optional). Defines whether + the link is to be handled by a mobile app and the additional state information to be + passed in the deep link. + app: An App instance (optional). + Returns: + link: The email verification link created by the API + + Raises: + ValueError: If the provided arguments are invalid + FirebaseError: If an error occurs while generating the link + """ + client = _get_client(app) + return client.generate_email_verification_link( + email, action_code_settings=action_code_settings) + + +def generate_sign_in_with_email_link(email, action_code_settings, app=None): + """Generates the out-of-band email action link for email link sign-in flows, using the action + code settings provided. + + Args: + email: The email of the user signing in. + action_code_settings: ``ActionCodeSettings`` instance. Defines whether + the link is to be handled by a mobile app and the additional state information to be + passed in the deep link. + app: An App instance (optional). + + Returns: + link: The email sign-in link created by the API + + Raises: + ValueError: If the provided arguments are invalid + FirebaseError: If an error occurs while generating the link + """ + client = _get_client(app) + return client.generate_sign_in_with_email_link( + email, action_code_settings=action_code_settings) + + +def get_oidc_provider_config(provider_id, app=None): + """Returns the ``OIDCProviderConfig`` with the given ID. + + Args: + provider_id: Provider ID string. + app: An App instance (optional). + + Returns: + OIDCProviderConfig: An OIDC provider config instance. + + Raises: + ValueError: If the provider ID is invalid, empty or does not have ``oidc.`` prefix. + ConfigurationNotFoundError: If no OIDC provider is available with the given identifier. + FirebaseError: If an error occurs while retrieving the OIDC provider. + """ + client = _get_client(app) + return client.get_oidc_provider_config(provider_id) + +def create_oidc_provider_config( + provider_id, client_id, issuer, display_name=None, enabled=None, app=None): + """Creates a new OIDC provider config from the given parameters. + + OIDC provider support requires Google Cloud's Identity Platform (GCIP). To learn more about + GCIP, including pricing and features, see https://cloud.google.com/identity-platform. + + Args: + provider_id: Provider ID string. Must have the prefix ``oidc.``. + client_id: Client ID of the new config. + issuer: Issuer of the new config. Must be a valid URL. + display_name: The user-friendly display name to the current configuration (optional). + This name is also used as the provider label in the Cloud Console. + enabled: A boolean indicating whether the provider configuration is enabled or disabled + (optional). A user cannot sign in using a disabled provider. + app: An App instance (optional). + + Returns: + OIDCProviderConfig: The newly created OIDC provider config instance. + + Raises: + ValueError: If any of the specified input parameters are invalid. + FirebaseError: If an error occurs while creating the new OIDC provider config. + """ + client = _get_client(app) + return client.create_oidc_provider_config( + provider_id, client_id=client_id, issuer=issuer, display_name=display_name, + enabled=enabled) + + +def update_oidc_provider_config( + provider_id, client_id=None, issuer=None, display_name=None, enabled=None, app=None): + """Updates an existing OIDC provider config with the given parameters. + + Args: + provider_id: Provider ID string. Must have the prefix ``oidc.``. + client_id: Client ID of the new config (optional). + issuer: Issuer of the new config (optional). Must be a valid URL. + display_name: The user-friendly display name of the current configuration (optional). + Pass ``auth.DELETE_ATTRIBUTE`` to delete the current display name. + enabled: A boolean indicating whether the provider configuration is enabled or disabled + (optional). + app: An App instance (optional). + + Returns: + OIDCProviderConfig: The updated OIDC provider config instance. + + Raises: + ValueError: If any of the specified input parameters are invalid. + FirebaseError: If an error occurs while updating the OIDC provider config. + """ + client = _get_client(app) + return client.update_oidc_provider_config( + provider_id, client_id=client_id, issuer=issuer, display_name=display_name, + enabled=enabled) + + +def delete_oidc_provider_config(provider_id, app=None): + """Deletes the ``OIDCProviderConfig`` with the given ID. + + Args: + provider_id: Provider ID string. + app: An App instance (optional). + + Raises: + ValueError: If the provider ID is invalid, empty or does not have ``oidc.`` prefix. + ConfigurationNotFoundError: If no OIDC provider is available with the given identifier. + FirebaseError: If an error occurs while deleting the OIDC provider. + """ + client = _get_client(app) + client.delete_oidc_provider_config(provider_id) + + +def list_oidc_provider_configs( + page_token=None, max_results=_auth_providers.MAX_LIST_CONFIGS_RESULTS, app=None): + """Retrieves a page of OIDC provider configs from a Firebase project. + + The ``page_token`` argument governs the starting point of the page. The ``max_results`` + argument governs the maximum number of configs that may be included in the returned + page. This function never returns ``None``. If there are no OIDC configs in the Firebase + project, this returns an empty page. + + Args: + page_token: A non-empty page token string, which indicates the starting point of the + page (optional). Defaults to ``None``, which will retrieve the first page of users. + max_results: A positive integer indicating the maximum number of users to include in + the returned page (optional). Defaults to 100, which is also the maximum number + allowed. + app: An App instance (optional). + + Returns: + ListProviderConfigsPage: A page of OIDC provider config instances. + + Raises: + ValueError: If ``max_results`` or ``page_token`` are invalid. + FirebaseError: If an error occurs while retrieving the OIDC provider configs. + """ + client = _get_client(app) + return client.list_oidc_provider_configs(page_token, max_results) + + +def get_saml_provider_config(provider_id, app=None): + """Returns the ``SAMLProviderConfig`` with the given ID. + + Args: + provider_id: Provider ID string. + app: An App instance (optional). + + Returns: + SAMLProviderConfig: A SAML provider config instance. + + Raises: + ValueError: If the provider ID is invalid, empty or does not have ``saml.`` prefix. + ConfigurationNotFoundError: If no SAML provider is available with the given identifier. + FirebaseError: If an error occurs while retrieving the SAML provider. + """ + client = _get_client(app) + return client.get_saml_provider_config(provider_id) + + +def create_saml_provider_config( + provider_id, idp_entity_id, sso_url, x509_certificates, rp_entity_id, callback_url, + display_name=None, enabled=None, app=None): + """Creates a new SAML provider config from the given parameters. + + SAML provider support requires Google Cloud's Identity Platform (GCIP). To learn more about + GCIP, including pricing and features, see https://cloud.google.com/identity-platform. + + Args: + provider_id: Provider ID string. Must have the prefix ``saml.``. + idp_entity_id: The SAML IdP entity identifier. + sso_url: The SAML IdP SSO URL. Must be a valid URL. + x509_certificates: The list of SAML IdP X.509 certificates issued by CA for this provider. + Multiple certificates are accepted to prevent outages during IdP key rotation (for + example ADFS rotates every 10 days). When the Auth server receives a SAML response, it + will match the SAML response with the certificate on record. Otherwise the response is + rejected. Developers are expected to manage the certificate updates as keys are + rotated. + rp_entity_id: The SAML relying party (service provider) entity ID. This is defined by the + developer but needs to be provided to the SAML IdP. + callback_url: Callback URL string. This is fixed and must always be the same as the OAuth + redirect URL provisioned by Firebase Auth, unless a custom authDomain is used. + display_name: The user-friendly display name to the current configuration (optional). This + name is also used as the provider label in the Cloud Console. + enabled: A boolean indicating whether the provider configuration is enabled or disabled + (optional). A user cannot sign in using a disabled provider. + app: An App instance (optional). + + Returns: + SAMLProviderConfig: The newly created SAML provider config instance. + + Raises: + ValueError: If any of the specified input parameters are invalid. + FirebaseError: If an error occurs while creating the new SAML provider config. + """ + client = _get_client(app) + return client.create_saml_provider_config( + provider_id, idp_entity_id=idp_entity_id, sso_url=sso_url, + x509_certificates=x509_certificates, rp_entity_id=rp_entity_id, callback_url=callback_url, + display_name=display_name, enabled=enabled) + + +def update_saml_provider_config( + provider_id, idp_entity_id=None, sso_url=None, x509_certificates=None, + rp_entity_id=None, callback_url=None, display_name=None, enabled=None, app=None): + """Updates an existing SAML provider config with the given parameters. + + Args: + provider_id: Provider ID string. Must have the prefix ``saml.``. + idp_entity_id: The SAML IdP entity identifier (optional). + sso_url: The SAML IdP SSO URL. Must be a valid URL (optional). + x509_certificates: The list of SAML IdP X.509 certificates issued by CA for this + provider (optional). + rp_entity_id: The SAML relying party entity ID (optional). + callback_url: Callback URL string (optional). + display_name: The user-friendly display name of the current configuration (optional). + Pass ``auth.DELETE_ATTRIBUTE`` to delete the current display name. + enabled: A boolean indicating whether the provider configuration is enabled or disabled + (optional). + app: An App instance (optional). + + Returns: + SAMLProviderConfig: The updated SAML provider config instance. + + Raises: + ValueError: If any of the specified input parameters are invalid. + FirebaseError: If an error occurs while updating the SAML provider config. + """ + client = _get_client(app) + return client.update_saml_provider_config( + provider_id, idp_entity_id=idp_entity_id, sso_url=sso_url, + x509_certificates=x509_certificates, rp_entity_id=rp_entity_id, + callback_url=callback_url, display_name=display_name, enabled=enabled) + + +def delete_saml_provider_config(provider_id, app=None): + """Deletes the ``SAMLProviderConfig`` with the given ID. + + Args: + provider_id: Provider ID string. + app: An App instance (optional). + + Raises: + ValueError: If the provider ID is invalid, empty or does not have ``saml.`` prefix. + ConfigurationNotFoundError: If no SAML provider is available with the given identifier. + FirebaseError: If an error occurs while deleting the SAML provider. + """ + client = _get_client(app) + client.delete_saml_provider_config(provider_id) + + +def list_saml_provider_configs( + page_token=None, max_results=_auth_providers.MAX_LIST_CONFIGS_RESULTS, app=None): + """Retrieves a page of SAML provider configs from a Firebase project. + + The ``page_token`` argument governs the starting point of the page. The ``max_results`` + argument governs the maximum number of configs that may be included in the returned + page. This function never returns ``None``. If there are no SAML configs in the Firebase + project, this returns an empty page. + + Args: + page_token: A non-empty page token string, which indicates the starting point of the + page (optional). Defaults to ``None``, which will retrieve the first page of users. + max_results: A positive integer indicating the maximum number of users to include in + the returned page (optional). Defaults to 100, which is also the maximum number + allowed. + app: An App instance (optional). + + Returns: + ListProviderConfigsPage: A page of SAML provider config instances. + + Raises: + ValueError: If ``max_results`` or ``page_token`` are invalid. + FirebaseError: If an error occurs while retrieving the SAML provider configs. + """ + client = _get_client(app) + return client.list_saml_provider_configs(page_token, max_results) diff --git a/venv/Lib/site-packages/firebase_admin/credentials.py b/venv/Lib/site-packages/firebase_admin/credentials.py new file mode 100644 index 000000000..8f9c504f0 --- /dev/null +++ b/venv/Lib/site-packages/firebase_admin/credentials.py @@ -0,0 +1,214 @@ +# Copyright 2017 Google Inc. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +"""Firebase credentials module.""" +import collections +import json + +import google.auth +from google.auth.transport import requests +from google.oauth2 import credentials +from google.oauth2 import service_account + + +_request = requests.Request() +_scopes = [ + 'https://www.googleapis.com/auth/cloud-platform', + 'https://www.googleapis.com/auth/datastore', + 'https://www.googleapis.com/auth/devstorage.read_write', + 'https://www.googleapis.com/auth/firebase', + 'https://www.googleapis.com/auth/identitytoolkit', + 'https://www.googleapis.com/auth/userinfo.email' +] + +AccessTokenInfo = collections.namedtuple('AccessTokenInfo', ['access_token', 'expiry']) +"""Data included in an OAuth2 access token. + +Contains the access token string and the expiry time. The expirty time is exposed as a +``datetime`` value. +""" + + +class Base: + """Provides OAuth2 access tokens for accessing Firebase services.""" + + def get_access_token(self): + """Fetches a Google OAuth2 access token using this credential instance. + + Returns: + AccessTokenInfo: An access token obtained using the credential. + """ + google_cred = self.get_credential() + google_cred.refresh(_request) + return AccessTokenInfo(google_cred.token, google_cred.expiry) + + def get_credential(self): + """Returns the Google credential instance used for authentication.""" + raise NotImplementedError + + +class Certificate(Base): + """A credential initialized from a JSON certificate keyfile.""" + + _CREDENTIAL_TYPE = 'service_account' + + def __init__(self, cert): + """Initializes a credential from a Google service account certificate. + + Service account certificates can be downloaded as JSON files from the Firebase console. + To instantiate a credential from a certificate file, either specify the file path or a + dict representing the parsed contents of the file. + + Args: + cert: Path to a certificate file or a dict representing the contents of a certificate. + + Raises: + IOError: If the specified certificate file doesn't exist or cannot be read. + ValueError: If the specified certificate is invalid. + """ + super(Certificate, self).__init__() + if isinstance(cert, str): + with open(cert) as json_file: + json_data = json.load(json_file) + elif isinstance(cert, dict): + json_data = cert + else: + raise ValueError( + 'Invalid certificate argument: "{0}". Certificate argument must be a file path, ' + 'or a dict containing the parsed file contents.'.format(cert)) + + if json_data.get('type') != self._CREDENTIAL_TYPE: + raise ValueError('Invalid service account certificate. Certificate must contain a ' + '"type" field set to "{0}".'.format(self._CREDENTIAL_TYPE)) + try: + self._g_credential = service_account.Credentials.from_service_account_info( + json_data, scopes=_scopes) + except ValueError as error: + raise ValueError('Failed to initialize a certificate credential. ' + 'Caused by: "{0}"'.format(error)) + + @property + def project_id(self): + return self._g_credential.project_id + + @property + def signer(self): + return self._g_credential.signer + + @property + def service_account_email(self): + return self._g_credential.service_account_email + + def get_credential(self): + """Returns the underlying Google credential. + + Returns: + google.auth.credentials.Credentials: A Google Auth credential instance.""" + return self._g_credential + + +class ApplicationDefault(Base): + """A Google Application Default credential.""" + + def __init__(self): + """Creates an instance that will use Application Default credentials. + + The credentials will be lazily initialized when get_credential() or + project_id() is called. See those methods for possible errors raised. + """ + super(ApplicationDefault, self).__init__() + self._g_credential = None # Will be lazily-loaded via _load_credential(). + + def get_credential(self): + """Returns the underlying Google credential. + + Raises: + google.auth.exceptions.DefaultCredentialsError: If Application Default + credentials cannot be initialized in the current environment. + Returns: + google.auth.credentials.Credentials: A Google Auth credential instance.""" + self._load_credential() + return self._g_credential + + @property + def project_id(self): + """Returns the project_id from the underlying Google credential. + + Raises: + google.auth.exceptions.DefaultCredentialsError: If Application Default + credentials cannot be initialized in the current environment. + Returns: + str: The project id.""" + self._load_credential() + return self._project_id + + def _load_credential(self): + if not self._g_credential: + self._g_credential, self._project_id = google.auth.default(scopes=_scopes) + +class RefreshToken(Base): + """A credential initialized from an existing refresh token.""" + + _CREDENTIAL_TYPE = 'authorized_user' + + def __init__(self, refresh_token): + """Initializes a credential from a refresh token JSON file. + + The JSON must consist of client_id, client_secert and refresh_token fields. Refresh + token files are typically created and managed by the gcloud SDK. To instantiate + a credential from a refresh token file, either specify the file path or a dict + representing the parsed contents of the file. + + Args: + refresh_token: Path to a refresh token file or a dict representing the contents of a + refresh token file. + + Raises: + IOError: If the specified file doesn't exist or cannot be read. + ValueError: If the refresh token configuration is invalid. + """ + super(RefreshToken, self).__init__() + if isinstance(refresh_token, str): + with open(refresh_token) as json_file: + json_data = json.load(json_file) + elif isinstance(refresh_token, dict): + json_data = refresh_token + else: + raise ValueError( + 'Invalid refresh token argument: "{0}". Refresh token argument must be a file ' + 'path, or a dict containing the parsed file contents.'.format(refresh_token)) + + if json_data.get('type') != self._CREDENTIAL_TYPE: + raise ValueError('Invalid refresh token configuration. JSON must contain a ' + '"type" field set to "{0}".'.format(self._CREDENTIAL_TYPE)) + self._g_credential = credentials.Credentials.from_authorized_user_info(json_data, _scopes) + + @property + def client_id(self): + return self._g_credential.client_id + + @property + def client_secret(self): + return self._g_credential.client_secret + + @property + def refresh_token(self): + return self._g_credential.refresh_token + + def get_credential(self): + """Returns the underlying Google credential. + + Returns: + google.auth.credentials.Credentials: A Google Auth credential instance.""" + return self._g_credential diff --git a/venv/Lib/site-packages/firebase_admin/db.py b/venv/Lib/site-packages/firebase_admin/db.py new file mode 100644 index 000000000..be2b9c917 --- /dev/null +++ b/venv/Lib/site-packages/firebase_admin/db.py @@ -0,0 +1,991 @@ +# Copyright 2017 Google Inc. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +"""Firebase Realtime Database module. + +This module contains functions and classes that facilitate interacting with the Firebase Realtime +Database. It supports basic data manipulation operations, as well as complex queries such as +limit queries and range queries. However, it does not support realtime update notifications. This +module uses the Firebase REST API underneath. +""" + +import collections +import json +import os +import sys +import threading +from urllib import parse + +import google.auth +import requests + +import firebase_admin +from firebase_admin import exceptions +from firebase_admin import _http_client +from firebase_admin import _sseclient +from firebase_admin import _utils + + +_DB_ATTRIBUTE = '_database' +_INVALID_PATH_CHARACTERS = '[].?#$' +_RESERVED_FILTERS = ('$key', '$value', '$priority') +_USER_AGENT = 'Firebase/HTTP/{0}/{1}.{2}/AdminPython'.format( + firebase_admin.__version__, sys.version_info.major, sys.version_info.minor) +_TRANSACTION_MAX_RETRIES = 25 +_EMULATOR_HOST_ENV_VAR = 'FIREBASE_DATABASE_EMULATOR_HOST' + + +def reference(path='/', app=None, url=None): + """Returns a database ``Reference`` representing the node at the specified path. + + If no path is specified, this function returns a ``Reference`` that represents the database + root. By default, the returned References provide access to the Firebase Database specified at + app initialization. To connect to a different database instance in the same Firebase project, + specify the ``url`` parameter. + + Args: + path: Path to a node in the Firebase realtime database (optional). + app: An App instance (optional). + url: Base URL of the Firebase Database instance (optional). When specified, takes + precedence over the the ``databaseURL`` option set at app initialization. + + Returns: + Reference: A newly initialized Reference. + + Raises: + ValueError: If the specified path or app is invalid. + """ + service = _utils.get_app_service(app, _DB_ATTRIBUTE, _DatabaseService) + client = service.get_client(url) + return Reference(client=client, path=path) + +def _parse_path(path): + """Parses a path string into a set of segments.""" + if not isinstance(path, str): + raise ValueError('Invalid path: "{0}". Path must be a string.'.format(path)) + if any(ch in path for ch in _INVALID_PATH_CHARACTERS): + raise ValueError( + 'Invalid path: "{0}". Path contains illegal characters.'.format(path)) + return [seg for seg in path.split('/') if seg] + + +class Event: + """Represents a realtime update event received from the database.""" + + def __init__(self, sse_event): + self._sse_event = sse_event + self._data = json.loads(sse_event.data) + + @property + def data(self): + """Parsed JSON data of this event.""" + return self._data['data'] + + @property + def path(self): + """Path of the database reference that triggered this event.""" + return self._data['path'] + + @property + def event_type(self): + """Event type string (put, patch).""" + return self._sse_event.event_type + + +class ListenerRegistration: + """Represents the addition of an event listener to a database reference.""" + + def __init__(self, callback, sse): + """Initializes a new listener with given parameters. + + This is an internal API. Use the ``db.Reference.listen()`` method to start a + new listener. + + Args: + callback: The callback function to fire in case of event. + sse: A transport session to make requests with. + """ + self._callback = callback + self._sse = sse + self._thread = threading.Thread(target=self._start_listen) + self._thread.start() + + def _start_listen(self): + # iterate the sse client's generator + for sse_event in self._sse: + # only inject data events + if sse_event: + self._callback(Event(sse_event)) + + def close(self): + """Stops the event listener represented by this registration + + This closes the SSE HTTP connection, and joins the background thread. + """ + self._sse.close() + self._thread.join() + + +class Reference: + """Reference represents a node in the Firebase realtime database.""" + + def __init__(self, **kwargs): + """Creates a new Reference using the provided parameters. + + This method is for internal use only. Use db.reference() to obtain an instance of + Reference. + """ + self._client = kwargs.get('client') + if 'segments' in kwargs: + self._segments = kwargs.get('segments') + else: + self._segments = _parse_path(kwargs.get('path')) + self._pathurl = '/' + '/'.join(self._segments) + + @property + def key(self): + if self._segments: + return self._segments[-1] + return None + + @property + def path(self): + return self._pathurl + + @property + def parent(self): + if self._segments: + return Reference(client=self._client, segments=self._segments[:-1]) + return None + + def child(self, path): + """Returns a Reference to the specified child node. + + The path may point to an immediate child of the current Reference, or a deeply nested + child. Child paths must not begin with '/'. + + Args: + path: Path to the child node. + + Returns: + Reference: A database Reference representing the specified child node. + + Raises: + ValueError: If the child path is not a string, not well-formed or begins with '/'. + """ + if not path or not isinstance(path, str): + raise ValueError( + 'Invalid path argument: "{0}". Path must be a non-empty string.'.format(path)) + if path.startswith('/'): + raise ValueError( + 'Invalid path argument: "{0}". Child path must not start with "/"'.format(path)) + full_path = self._pathurl + '/' + path + return Reference(client=self._client, path=full_path) + + def get(self, etag=False, shallow=False): + """Returns the value, and optionally the ETag, at the current location of the database. + + Args: + etag: A boolean indicating whether the Etag value should be returned or not (optional). + shallow: A boolean indicating whether to execute a shallow read (optional). Shallow + reads do not retrieve the child nodes of the current database location. Cannot be + set to True if ``etag`` is also set to True. + + Returns: + object: If etag is False returns the decoded JSON value of the current database location. + If etag is True, returns a 2-tuple consisting of the decoded JSON value and the Etag + associated with the current database location. + + Raises: + ValueError: If both ``etag`` and ``shallow`` are set to True. + FirebaseError: If an error occurs while communicating with the remote database server. + """ + if etag: + if shallow: + raise ValueError('etag and shallow cannot both be set to True.') + headers, data = self._client.headers_and_body( + 'get', self._add_suffix(), headers={'X-Firebase-ETag' : 'true'}) + return data, headers.get('ETag') + + params = 'shallow=true' if shallow else None + return self._client.body('get', self._add_suffix(), params=params) + + def get_if_changed(self, etag): + """Gets data in this location only if the specified ETag does not match. + + Args: + etag: The ETag value to be checked against the ETag of the current location. + + Returns: + tuple: A 3-tuple consisting of a boolean, a decoded JSON value and an ETag. If the ETag + specified by the caller did not match, the boolen value will be True and the JSON + and ETag values would reflect the corresponding values in the database. If the ETag + matched, the boolean value will be False and the other elements of the tuple will be + None. + + Raises: + ValueError: If the ETag is not a string. + FirebaseError: If an error occurs while communicating with the remote database server. + """ + if not isinstance(etag, str): + raise ValueError('ETag must be a string.') + + resp = self._client.request('get', self._add_suffix(), headers={'if-none-match': etag}) + if resp.status_code == 304: + return False, None, None + + return True, resp.json(), resp.headers.get('ETag') + + def set(self, value): + """Sets the data at this location to the given value. + + The value must be JSON-serializable and not None. + + Args: + value: JSON-serializable value to be set at this location. + + Raises: + ValueError: If the provided value is None. + TypeError: If the value is not JSON-serializable. + FirebaseError: If an error occurs while communicating with the remote database server. + """ + if value is None: + raise ValueError('Value must not be None.') + self._client.request('put', self._add_suffix(), json=value, params='print=silent') + + def set_if_unchanged(self, expected_etag, value): + """Conditonally sets the data at this location to the given value. + + Sets the data at this location to the given value only if ``expected_etag`` is same as the + ETag value in the database. + + Args: + expected_etag: Value of ETag we want to check. + value: JSON-serializable value to be set at this location. + + Returns: + tuple: A 3-tuple consisting of a boolean, a decoded JSON value and an ETag. The boolean + indicates whether the set operation was successful or not. The decoded JSON and the + ETag corresponds to the latest value in this database location. + + Raises: + ValueError: If the value is None, or if expected_etag is not a string. + FirebaseError: If an error occurs while communicating with the remote database server. + """ + # pylint: disable=missing-raises-doc + if not isinstance(expected_etag, str): + raise ValueError('Expected ETag must be a string.') + if value is None: + raise ValueError('Value must not be none.') + + try: + headers = self._client.headers( + 'put', self._add_suffix(), json=value, headers={'if-match': expected_etag}) + return True, value, headers.get('ETag') + except exceptions.FailedPreconditionError as error: + http_response = error.http_response + if http_response is not None and 'ETag' in http_response.headers: + etag = http_response.headers['ETag'] + snapshot = http_response.json() + return False, snapshot, etag + + raise error + + def push(self, value=''): + """Creates a new child node. + + The optional value argument can be used to provide an initial value for the child node. If + no value is provided, child node will have empty string as the default value. + + Args: + value: JSON-serializable initial value for the child node (optional). + + Returns: + Reference: A Reference representing the newly created child node. + + Raises: + ValueError: If the value is None. + TypeError: If the value is not JSON-serializable. + FirebaseError: If an error occurs while communicating with the remote database server. + """ + if value is None: + raise ValueError('Value must not be None.') + output = self._client.body('post', self._add_suffix(), json=value) + push_id = output.get('name') + return self.child(push_id) + + def update(self, value): + """Updates the specified child keys of this Reference to the provided values. + + Args: + value: A dictionary containing the child keys to update, and their new values. + + Raises: + ValueError: If value is empty or not a dictionary. + FirebaseError: If an error occurs while communicating with the remote database server. + """ + if not value or not isinstance(value, dict): + raise ValueError('Value argument must be a non-empty dictionary.') + if None in value.keys(): + raise ValueError('Dictionary must not contain None keys.') + self._client.request('patch', self._add_suffix(), json=value, params='print=silent') + + def delete(self): + """Deletes this node from the database. + + Raises: + FirebaseError: If an error occurs while communicating with the remote database server. + """ + self._client.request('delete', self._add_suffix()) + + def listen(self, callback): + """Registers the ``callback`` function to receive realtime updates. + + The specified callback function will get invoked with ``db.Event`` objects for each + realtime update received from the database. It will also get called whenever the SDK + reconnects to the server due to network issues or credential expiration. In general, + the OAuth2 credentials used to authorize connections to the server expire every hour. + Therefore clients should expect the ``callback`` to fire at least once every hour, even if + there are no updates in the database. + + This API is based on the event streaming support available in the Firebase REST API. Each + call to ``listen()`` starts a new HTTP connection and a background thread. This is an + experimental feature. It currently does not honor the auth overrides and timeout settings. + Cannot be used in thread-constrained environments like Google App Engine. + + Args: + callback: A function to be called when a data change is detected. + + Returns: + ListenerRegistration: An object that can be used to stop the event listener. + + Raises: + FirebaseError: If an error occurs while starting the initial HTTP connection. + """ + return self._listen_with_session(callback) + + def transaction(self, transaction_update): + """Atomically modifies the data at this location. + + Unlike a normal ``set()``, which just overwrites the data regardless of its previous state, + ``transaction()`` is used to modify the existing value to a new value, ensuring there are + no conflicts with other clients simultaneously writing to the same location. + + This is accomplished by passing an update function which is used to transform the current + value of this reference into a new value. If another client writes to this location before + the new value is successfully saved, the update function is called again with the new + current value, and the write will be retried. In case of repeated failures, this method + will retry the transaction up to 25 times before giving up and raising a + TransactionAbortedError. The update function may also force an early abort by raising an + exception instead of returning a value. + + Args: + transaction_update: A function which will be passed the current data stored at this + location. The function should return the new value it would like written. If + an exception is raised, the transaction will be aborted, and the data at this + location will not be modified. The exceptions raised by this function are + propagated to the caller of the transaction method. + + Returns: + object: New value of the current database Reference (only if the transaction commits). + + Raises: + TransactionAbortedError: If the transaction aborts after exhausting all retry attempts. + ValueError: If transaction_update is not a function. + """ + if not callable(transaction_update): + raise ValueError('transaction_update must be a function.') + + tries = 0 + data, etag = self.get(etag=True) + while tries < _TRANSACTION_MAX_RETRIES: + new_data = transaction_update(data) + success, data, etag = self.set_if_unchanged(etag, new_data) + if success: + return new_data + tries += 1 + + raise TransactionAbortedError('Transaction aborted after failed retries.') + + def order_by_child(self, path): + """Returns a Query that orders data by child values. + + Returned Query can be used to set additional parameters, and execute complex database + queries (e.g. limit queries, range queries). + + Args: + path: Path to a valid child of the current Reference. + + Returns: + Query: A database Query instance. + + Raises: + ValueError: If the child path is not a string, not well-formed or None. + """ + if path in _RESERVED_FILTERS: + raise ValueError('Illegal child path: {0}'.format(path)) + return Query(order_by=path, client=self._client, pathurl=self._add_suffix()) + + def order_by_key(self): + """Creates a Query that orderes data by key. + + Returned Query can be used to set additional parameters, and execute complex database + queries (e.g. limit queries, range queries). + + Returns: + Query: A database Query instance. + """ + return Query(order_by='$key', client=self._client, pathurl=self._add_suffix()) + + def order_by_value(self): + """Creates a Query that orderes data by value. + + Returned Query can be used to set additional parameters, and execute complex database + queries (e.g. limit queries, range queries). + + Returns: + Query: A database Query instance. + """ + return Query(order_by='$value', client=self._client, pathurl=self._add_suffix()) + + def _add_suffix(self, suffix='.json'): + return self._pathurl + suffix + + def _listen_with_session(self, callback, session=None): + url = self._client.base_url + self._add_suffix() + if not session: + session = self._client.create_listener_session() + + try: + sse = _sseclient.SSEClient(url, session) + return ListenerRegistration(callback, sse) + except requests.exceptions.RequestException as error: + raise _Client.handle_rtdb_error(error) + + +class Query: + """Represents a complex query that can be executed on a Reference. + + Complex queries can consist of up to 2 components: a required ordering constraint, and an + optional filtering constraint. At the server, data is first sorted according to the given + ordering constraint (e.g. order by child). Then the filtering constraint (e.g. limit, range) + is applied on the sorted data to produce the final result. Despite the ordering constraint, + the final result is returned by the server as an unordered collection. Therefore the Query + interface performs another round of sorting at the client-side before returning the results + to the caller. This client-side sorted results are returned to the user as a Python + OrderedDict. + """ + + def __init__(self, **kwargs): + order_by = kwargs.pop('order_by') + if not order_by or not isinstance(order_by, str): + raise ValueError('order_by field must be a non-empty string') + if order_by not in _RESERVED_FILTERS: + if order_by.startswith('/'): + raise ValueError('Invalid path argument: "{0}". Child path must not start ' + 'with "/"'.format(order_by)) + segments = _parse_path(order_by) + order_by = '/'.join(segments) + self._client = kwargs.pop('client') + self._pathurl = kwargs.pop('pathurl') + self._order_by = order_by + self._params = {'orderBy' : json.dumps(order_by)} + if kwargs: + raise ValueError('Unexpected keyword arguments: {0}'.format(kwargs)) + + def limit_to_first(self, limit): + """Creates a query with limit, and anchors it to the start of the window. + + Args: + limit: The maximum number of child nodes to return. + + Returns: + Query: The updated Query instance. + + Raises: + ValueError: If the value is not an integer, or set_limit_last() was called previously. + """ + if not isinstance(limit, int) or limit < 0: + raise ValueError('Limit must be a non-negative integer.') + if 'limitToLast' in self._params: + raise ValueError('Cannot set both first and last limits.') + self._params['limitToFirst'] = limit + return self + + def limit_to_last(self, limit): + """Creates a query with limit, and anchors it to the end of the window. + + Args: + limit: The maximum number of child nodes to return. + + Returns: + Query: The updated Query instance. + + Raises: + ValueError: If the value is not an integer, or set_limit_first() was called previously. + """ + if not isinstance(limit, int) or limit < 0: + raise ValueError('Limit must be a non-negative integer.') + if 'limitToFirst' in self._params: + raise ValueError('Cannot set both first and last limits.') + self._params['limitToLast'] = limit + return self + + def start_at(self, start): + """Sets the lower bound for a range query. + + The Query will only return child nodes with a value greater than or equal to the specified + value. + + Args: + start: JSON-serializable value to start at, inclusive. + + Returns: + Query: The updated Query instance. + + Raises: + ValueError: If the value is ``None``. + """ + if start is None: + raise ValueError('Start value must not be None.') + self._params['startAt'] = json.dumps(start) + return self + + def end_at(self, end): + """Sets the upper bound for a range query. + + The Query will only return child nodes with a value less than or equal to the specified + value. + + Args: + end: JSON-serializable value to end at, inclusive. + + Returns: + Query: The updated Query instance. + + Raises: + ValueError: If the value is ``None``. + """ + if end is None: + raise ValueError('End value must not be None.') + self._params['endAt'] = json.dumps(end) + return self + + def equal_to(self, value): + """Sets an equals constraint on the Query. + + The Query will only return child nodes whose value is equal to the specified value. + + Args: + value: JSON-serializable value to query for. + + Returns: + Query: The updated Query instance. + + Raises: + ValueError: If the value is ``None``. + """ + if value is None: + raise ValueError('Equal to value must not be None.') + self._params['equalTo'] = json.dumps(value) + return self + + @property + def _querystr(self): + params = [] + for key in sorted(self._params): + params.append('{0}={1}'.format(key, self._params[key])) + return '&'.join(params) + + def get(self): + """Executes this Query and returns the results. + + The results will be returned as a sorted list or an OrderedDict. + + Returns: + object: Decoded JSON result of the Query. + + Raises: + FirebaseError: If an error occurs while communicating with the remote database server. + """ + result = self._client.body('get', self._pathurl, params=self._querystr) + if isinstance(result, (dict, list)) and self._order_by != '$priority': + return _Sorter(result, self._order_by).get() + return result + + +class TransactionAbortedError(exceptions.AbortedError): + """A transaction was aborted aftr exceeding the maximum number of retries.""" + + def __init__(self, message): + exceptions.AbortedError.__init__(self, message) + + +class _Sorter: + """Helper class for sorting query results.""" + + def __init__(self, results, order_by): + if isinstance(results, dict): + self.dict_input = True + entries = [_SortEntry(k, v, order_by) for k, v in results.items()] + elif isinstance(results, list): + self.dict_input = False + entries = [_SortEntry(k, v, order_by) for k, v in enumerate(results)] + else: + raise ValueError('Sorting not supported for "{0}" object.'.format(type(results))) + self.sort_entries = sorted(entries) + + def get(self): + if self.dict_input: + return collections.OrderedDict([(e.key, e.value) for e in self.sort_entries]) + + return [e.value for e in self.sort_entries] + + +class _SortEntry: + """A wrapper that is capable of sorting items in a dictionary.""" + + _type_none = 0 + _type_bool_false = 1 + _type_bool_true = 2 + _type_numeric = 3 + _type_string = 4 + _type_object = 5 + + def __init__(self, key, value, order_by): + self._key = key + self._value = value + if order_by in ('$key', '$priority'): + self._index = key + elif order_by == '$value': + self._index = value + else: + self._index = _SortEntry._extract_child(value, order_by) + self._index_type = _SortEntry._get_index_type(self._index) + + @property + def key(self): + return self._key + + @property + def index(self): + return self._index + + @property + def index_type(self): + return self._index_type + + @property + def value(self): + return self._value + + @classmethod + def _get_index_type(cls, index): + """Assigns an integer code to the type of the index. + + The index type determines how differently typed values are sorted. This ordering is based + on https://firebase.google.com/docs/database/rest/retrieve-data#section-rest-ordered-data + """ + if index is None: + return cls._type_none + if isinstance(index, bool) and not index: + return cls._type_bool_false + if isinstance(index, bool) and index: + return cls._type_bool_true + if isinstance(index, (int, float)): + return cls._type_numeric + if isinstance(index, str): + return cls._type_string + + return cls._type_object + + @classmethod + def _extract_child(cls, value, path): + segments = path.split('/') + current = value + for segment in segments: + if isinstance(current, dict): + current = current.get(segment) + else: + return None + return current + + def _compare(self, other): + """Compares two _SortEntry instances. + + If the indices have the same numeric or string type, compare them directly. Ties are + broken by comparing the keys. If the indices have the same type, but are neither numeric + nor string, compare the keys. In all other cases compare based on the ordering provided + by index types. + """ + self_key, other_key = self.index_type, other.index_type + if self_key == other_key: + if self_key in (self._type_numeric, self._type_string) and self.index != other.index: + self_key, other_key = self.index, other.index + else: + self_key, other_key = self.key, other.key + + if self_key < other_key: + return -1 + if self_key > other_key: + return 1 + + return 0 + + def __lt__(self, other): + return self._compare(other) < 0 + + def __le__(self, other): + return self._compare(other) <= 0 + + def __gt__(self, other): + return self._compare(other) > 0 + + def __ge__(self, other): + return self._compare(other) >= 0 + + def __eq__(self, other): + return self._compare(other) == 0 + + +class _DatabaseService: + """Service that maintains a collection of database clients.""" + + _DEFAULT_AUTH_OVERRIDE = '_admin_' + + def __init__(self, app): + self._credential = app.credential + db_url = app.options.get('databaseURL') + if db_url: + _DatabaseService._parse_db_url(db_url) # Just for validation. + self._db_url = db_url + else: + self._db_url = None + auth_override = _DatabaseService._get_auth_override(app) + if auth_override not in (self._DEFAULT_AUTH_OVERRIDE, {}): + self._auth_override = json.dumps(auth_override, separators=(',', ':')) + else: + self._auth_override = None + self._timeout = app.options.get('httpTimeout', _http_client.DEFAULT_TIMEOUT_SECONDS) + self._clients = {} + + emulator_host = os.environ.get(_EMULATOR_HOST_ENV_VAR) + if emulator_host: + if '//' in emulator_host: + raise ValueError( + 'Invalid {0}: "{1}". It must follow format "host:port".'.format( + _EMULATOR_HOST_ENV_VAR, emulator_host)) + self._emulator_host = emulator_host + else: + self._emulator_host = None + + def get_client(self, db_url=None): + """Creates a client based on the db_url. Clients may be cached.""" + if db_url is None: + db_url = self._db_url + + base_url, namespace = _DatabaseService._parse_db_url(db_url, self._emulator_host) + if base_url == 'https://{0}.firebaseio.com'.format(namespace): + # Production base_url. No need to specify namespace in query params. + params = {} + credential = self._credential.get_credential() + else: + # Emulator base_url. Use fake credentials and specify ?ns=foo in query params. + credential = _EmulatorAdminCredentials() + params = {'ns': namespace} + if self._auth_override: + params['auth_variable_override'] = self._auth_override + + client_cache_key = (base_url, json.dumps(params, sort_keys=True)) + if client_cache_key not in self._clients: + client = _Client(credential, base_url, self._timeout, params) + self._clients[client_cache_key] = client + return self._clients[client_cache_key] + + @classmethod + def _parse_db_url(cls, url, emulator_host=None): + """Parses (base_url, namespace) from a database URL. + + The input can be either a production URL (https://foo-bar.firebaseio.com/) + or an Emulator URL (http://localhost:8080/?ns=foo-bar). In case of Emulator + URL, the namespace is extracted from the query param ns. The resulting + base_url never includes query params. + + If url is a production URL and emulator_host is specified, the result + base URL will use emulator_host instead. emulator_host is ignored + if url is already an emulator URL. + """ + if not url or not isinstance(url, str): + raise ValueError( + 'Invalid database URL: "{0}". Database URL must be a non-empty ' + 'URL string.'.format(url)) + parsed_url = parse.urlparse(url) + if parsed_url.netloc.endswith('.firebaseio.com'): + return cls._parse_production_url(parsed_url, emulator_host) + + return cls._parse_emulator_url(parsed_url) + + @classmethod + def _parse_production_url(cls, parsed_url, emulator_host): + """Parses production URL like https://foo-bar.firebaseio.com/""" + if parsed_url.scheme != 'https': + raise ValueError( + 'Invalid database URL scheme: "{0}". Database URL must be an HTTPS URL.'.format( + parsed_url.scheme)) + namespace = parsed_url.netloc.split('.')[0] + if not namespace: + raise ValueError( + 'Invalid database URL: "{0}". Database URL must be a valid URL to a ' + 'Firebase Realtime Database instance.'.format(parsed_url.geturl())) + + if emulator_host: + base_url = 'http://{0}'.format(emulator_host) + else: + base_url = 'https://{0}'.format(parsed_url.netloc) + return base_url, namespace + + @classmethod + def _parse_emulator_url(cls, parsed_url): + """Parses emulator URL like http://localhost:8080/?ns=foo-bar""" + query_ns = parse.parse_qs(parsed_url.query).get('ns') + if parsed_url.scheme != 'http' or (not query_ns or len(query_ns) != 1 or not query_ns[0]): + raise ValueError( + 'Invalid database URL: "{0}". Database URL must be a valid URL to a ' + 'Firebase Realtime Database instance.'.format(parsed_url.geturl())) + + namespace = query_ns[0] + base_url = '{0}://{1}'.format(parsed_url.scheme, parsed_url.netloc) + return base_url, namespace + + @classmethod + def _get_auth_override(cls, app): + auth_override = app.options.get('databaseAuthVariableOverride', cls._DEFAULT_AUTH_OVERRIDE) + if auth_override == cls._DEFAULT_AUTH_OVERRIDE or auth_override is None: + return auth_override + if not isinstance(auth_override, dict): + raise ValueError('Invalid databaseAuthVariableOverride option: "{0}". Override ' + 'value must be a dict or None.'.format(auth_override)) + + return auth_override + + def close(self): + for value in self._clients.values(): + value.close() + self._clients = {} + + +class _Client(_http_client.JsonHttpClient): + """HTTP client used to make REST calls. + + _Client maintains an HTTP session, and handles authenticating HTTP requests along with + marshalling and unmarshalling of JSON data. + """ + + def __init__(self, credential, base_url, timeout, params=None): + """Creates a new _Client from the given parameters. + + This exists primarily to enable testing. For regular use, obtain _Client instances by + calling the from_app() class method. + + Args: + credential: A Google credential that can be used to authenticate requests. + base_url: A URL prefix to be added to all outgoing requests. This is typically the + Firebase Realtime Database URL. + timeout: HTTP request timeout in seconds. If set to None connections will never + timeout, which is the default behavior of the underlying requests library. + params: Dict of query parameters to add to all outgoing requests. + """ + super().__init__( + credential=credential, base_url=base_url, + timeout=timeout, headers={'User-Agent': _USER_AGENT}) + self.credential = credential + self.params = params if params else {} + + def request(self, method, url, **kwargs): + """Makes an HTTP call using the Python requests library. + + Extends the request() method of the parent JsonHttpClient class. Handles default + params like auth overrides, and low-level exceptions. + + Args: + method: HTTP method name as a string (e.g. get, post). + url: URL path of the remote endpoint. This will be appended to the server's base URL. + kwargs: An additional set of keyword arguments to be passed into requests API + (e.g. json, params). + + Returns: + Response: An HTTP response object. + + Raises: + FirebaseError: If an error occurs while making the HTTP call. + """ + query = '&'.join('{0}={1}'.format(key, self.params[key]) for key in self.params) + extra_params = kwargs.get('params') + if extra_params: + if query: + query = extra_params + '&' + query + else: + query = extra_params + kwargs['params'] = query + + try: + return super(_Client, self).request(method, url, **kwargs) + except requests.exceptions.RequestException as error: + raise _Client.handle_rtdb_error(error) + + def create_listener_session(self): + return _sseclient.KeepAuthSession(self.credential) + + @classmethod + def handle_rtdb_error(cls, error): + """Converts an error encountered while calling RTDB into a FirebaseError.""" + if error.response is None: + return _utils.handle_requests_error(error) + + message = cls._extract_error_message(error.response) + return _utils.handle_requests_error(error, message=message) + + @classmethod + def _extract_error_message(cls, response): + """Extracts an error message from an error response. + + If the server has sent a JSON response with an 'error' field, which is the typical + behavior of the Realtime Database REST API, parses the response to retrieve the error + message. If the server has sent a non-JSON response, returns the full response + as the error message. + """ + message = None + try: + # RTDB error format: {"error": "text message"} + data = response.json() + if isinstance(data, dict): + message = data.get('error') + except ValueError: + pass + + if not message: + message = 'Unexpected response from database: {0}'.format(response.content.decode()) + + return message + +# Temporarily disable the lint rule. For more information see: +# https://github.com/googleapis/google-auth-library-python/pull/561 +# pylint: disable=abstract-method +class _EmulatorAdminCredentials(google.auth.credentials.Credentials): + def __init__(self): + google.auth.credentials.Credentials.__init__(self) + self.token = 'owner' + + def refresh(self, request): + pass diff --git a/venv/Lib/site-packages/firebase_admin/exceptions.py b/venv/Lib/site-packages/firebase_admin/exceptions.py new file mode 100644 index 000000000..06504225f --- /dev/null +++ b/venv/Lib/site-packages/firebase_admin/exceptions.py @@ -0,0 +1,237 @@ +# Copyright 2019 Google Inc. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +"""Firebase Exceptions module. + +This module defines the base types for exceptions and the platform-wide error codes as outlined in +https://cloud.google.com/apis/design/errors. + +:class:`FirebaseError` is the parent class of all exceptions raised by the Admin SDK. It contains +the ``code``, ``http_response`` and ``cause`` properties common to all Firebase exception types. +Each exception also carries a message that outlines what went wrong. This can be logged for +audit or debugging purposes. + +When calling an Admin SDK API, developers can catch the parent ``FirebaseError`` and +inspect its ``code`` to implement fine-grained error handling. Alternatively, developers can +catch one or more subtypes of ``FirebaseError``. Under normal conditions, any given API can raise +only a small subset of the available exception subtypes. However, the SDK also exposes rare error +conditions like connection timeouts and other I/O errors as instances of ``FirebaseError``. +Therefore it is always a good idea to have a handler specified for ``FirebaseError``, after all the +subtype error handlers. +""" + + +#: Error code for ``InvalidArgumentError`` type. +INVALID_ARGUMENT = 'INVALID_ARGUMENT' + +#: Error code for ``FailedPreconditionError`` type. +FAILED_PRECONDITION = 'FAILED_PRECONDITION' + +#: Error code for ``OutOfRangeError`` type. +OUT_OF_RANGE = 'OUT_OF_RANGE' + +#: Error code for ``UnauthenticatedError`` type. +UNAUTHENTICATED = 'UNAUTHENTICATED' + +#: Error code for ``PermissionDeniedError`` type. +PERMISSION_DENIED = 'PERMISSION_DENIED' + +#: Error code for ``NotFoundError`` type. +NOT_FOUND = 'NOT_FOUND' + +#: Error code for ``ConflictError`` type. +CONFLICT = 'CONFLICT' + +#: Error code for ``AbortedError`` type. +ABORTED = 'ABORTED' + +#: Error code for ``AlreadyExistsError`` type. +ALREADY_EXISTS = 'ALREADY_EXISTS' + +#: Error code for ``ResourceExhaustedError`` type. +RESOURCE_EXHAUSTED = 'RESOURCE_EXHAUSTED' + +#: Error code for ``CancelledError`` type. +CANCELLED = 'CANCELLED' + +#: Error code for ``DataLossError`` type. +DATA_LOSS = 'DATA_LOSS' + +#: Error code for ``UnknownError`` type. +UNKNOWN = 'UNKNOWN' + +#: Error code for ``InternalError`` type. +INTERNAL = 'INTERNAL' + +#: Error code for ``UnavailableError`` type. +UNAVAILABLE = 'UNAVAILABLE' + +#: Error code for ``DeadlineExceededError`` type. +DEADLINE_EXCEEDED = 'DEADLINE_EXCEEDED' + + +class FirebaseError(Exception): + """Base class for all errors raised by the Admin SDK. + + Args: + code: A string error code that represents the type of the exception. Possible error + codes are defined in https://cloud.google.com/apis/design/errors#handling_errors. + message: A human-readable error message string. + cause: The exception that caused this error (optional). + http_response: If this error was caused by an HTTP error response, this property is + set to the ``requests.Response`` object that represents the HTTP response (optional). + See https://2.python-requests.org/en/master/api/#requests.Response for details of + this object. + """ + + def __init__(self, code, message, cause=None, http_response=None): + Exception.__init__(self, message) + self._code = code + self._cause = cause + self._http_response = http_response + + @property + def code(self): + return self._code + + @property + def cause(self): + return self._cause + + @property + def http_response(self): + return self._http_response + + +class InvalidArgumentError(FirebaseError): + """Client specified an invalid argument.""" + + def __init__(self, message, cause=None, http_response=None): + FirebaseError.__init__(self, INVALID_ARGUMENT, message, cause, http_response) + + +class FailedPreconditionError(FirebaseError): + """Request can not be executed in the current system state, such as deleting a non-empty + directory.""" + + def __init__(self, message, cause=None, http_response=None): + FirebaseError.__init__(self, FAILED_PRECONDITION, message, cause, http_response) + + +class OutOfRangeError(FirebaseError): + """Client specified an invalid range.""" + + def __init__(self, message, cause=None, http_response=None): + FirebaseError.__init__(self, OUT_OF_RANGE, message, cause, http_response) + + +class UnauthenticatedError(FirebaseError): + """Request not authenticated due to missing, invalid, or expired OAuth token.""" + + def __init__(self, message, cause=None, http_response=None): + FirebaseError.__init__(self, UNAUTHENTICATED, message, cause, http_response) + + +class PermissionDeniedError(FirebaseError): + """Client does not have sufficient permission. + + This can happen because the OAuth token does not have the right scopes, the client doesn't + have permission, or the API has not been enabled for the client project. + """ + + def __init__(self, message, cause=None, http_response=None): + FirebaseError.__init__(self, PERMISSION_DENIED, message, cause, http_response) + + +class NotFoundError(FirebaseError): + """A specified resource is not found, or the request is rejected by undisclosed reasons, such + as whitelisting.""" + + def __init__(self, message, cause=None, http_response=None): + FirebaseError.__init__(self, NOT_FOUND, message, cause, http_response) + + +class ConflictError(FirebaseError): + """Concurrency conflict, such as read-modify-write conflict.""" + + def __init__(self, message, cause=None, http_response=None): + FirebaseError.__init__(self, CONFLICT, message, cause, http_response) + + +class AbortedError(FirebaseError): + """Concurrency conflict, such as read-modify-write conflict.""" + + def __init__(self, message, cause=None, http_response=None): + FirebaseError.__init__(self, ABORTED, message, cause, http_response) + + +class AlreadyExistsError(FirebaseError): + """The resource that a client tried to create already exists.""" + + def __init__(self, message, cause=None, http_response=None): + FirebaseError.__init__(self, ALREADY_EXISTS, message, cause, http_response) + + +class ResourceExhaustedError(FirebaseError): + """Either out of resource quota or reaching rate limiting.""" + + def __init__(self, message, cause=None, http_response=None): + FirebaseError.__init__(self, RESOURCE_EXHAUSTED, message, cause, http_response) + + +class CancelledError(FirebaseError): + """Request cancelled by the client.""" + + def __init__(self, message, cause=None, http_response=None): + FirebaseError.__init__(self, CANCELLED, message, cause, http_response) + + +class DataLossError(FirebaseError): + """Unrecoverable data loss or data corruption.""" + + def __init__(self, message, cause=None, http_response=None): + FirebaseError.__init__(self, DATA_LOSS, message, cause, http_response) + + +class UnknownError(FirebaseError): + """Unknown server error.""" + + def __init__(self, message, cause=None, http_response=None): + FirebaseError.__init__(self, UNKNOWN, message, cause, http_response) + + +class InternalError(FirebaseError): + """Internal server error.""" + + def __init__(self, message, cause=None, http_response=None): + FirebaseError.__init__(self, INTERNAL, message, cause, http_response) + + +class UnavailableError(FirebaseError): + """Service unavailable. Typically the server is down.""" + + def __init__(self, message, cause=None, http_response=None): + FirebaseError.__init__(self, UNAVAILABLE, message, cause, http_response) + + +class DeadlineExceededError(FirebaseError): + """Request deadline exceeded. + + This will happen only if the caller sets a deadline that is shorter than the method's + default deadline (i.e. requested deadline is not enough for the server to process the + request) and the request did not finish within the deadline. + """ + + def __init__(self, message, cause=None, http_response=None): + FirebaseError.__init__(self, DEADLINE_EXCEEDED, message, cause, http_response) diff --git a/venv/Lib/site-packages/firebase_admin/firestore.py b/venv/Lib/site-packages/firebase_admin/firestore.py new file mode 100644 index 000000000..32c9897d5 --- /dev/null +++ b/venv/Lib/site-packages/firebase_admin/firestore.py @@ -0,0 +1,76 @@ +# Copyright 2017 Google Inc. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +"""Cloud Firestore module. + +This module contains utilities for accessing the Google Cloud Firestore databases associated with +Firebase apps. This requires the ``google-cloud-firestore`` Python module. +""" + +try: + from google.cloud import firestore # pylint: disable=import-error,no-name-in-module + existing = globals().keys() + for key, value in firestore.__dict__.items(): + if not key.startswith('_') and key not in existing: + globals()[key] = value +except ImportError: + raise ImportError('Failed to import the Cloud Firestore library for Python. Make sure ' + 'to install the "google-cloud-firestore" module.') + +from firebase_admin import _utils + + +_FIRESTORE_ATTRIBUTE = '_firestore' + + +def client(app=None): + """Returns a client that can be used to interact with Google Cloud Firestore. + + Args: + app: An App instance (optional). + + Returns: + google.cloud.firestore.Firestore: A `Firestore Client`_. + + Raises: + ValueError: If a project ID is not specified either via options, credentials or + environment variables, or if the specified project ID is not a valid string. + + .. _Firestore Client: https://googlecloudplatform.github.io/google-cloud-python/latest\ + /firestore/client.html + """ + fs_client = _utils.get_app_service(app, _FIRESTORE_ATTRIBUTE, _FirestoreClient.from_app) + return fs_client.get() + + +class _FirestoreClient: + """Holds a Google Cloud Firestore client instance.""" + + def __init__(self, credentials, project): + self._client = firestore.Client(credentials=credentials, project=project) + + def get(self): + return self._client + + @classmethod + def from_app(cls, app): + """Creates a new _FirestoreClient for the specified app.""" + credentials = app.credential.get_credential() + project = app.project_id + if not project: + raise ValueError( + 'Project ID is required to access Firestore. Either set the projectId option, ' + 'or use service account credentials. Alternatively, set the GOOGLE_CLOUD_PROJECT ' + 'environment variable.') + return _FirestoreClient(credentials, project) diff --git a/venv/Lib/site-packages/firebase_admin/instance_id.py b/venv/Lib/site-packages/firebase_admin/instance_id.py new file mode 100644 index 000000000..604158d9c --- /dev/null +++ b/venv/Lib/site-packages/firebase_admin/instance_id.py @@ -0,0 +1,99 @@ +# Copyright 2017 Google Inc. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +"""Firebase Instance ID module. + +This module enables deleting instance IDs associated with Firebase projects. +""" + +import requests + +from firebase_admin import _http_client +from firebase_admin import _utils + + +_IID_SERVICE_URL = 'https://console.firebase.google.com/v1/' +_IID_ATTRIBUTE = '_iid' + + +def _get_iid_service(app): + return _utils.get_app_service(app, _IID_ATTRIBUTE, _InstanceIdService) + + +def delete_instance_id(instance_id, app=None): + """Deletes the specified instance ID and the associated data from Firebase. + + Note that Google Analytics for Firebase uses its own form of Instance ID to + keep track of analytics data. Therefore deleting a regular Instance ID does + not delete Analytics data. See `Delete an Instance ID`_ for more information. + + Args: + instance_id: A non-empty instance ID string. + app: An App instance (optional). + + Raises: + InstanceIdError: If an error occurs while invoking the backend instance ID service. + ValueError: If the specified instance ID or app is invalid. + + .. _Delete an Instance ID: https://firebase.google.com/support/privacy\ + /manage-iids#delete_an_instance_id + """ + _get_iid_service(app).delete_instance_id(instance_id) + + +class _InstanceIdService: + """Provides methods for interacting with the remote instance ID service.""" + + error_codes = { + 400: 'Malformed instance ID argument.', + 401: 'Request not authorized.', + 403: 'Project does not match instance ID or the client does not have ' + 'sufficient privileges.', + 404: 'Failed to find the instance ID.', + 409: 'Already deleted.', + 429: 'Request throttled out by the backend server.', + 500: 'Internal server error.', + 503: 'Backend servers are over capacity. Try again later.' + } + + def __init__(self, app): + project_id = app.project_id + if not project_id: + raise ValueError( + 'Project ID is required to access Instance ID service. Either set the projectId ' + 'option, or use service account credentials. Alternatively, set the ' + 'GOOGLE_CLOUD_PROJECT environment variable.') + self._project_id = project_id + self._client = _http_client.JsonHttpClient( + credential=app.credential.get_credential(), base_url=_IID_SERVICE_URL) + + def delete_instance_id(self, instance_id): + if not isinstance(instance_id, str) or not instance_id: + raise ValueError('Instance ID must be a non-empty string.') + path = 'project/{0}/instanceId/{1}'.format(self._project_id, instance_id) + try: + self._client.request('delete', path) + except requests.exceptions.RequestException as error: + msg = self._extract_message(instance_id, error) + raise _utils.handle_requests_error(error, msg) + + def _extract_message(self, instance_id, error): + if error.response is None: + return None + status = error.response.status_code + msg = self.error_codes.get(status) + if msg: + return 'Instance ID "{0}": {1}'.format(instance_id, msg) + + return 'Instance ID "{0}": {1}'.format(instance_id, error) diff --git a/venv/Lib/site-packages/firebase_admin/messaging.py b/venv/Lib/site-packages/firebase_admin/messaging.py new file mode 100644 index 000000000..217cf0a56 --- /dev/null +++ b/venv/Lib/site-packages/firebase_admin/messaging.py @@ -0,0 +1,495 @@ +# Copyright 2017 Google Inc. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +"""Firebase Cloud Messaging module.""" + +import json + +import googleapiclient +from googleapiclient import http +from googleapiclient import _auth +import requests + +import firebase_admin +from firebase_admin import _http_client +from firebase_admin import _messaging_encoder +from firebase_admin import _messaging_utils +from firebase_admin import _utils + + +_MESSAGING_ATTRIBUTE = '_messaging' + + +__all__ = [ + 'AndroidConfig', + 'AndroidFCMOptions', + 'AndroidNotification', + 'APNSConfig', + 'APNSFCMOptions', + 'APNSPayload', + 'Aps', + 'ApsAlert', + 'BatchResponse', + 'CriticalSound', + 'ErrorInfo', + 'FCMOptions', + 'LightSettings', + 'Message', + 'MulticastMessage', + 'Notification', + 'QuotaExceededError', + 'SenderIdMismatchError', + 'SendResponse', + 'ThirdPartyAuthError', + 'TopicManagementResponse', + 'UnregisteredError', + 'WebpushConfig', + 'WebpushFCMOptions', + 'WebpushNotification', + 'WebpushNotificationAction', + + 'send', + 'send_all', + 'send_multicast', + 'subscribe_to_topic', + 'unsubscribe_from_topic', +] + + +AndroidConfig = _messaging_utils.AndroidConfig +AndroidFCMOptions = _messaging_utils.AndroidFCMOptions +AndroidNotification = _messaging_utils.AndroidNotification +APNSConfig = _messaging_utils.APNSConfig +APNSFCMOptions = _messaging_utils.APNSFCMOptions +APNSPayload = _messaging_utils.APNSPayload +Aps = _messaging_utils.Aps +ApsAlert = _messaging_utils.ApsAlert +CriticalSound = _messaging_utils.CriticalSound +FCMOptions = _messaging_utils.FCMOptions +LightSettings = _messaging_utils.LightSettings +Message = _messaging_encoder.Message +MulticastMessage = _messaging_encoder.MulticastMessage +Notification = _messaging_utils.Notification +WebpushConfig = _messaging_utils.WebpushConfig +WebpushFCMOptions = _messaging_utils.WebpushFCMOptions +WebpushNotification = _messaging_utils.WebpushNotification +WebpushNotificationAction = _messaging_utils.WebpushNotificationAction + +QuotaExceededError = _messaging_utils.QuotaExceededError +SenderIdMismatchError = _messaging_utils.SenderIdMismatchError +ThirdPartyAuthError = _messaging_utils.ThirdPartyAuthError +UnregisteredError = _messaging_utils.UnregisteredError + + +def _get_messaging_service(app): + return _utils.get_app_service(app, _MESSAGING_ATTRIBUTE, _MessagingService) + +def send(message, dry_run=False, app=None): + """Sends the given message via Firebase Cloud Messaging (FCM). + + If the ``dry_run`` mode is enabled, the message will not be actually delivered to the + recipients. Instead FCM performs all the usual validations, and emulates the send operation. + + Args: + message: An instance of ``messaging.Message``. + dry_run: A boolean indicating whether to run the operation in dry run mode (optional). + app: An App instance (optional). + + Returns: + string: A message ID string that uniquely identifies the sent the message. + + Raises: + FirebaseError: If an error occurs while sending the message to the FCM service. + ValueError: If the input arguments are invalid. + """ + return _get_messaging_service(app).send(message, dry_run) + +def send_all(messages, dry_run=False, app=None): + """Sends the given list of messages via Firebase Cloud Messaging as a single batch. + + If the ``dry_run`` mode is enabled, the message will not be actually delivered to the + recipients. Instead FCM performs all the usual validations, and emulates the send operation. + + Args: + messages: A list of ``messaging.Message`` instances. + dry_run: A boolean indicating whether to run the operation in dry run mode (optional). + app: An App instance (optional). + + Returns: + BatchResponse: A ``messaging.BatchResponse`` instance. + + Raises: + FirebaseError: If an error occurs while sending the message to the FCM service. + ValueError: If the input arguments are invalid. + """ + return _get_messaging_service(app).send_all(messages, dry_run) + +def send_multicast(multicast_message, dry_run=False, app=None): + """Sends the given mutlicast message to all tokens via Firebase Cloud Messaging (FCM). + + If the ``dry_run`` mode is enabled, the message will not be actually delivered to the + recipients. Instead FCM performs all the usual validations, and emulates the send operation. + + Args: + multicast_message: An instance of ``messaging.MulticastMessage``. + dry_run: A boolean indicating whether to run the operation in dry run mode (optional). + app: An App instance (optional). + + Returns: + BatchResponse: A ``messaging.BatchResponse`` instance. + + Raises: + FirebaseError: If an error occurs while sending the message to the FCM service. + ValueError: If the input arguments are invalid. + """ + if not isinstance(multicast_message, MulticastMessage): + raise ValueError('Message must be an instance of messaging.MulticastMessage class.') + messages = [Message( + data=multicast_message.data, + notification=multicast_message.notification, + android=multicast_message.android, + webpush=multicast_message.webpush, + apns=multicast_message.apns, + fcm_options=multicast_message.fcm_options, + token=token + ) for token in multicast_message.tokens] + return _get_messaging_service(app).send_all(messages, dry_run) + +def subscribe_to_topic(tokens, topic, app=None): + """Subscribes a list of registration tokens to an FCM topic. + + Args: + tokens: A non-empty list of device registration tokens. List may not have more than 1000 + elements. + topic: Name of the topic to subscribe to. May contain the ``/topics/`` prefix. + app: An App instance (optional). + + Returns: + TopicManagementResponse: A ``TopicManagementResponse`` instance. + + Raises: + FirebaseError: If an error occurs while communicating with instance ID service. + ValueError: If the input arguments are invalid. + """ + return _get_messaging_service(app).make_topic_management_request( + tokens, topic, 'iid/v1:batchAdd') + +def unsubscribe_from_topic(tokens, topic, app=None): + """Unsubscribes a list of registration tokens from an FCM topic. + + Args: + tokens: A non-empty list of device registration tokens. List may not have more than 1000 + elements. + topic: Name of the topic to unsubscribe from. May contain the ``/topics/`` prefix. + app: An App instance (optional). + + Returns: + TopicManagementResponse: A ``TopicManagementResponse`` instance. + + Raises: + FirebaseError: If an error occurs while communicating with instance ID service. + ValueError: If the input arguments are invalid. + """ + return _get_messaging_service(app).make_topic_management_request( + tokens, topic, 'iid/v1:batchRemove') + + +class ErrorInfo: + """An error encountered when performing a topic management operation.""" + + def __init__(self, index, reason): + self._index = index + self._reason = reason + + @property + def index(self): + """Index of the registration token to which this error is related to.""" + return self._index + + @property + def reason(self): + """String describing the nature of the error.""" + return self._reason + + +class TopicManagementResponse: + """The response received from a topic management operation.""" + + def __init__(self, resp): + if not isinstance(resp, dict) or 'results' not in resp: + raise ValueError('Unexpected topic management response: {0}.'.format(resp)) + self._success_count = 0 + self._failure_count = 0 + self._errors = [] + for index, result in enumerate(resp['results']): + if 'error' in result: + self._failure_count += 1 + self._errors.append(ErrorInfo(index, result['error'])) + else: + self._success_count += 1 + + @property + def success_count(self): + """Number of tokens that were successfully subscribed or unsubscribed.""" + return self._success_count + + @property + def failure_count(self): + """Number of tokens that could not be subscribed or unsubscribed due to errors.""" + return self._failure_count + + @property + def errors(self): + """A list of ``messaging.ErrorInfo`` objects (possibly empty).""" + return self._errors + + +class BatchResponse: + """The response received from a batch request to the FCM API.""" + + def __init__(self, responses): + self._responses = responses + self._success_count = len([resp for resp in responses if resp.success]) + + @property + def responses(self): + """A list of ``messaging.SendResponse`` objects (possibly empty).""" + return self._responses + + @property + def success_count(self): + return self._success_count + + @property + def failure_count(self): + return len(self.responses) - self.success_count + + +class SendResponse: + """The response received from an individual batched request to the FCM API.""" + + def __init__(self, resp, exception): + self._exception = exception + self._message_id = None + if resp: + self._message_id = resp.get('name', None) + + @property + def message_id(self): + """A message ID string that uniquely identifies the message.""" + return self._message_id + + @property + def success(self): + """A boolean indicating if the request was successful.""" + return self._message_id is not None and not self._exception + + @property + def exception(self): + """A ``FirebaseError`` if an error occurs while sending the message to the FCM service.""" + return self._exception + + +class _MessagingService: + """Service class that implements Firebase Cloud Messaging (FCM) functionality.""" + + FCM_URL = 'https://fcm.googleapis.com/v1/projects/{0}/messages:send' + FCM_BATCH_URL = 'https://fcm.googleapis.com/batch' + IID_URL = 'https://iid.googleapis.com' + IID_HEADERS = {'access_token_auth': 'true'} + JSON_ENCODER = _messaging_encoder.MessageEncoder() + + FCM_ERROR_TYPES = { + 'APNS_AUTH_ERROR': ThirdPartyAuthError, + 'QUOTA_EXCEEDED': QuotaExceededError, + 'SENDER_ID_MISMATCH': SenderIdMismatchError, + 'THIRD_PARTY_AUTH_ERROR': ThirdPartyAuthError, + 'UNREGISTERED': UnregisteredError, + } + + def __init__(self, app): + project_id = app.project_id + if not project_id: + raise ValueError( + 'Project ID is required to access Cloud Messaging service. Either set the ' + 'projectId option, or use service account credentials. Alternatively, set the ' + 'GOOGLE_CLOUD_PROJECT environment variable.') + self._fcm_url = _MessagingService.FCM_URL.format(project_id) + self._fcm_headers = { + 'X-GOOG-API-FORMAT-VERSION': '2', + 'X-FIREBASE-CLIENT': 'fire-admin-python/{0}'.format(firebase_admin.__version__), + } + timeout = app.options.get('httpTimeout', _http_client.DEFAULT_TIMEOUT_SECONDS) + self._client = _http_client.JsonHttpClient( + credential=app.credential.get_credential(), timeout=timeout) + self._transport = _auth.authorized_http(app.credential.get_credential()) + + @classmethod + def encode_message(cls, message): + if not isinstance(message, Message): + raise ValueError('Message must be an instance of messaging.Message class.') + return cls.JSON_ENCODER.default(message) + + def send(self, message, dry_run=False): + """Sends the given message to FCM via the FCM v1 API.""" + data = self._message_data(message, dry_run) + try: + resp = self._client.body( + 'post', + url=self._fcm_url, + headers=self._fcm_headers, + json=data + ) + except requests.exceptions.RequestException as error: + raise self._handle_fcm_error(error) + else: + return resp['name'] + + def send_all(self, messages, dry_run=False): + """Sends the given messages to FCM via the batch API.""" + if not isinstance(messages, list): + raise ValueError('messages must be a list of messaging.Message instances.') + if len(messages) > 500: + raise ValueError('messages must not contain more than 500 elements.') + + responses = [] + + def batch_callback(_, response, error): + exception = None + if error: + exception = self._handle_batch_error(error) + send_response = SendResponse(response, exception) + responses.append(send_response) + + batch = http.BatchHttpRequest( + callback=batch_callback, batch_uri=_MessagingService.FCM_BATCH_URL) + for message in messages: + body = json.dumps(self._message_data(message, dry_run)) + req = http.HttpRequest( + http=self._transport, + postproc=self._postproc, + uri=self._fcm_url, + method='POST', + body=body, + headers=self._fcm_headers + ) + batch.add(req) + + try: + batch.execute() + except googleapiclient.http.HttpError as error: + raise self._handle_batch_error(error) + else: + return BatchResponse(responses) + + def make_topic_management_request(self, tokens, topic, operation): + """Invokes the IID service for topic management functionality.""" + if isinstance(tokens, str): + tokens = [tokens] + if not isinstance(tokens, list) or not tokens: + raise ValueError('Tokens must be a string or a non-empty list of strings.') + invalid_str = [t for t in tokens if not isinstance(t, str) or not t] + if invalid_str: + raise ValueError('Tokens must be non-empty strings.') + + if not isinstance(topic, str) or not topic: + raise ValueError('Topic must be a non-empty string.') + if not topic.startswith('/topics/'): + topic = '/topics/{0}'.format(topic) + data = { + 'to': topic, + 'registration_tokens': tokens, + } + url = '{0}/{1}'.format(_MessagingService.IID_URL, operation) + try: + resp = self._client.body( + 'post', + url=url, + json=data, + headers=_MessagingService.IID_HEADERS + ) + except requests.exceptions.RequestException as error: + raise self._handle_iid_error(error) + else: + return TopicManagementResponse(resp) + + def _message_data(self, message, dry_run): + data = {'message': _MessagingService.encode_message(message)} + if dry_run: + data['validate_only'] = True + return data + + def _postproc(self, _, body): + """Handle response from batch API request.""" + # This only gets called for 2xx responses. + return json.loads(body.decode()) + + def _handle_fcm_error(self, error): + """Handles errors received from the FCM API.""" + return _utils.handle_platform_error_from_requests( + error, _MessagingService._build_fcm_error_requests) + + def _handle_iid_error(self, error): + """Handles errors received from the Instance ID API.""" + if error.response is None: + raise _utils.handle_requests_error(error) + + data = {} + try: + parsed_body = error.response.json() + if isinstance(parsed_body, dict): + data = parsed_body + except ValueError: + pass + + # IID error response format: {"error": "ErrorCode"} + code = data.get('error') + msg = None + if code: + msg = 'Error while calling the IID service: {0}'.format(code) + else: + msg = 'Unexpected HTTP response with status: {0}; body: {1}'.format( + error.response.status_code, error.response.content.decode()) + + return _utils.handle_requests_error(error, msg) + + def _handle_batch_error(self, error): + """Handles errors received from the googleapiclient while making batch requests.""" + return _utils.handle_platform_error_from_googleapiclient( + error, _MessagingService._build_fcm_error_googleapiclient) + + @classmethod + def _build_fcm_error_requests(cls, error, message, error_dict): + """Parses an error response from the FCM API and creates a FCM-specific exception if + appropriate.""" + exc_type = cls._build_fcm_error(error_dict) + return exc_type(message, cause=error, http_response=error.response) if exc_type else None + + @classmethod + def _build_fcm_error_googleapiclient(cls, error, message, error_dict, http_response): + """Parses an error response from the FCM API and creates a FCM-specific exception if + appropriate.""" + exc_type = cls._build_fcm_error(error_dict) + return exc_type(message, cause=error, http_response=http_response) if exc_type else None + + @classmethod + def _build_fcm_error(cls, error_dict): + if not error_dict: + return None + fcm_code = None + for detail in error_dict.get('details', []): + if detail.get('@type') == 'type.googleapis.com/google.firebase.fcm.v1.FcmError': + fcm_code = detail.get('errorCode') + break + return _MessagingService.FCM_ERROR_TYPES.get(fcm_code) diff --git a/venv/Lib/site-packages/firebase_admin/ml.py b/venv/Lib/site-packages/firebase_admin/ml.py new file mode 100644 index 000000000..bcc4b9390 --- /dev/null +++ b/venv/Lib/site-packages/firebase_admin/ml.py @@ -0,0 +1,983 @@ +# Copyright 2019 Google Inc. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +"""Firebase ML module. + +This module contains functions for creating, updating, getting, listing, +deleting, publishing and unpublishing Firebase ML models. +""" + + +import datetime +import re +import time +import os +from urllib import parse + +import requests + +import firebase_admin +from firebase_admin import _http_client +from firebase_admin import _utils +from firebase_admin import exceptions + +# pylint: disable=import-error,no-name-in-module +try: + from firebase_admin import storage + _GCS_ENABLED = True +except ImportError: + _GCS_ENABLED = False + +# pylint: disable=import-error,no-name-in-module +try: + import tensorflow as tf + _TF_ENABLED = True +except ImportError: + _TF_ENABLED = False + +_ML_ATTRIBUTE = '_ml' +_MAX_PAGE_SIZE = 100 +_MODEL_ID_PATTERN = re.compile(r'^[A-Za-z0-9_-]{1,60}$') +_DISPLAY_NAME_PATTERN = re.compile(r'^[A-Za-z0-9_-]{1,32}$') +_TAG_PATTERN = re.compile(r'^[A-Za-z0-9_-]{1,32}$') +_GCS_TFLITE_URI_PATTERN = re.compile( + r'^gs://(?P[a-z0-9_.-]{3,63})/(?P.+)$') +_AUTO_ML_MODEL_PATTERN = re.compile( + r'^projects/(?P[a-z0-9-]{6,30})/locations/(?P[^/]+)/' + + r'models/(?P[A-Za-z0-9]+)$') +_RESOURCE_NAME_PATTERN = re.compile( + r'^projects/(?P[a-z0-9-]{6,30})/models/(?P[A-Za-z0-9_-]{1,60})$') +_OPERATION_NAME_PATTERN = re.compile( + r'^projects/(?P[a-z0-9-]{6,30})/operations/[^/]+$') + + +def _get_ml_service(app): + """ Returns an _MLService instance for an App. + + Args: + app: A Firebase App instance (or None to use the default App). + + Returns: + _MLService: An _MLService for the specified App instance. + + Raises: + ValueError: If the app argument is invalid. + """ + return _utils.get_app_service(app, _ML_ATTRIBUTE, _MLService) + + +def create_model(model, app=None): + """Creates a model in the current Firebase project. + + Args: + model: An ml.Model to create. + app: A Firebase app instance (or None to use the default app). + + Returns: + Model: The model that was created in Firebase ML. + """ + ml_service = _get_ml_service(app) + return Model.from_dict(ml_service.create_model(model), app=app) + + +def update_model(model, app=None): + """Updates a model's metadata or model file. + + Args: + model: The ml.Model to update. + app: A Firebase app instance (or None to use the default app). + + Returns: + Model: The updated model. + """ + ml_service = _get_ml_service(app) + return Model.from_dict(ml_service.update_model(model), app=app) + + +def publish_model(model_id, app=None): + """Publishes a Firebase ML model. + + A published model can be downloaded to client apps. + + Args: + model_id: The id of the model to publish. + app: A Firebase app instance (or None to use the default app). + + Returns: + Model: The published model. + """ + ml_service = _get_ml_service(app) + return Model.from_dict(ml_service.set_published(model_id, publish=True), app=app) + + +def unpublish_model(model_id, app=None): + """Unpublishes a Firebase ML model. + + Args: + model_id: The id of the model to unpublish. + app: A Firebase app instance (or None to use the default app). + + Returns: + Model: The unpublished model. + """ + ml_service = _get_ml_service(app) + return Model.from_dict(ml_service.set_published(model_id, publish=False), app=app) + + +def get_model(model_id, app=None): + """Gets the model specified by the given ID. + + Args: + model_id: The id of the model to get. + app: A Firebase app instance (or None to use the default app). + + Returns: + Model: The requested model. + """ + ml_service = _get_ml_service(app) + return Model.from_dict(ml_service.get_model(model_id), app=app) + + +def list_models(list_filter=None, page_size=None, page_token=None, app=None): + """Lists the current project's models. + + Args: + list_filter: a list filter string such as ``tags:'tag_1'``. None will return all models. + page_size: A number between 1 and 100 inclusive that specifies the maximum + number of models to return per page. None for default. + page_token: A next page token returned from a previous page of results. None + for first page of results. + app: A Firebase app instance (or None to use the default app). + + Returns: + ListModelsPage: A (filtered) list of models. + """ + ml_service = _get_ml_service(app) + return ListModelsPage( + ml_service.list_models, list_filter, page_size, page_token, app=app) + + +def delete_model(model_id, app=None): + """Deletes a model from the current project. + + Args: + model_id: The id of the model you wish to delete. + app: A Firebase app instance (or None to use the default app). + """ + ml_service = _get_ml_service(app) + ml_service.delete_model(model_id) + + +class Model: + """A Firebase ML Model object. + + Args: + display_name: The display name of your model - used to identify your model in code. + tags: Optional list of strings associated with your model. Can be used in list queries. + model_format: A subclass of ModelFormat. (e.g. TFLiteFormat) Specifies the model details. + """ + def __init__(self, display_name=None, tags=None, model_format=None): + self._app = None # Only needed for wait_for_unlo + self._data = {} + self._model_format = None + + if display_name is not None: + self.display_name = display_name + if tags is not None: + self.tags = tags + if model_format is not None: + self.model_format = model_format + + @classmethod + def from_dict(cls, data, app=None): + """Create an instance of the object from a dict.""" + data_copy = dict(data) + tflite_format = None + tflite_format_data = data_copy.pop('tfliteModel', None) + data_copy.pop('@type', None) # Returned by Operations. (Not needed) + if tflite_format_data: + tflite_format = TFLiteFormat.from_dict(tflite_format_data) + model = Model(model_format=tflite_format) + model._data = data_copy # pylint: disable=protected-access + model._app = app # pylint: disable=protected-access + return model + + def _update_from_dict(self, data): + copy = Model.from_dict(data) + self.model_format = copy.model_format + self._data = copy._data # pylint: disable=protected-access + + def __eq__(self, other): + if isinstance(other, self.__class__): + # pylint: disable=protected-access + return self._data == other._data and self._model_format == other._model_format + return False + + def __ne__(self, other): + return not self.__eq__(other) + + @property + def model_id(self): + """The model's ID, unique to the project.""" + if not self._data.get('name'): + return None + _, model_id = _validate_and_parse_name(self._data.get('name')) + return model_id + + @property + def display_name(self): + """The model's display name, used to refer to the model in code and in + the Firebase console.""" + return self._data.get('displayName') + + @display_name.setter + def display_name(self, display_name): + self._data['displayName'] = _validate_display_name(display_name) + return self + + @staticmethod + def _convert_to_millis(date_string): + if not date_string: + return None + format_str = '%Y-%m-%dT%H:%M:%S.%fZ' + epoch = datetime.datetime.utcfromtimestamp(0) + datetime_object = datetime.datetime.strptime(date_string, format_str) + millis = int((datetime_object - epoch).total_seconds() * 1000) + return millis + + @property + def create_time(self): + """The time the model was created.""" + return Model._convert_to_millis(self._data.get('createTime', None)) + + @property + def update_time(self): + """The time the model was last updated.""" + return Model._convert_to_millis(self._data.get('updateTime', None)) + + @property + def validation_error(self): + """Validation error message.""" + return self._data.get('state', {}).get('validationError', {}).get('message') + + @property + def published(self): + """True if the model is published and available for clients to + download.""" + return bool(self._data.get('state', {}).get('published')) + + @property + def etag(self): + """The entity tag (ETag) of the model resource.""" + return self._data.get('etag') + + @property + def model_hash(self): + """SHA256 hash of the model binary.""" + return self._data.get('modelHash') + + @property + def tags(self): + """Tag strings, used for filtering query results.""" + return self._data.get('tags') + + @tags.setter + def tags(self, tags): + self._data['tags'] = _validate_tags(tags) + return self + + @property + def locked(self): + """True if the Model object is locked by an active operation.""" + return bool(self._data.get('activeOperations') and + len(self._data.get('activeOperations')) > 0) + + def wait_for_unlocked(self, max_time_seconds=None): + """Waits for the model to be unlocked. (All active operations complete) + + Args: + max_time_seconds: The maximum number of seconds to wait for the model to unlock. + (None for no limit) + + Raises: + exceptions.DeadlineExceeded: If max_time_seconds passed and the model is still locked. + """ + if not self.locked: + return + ml_service = _get_ml_service(self._app) + op_name = self._data.get('activeOperations')[0].get('name') + model_dict = ml_service.handle_operation( + ml_service.get_operation(op_name), + wait_for_operation=True, + max_time_seconds=max_time_seconds) + self._update_from_dict(model_dict) + + @property + def model_format(self): + """The model's ``ModelFormat`` object, which represents the model's + format and storage location.""" + return self._model_format + + @model_format.setter + def model_format(self, model_format): + if model_format is not None: + _validate_model_format(model_format) + self._model_format = model_format #Can be None + return self + + def as_dict(self, for_upload=False): + """Returns a serializable representation of the object.""" + copy = dict(self._data) + if self._model_format: + copy.update(self._model_format.as_dict(for_upload=for_upload)) + return copy + + +class ModelFormat: + """Abstract base class representing a Model Format such as TFLite.""" + def as_dict(self, for_upload=False): + """Returns a serializable representation of the object.""" + raise NotImplementedError + + +class TFLiteFormat(ModelFormat): + """Model format representing a TFLite model. + + Args: + model_source: A TFLiteModelSource sub class. Specifies the details of the model source. + """ + def __init__(self, model_source=None): + self._data = {} + self._model_source = None + + if model_source is not None: + self.model_source = model_source + + @classmethod + def from_dict(cls, data): + """Create an instance of the object from a dict.""" + data_copy = dict(data) + tflite_format = TFLiteFormat(model_source=cls._init_model_source(data_copy)) + tflite_format._data = data_copy # pylint: disable=protected-access + return tflite_format + + def __eq__(self, other): + if isinstance(other, self.__class__): + # pylint: disable=protected-access + return self._data == other._data and self._model_source == other._model_source + return False + + def __ne__(self, other): + return not self.__eq__(other) + + @staticmethod + def _init_model_source(data): + gcs_tflite_uri = data.pop('gcsTfliteUri', None) + if gcs_tflite_uri: + return TFLiteGCSModelSource(gcs_tflite_uri=gcs_tflite_uri) + auto_ml_model = data.pop('automlModel', None) + if auto_ml_model: + return TFLiteAutoMlSource(auto_ml_model=auto_ml_model) + return None + + @property + def model_source(self): + """The TF Lite model's location.""" + return self._model_source + + @model_source.setter + def model_source(self, model_source): + if model_source is not None: + if not isinstance(model_source, TFLiteModelSource): + raise TypeError('Model source must be a TFLiteModelSource object.') + self._model_source = model_source # Can be None + + @property + def size_bytes(self): + """The size in bytes of the TF Lite model.""" + return self._data.get('sizeBytes') + + def as_dict(self, for_upload=False): + """Returns a serializable representation of the object.""" + copy = dict(self._data) + if self._model_source: + copy.update(self._model_source.as_dict(for_upload=for_upload)) + return {'tfliteModel': copy} + + +class TFLiteModelSource: + """Abstract base class representing a model source for TFLite format models.""" + def as_dict(self, for_upload=False): + """Returns a serializable representation of the object.""" + raise NotImplementedError + + +class _CloudStorageClient: + """Cloud Storage helper class""" + + GCS_URI = 'gs://{0}/{1}' + BLOB_NAME = 'Firebase/ML/Models/{0}' + + @staticmethod + def _assert_gcs_enabled(): + if not _GCS_ENABLED: + raise ImportError('Failed to import the Cloud Storage library for Python. Make sure ' + 'to install the "google-cloud-storage" module.') + + @staticmethod + def _parse_gcs_tflite_uri(uri): + # GCS Bucket naming rules are complex. The regex is not comprehensive. + # See https://cloud.google.com/storage/docs/naming for full details. + matcher = _GCS_TFLITE_URI_PATTERN.match(uri) + if not matcher: + raise ValueError('GCS TFLite URI format is invalid.') + return matcher.group('bucket_name'), matcher.group('blob_name') + + @staticmethod + def upload(bucket_name, model_file_name, app): + """Upload a model file to the specified Storage bucket.""" + _CloudStorageClient._assert_gcs_enabled() + + file_name = os.path.basename(model_file_name) + bucket = storage.bucket(bucket_name, app=app) + blob_name = _CloudStorageClient.BLOB_NAME.format(file_name) + blob = bucket.blob(blob_name) + blob.upload_from_filename(model_file_name) + return _CloudStorageClient.GCS_URI.format(bucket.name, blob_name) + + @staticmethod + def sign_uri(gcs_tflite_uri, app): + """Makes the gcs_tflite_uri readable for GET for 10 minutes via signed_uri.""" + _CloudStorageClient._assert_gcs_enabled() + bucket_name, blob_name = _CloudStorageClient._parse_gcs_tflite_uri(gcs_tflite_uri) + bucket = storage.bucket(bucket_name, app=app) + blob = bucket.blob(blob_name) + return blob.generate_signed_url( + version='v4', + expiration=datetime.timedelta(minutes=10), + method='GET' + ) + + +class TFLiteGCSModelSource(TFLiteModelSource): + """TFLite model source representing a tflite model file stored in GCS.""" + + _STORAGE_CLIENT = _CloudStorageClient() + + def __init__(self, gcs_tflite_uri, app=None): + self._app = app + self._gcs_tflite_uri = _validate_gcs_tflite_uri(gcs_tflite_uri) + + def __eq__(self, other): + if isinstance(other, self.__class__): + return self._gcs_tflite_uri == other._gcs_tflite_uri # pylint: disable=protected-access + return False + + def __ne__(self, other): + return not self.__eq__(other) + + @classmethod + def from_tflite_model_file(cls, model_file_name, bucket_name=None, app=None): + """Uploads the model file to an existing Google Cloud Storage bucket. + + Args: + model_file_name: The name of the model file. + bucket_name: The name of an existing bucket. None to use the default bucket configured + in the app. + app: A Firebase app instance (or None to use the default app). + + Returns: + TFLiteGCSModelSource: The source created from the model_file + + Raises: + ImportError: If the Cloud Storage Library has not been installed. + """ + gcs_uri = TFLiteGCSModelSource._STORAGE_CLIENT.upload(bucket_name, model_file_name, app) + return TFLiteGCSModelSource(gcs_tflite_uri=gcs_uri, app=app) + + @staticmethod + def _assert_tf_enabled(): + if not _TF_ENABLED: + raise ImportError('Failed to import the tensorflow library for Python. Make sure ' + 'to install the tensorflow module.') + if not tf.version.VERSION.startswith('1.') and not tf.version.VERSION.startswith('2.'): + raise ImportError('Expected tensorflow version 1.x or 2.x, but found {0}' + .format(tf.version.VERSION)) + + @staticmethod + def _tf_convert_from_saved_model(saved_model_dir): + # Same for both v1.x and v2.x + converter = tf.lite.TFLiteConverter.from_saved_model(saved_model_dir) + return converter.convert() + + @staticmethod + def _tf_convert_from_keras_model(keras_model): + """Converts the given Keras model into a TF Lite model.""" + # Version 1.x conversion function takes a model file. Version 2.x takes the model itself. + if tf.version.VERSION.startswith('1.'): + keras_file = 'firebase_keras_model.h5' + tf.keras.models.save_model(keras_model, keras_file) + converter = tf.lite.TFLiteConverter.from_keras_model_file(keras_file) + else: + converter = tf.lite.TFLiteConverter.from_keras_model(keras_model) + + return converter.convert() + + @classmethod + def from_saved_model(cls, saved_model_dir, model_file_name='firebase_ml_model.tflite', + bucket_name=None, app=None): + """Creates a Tensor Flow Lite model from the saved model, and uploads the model to GCS. + + Args: + saved_model_dir: The saved model directory. + model_file_name: The name that the tflite model will be saved as in Cloud Storage. + bucket_name: The name of an existing bucket. None to use the default bucket configured + in the app. + app: Optional. A Firebase app instance (or None to use the default app) + + Returns: + TFLiteGCSModelSource: The source created from the saved_model_dir + + Raises: + ImportError: If the Tensor Flow or Cloud Storage Libraries have not been installed. + """ + TFLiteGCSModelSource._assert_tf_enabled() + tflite_model = TFLiteGCSModelSource._tf_convert_from_saved_model(saved_model_dir) + with open(model_file_name, 'wb') as model_file: + model_file.write(tflite_model) + return TFLiteGCSModelSource.from_tflite_model_file(model_file_name, bucket_name, app) + + @classmethod + def from_keras_model(cls, keras_model, model_file_name='firebase_ml_model.tflite', + bucket_name=None, app=None): + """Creates a Tensor Flow Lite model from the keras model, and uploads the model to GCS. + + Args: + keras_model: A tf.keras model. + model_file_name: The name that the tflite model will be saved as in Cloud Storage. + bucket_name: The name of an existing bucket. None to use the default bucket configured + in the app. + app: Optional. A Firebase app instance (or None to use the default app) + + Returns: + TFLiteGCSModelSource: The source created from the keras_model + + Raises: + ImportError: If the Tensor Flow or Cloud Storage Libraries have not been installed. + """ + TFLiteGCSModelSource._assert_tf_enabled() + tflite_model = TFLiteGCSModelSource._tf_convert_from_keras_model(keras_model) + with open(model_file_name, 'wb') as model_file: + model_file.write(tflite_model) + return TFLiteGCSModelSource.from_tflite_model_file(model_file_name, bucket_name, app) + + @property + def gcs_tflite_uri(self): + """URI of the model file in Cloud Storage.""" + return self._gcs_tflite_uri + + @gcs_tflite_uri.setter + def gcs_tflite_uri(self, gcs_tflite_uri): + self._gcs_tflite_uri = _validate_gcs_tflite_uri(gcs_tflite_uri) + + def _get_signed_gcs_tflite_uri(self): + """Signs the GCS uri, so the model file can be uploaded to Firebase ML and verified.""" + return TFLiteGCSModelSource._STORAGE_CLIENT.sign_uri(self._gcs_tflite_uri, self._app) + + def as_dict(self, for_upload=False): + """Returns a serializable representation of the object.""" + if for_upload: + return {'gcsTfliteUri': self._get_signed_gcs_tflite_uri()} + + return {'gcsTfliteUri': self._gcs_tflite_uri} + + +class TFLiteAutoMlSource(TFLiteModelSource): + """TFLite model source representing a tflite model created with AutoML.""" + + def __init__(self, auto_ml_model, app=None): + self._app = app + self.auto_ml_model = auto_ml_model + + def __eq__(self, other): + if isinstance(other, self.__class__): + return self.auto_ml_model == other.auto_ml_model + return False + + def __ne__(self, other): + return not self.__eq__(other) + + @property + def auto_ml_model(self): + """Resource name of the model, created by the AutoML API or Cloud console.""" + return self._auto_ml_model + + @auto_ml_model.setter + def auto_ml_model(self, auto_ml_model): + self._auto_ml_model = _validate_auto_ml_model(auto_ml_model) + + def as_dict(self, for_upload=False): + """Returns a serializable representation of the object.""" + # Upload is irrelevant for auto_ml models + return {'automlModel': self._auto_ml_model} + + +class ListModelsPage: + """Represents a page of models in a Firebase project. + + Provides methods for traversing the models included in this page, as well as + retrieving subsequent pages of models. The iterator returned by + ``iterate_all()`` can be used to iterate through all the models in the + Firebase project starting from this page. + """ + def __init__(self, list_models_func, list_filter, page_size, page_token, app): + self._list_models_func = list_models_func + self._list_filter = list_filter + self._page_size = page_size + self._page_token = page_token + self._app = app + self._list_response = list_models_func(list_filter, page_size, page_token) + + @property + def models(self): + """A list of Models from this page.""" + return [ + Model.from_dict(model, app=self._app) for model in self._list_response.get('models', []) + ] + + @property + def list_filter(self): + """The filter string used to filter the models.""" + return self._list_filter + + @property + def next_page_token(self): + """Token identifying the next page of results.""" + return self._list_response.get('nextPageToken', '') + + @property + def has_next_page(self): + """True if more pages are available.""" + return bool(self.next_page_token) + + def get_next_page(self): + """Retrieves the next page of models if available. + + Returns: + ListModelsPage: Next page of models, or None if this is the last page. + """ + if self.has_next_page: + return ListModelsPage( + self._list_models_func, + self._list_filter, + self._page_size, + self.next_page_token, + self._app) + return None + + def iterate_all(self): + """Retrieves an iterator for Models. + + Returned iterator will iterate through all the models in the Firebase + project starting from this page. The iterator will never buffer more than + one page of models in memory at a time. + + Returns: + iterator: An iterator of Model instances. + """ + return _ModelIterator(self) + + +class _ModelIterator: + """An iterator that allows iterating over models, one at a time. + + This implementation loads a page of models into memory, and iterates on them. + When the whole page has been traversed, it loads another page. This class + never keeps more than one page of entries in memory. + """ + def __init__(self, current_page): + if not isinstance(current_page, ListModelsPage): + raise TypeError('Current page must be a ListModelsPage') + self._current_page = current_page + self._index = 0 + + def next(self): + if self._index == len(self._current_page.models): + if self._current_page.has_next_page: + self._current_page = self._current_page.get_next_page() + self._index = 0 + if self._index < len(self._current_page.models): + result = self._current_page.models[self._index] + self._index += 1 + return result + raise StopIteration + + def __next__(self): + return self.next() + + def __iter__(self): + return self + + +def _validate_and_parse_name(name): + # The resource name is added automatically from API call responses. + # The only way it could be invalid is if someone tries to + # create a model from a dictionary manually and does it incorrectly. + matcher = _RESOURCE_NAME_PATTERN.match(name) + if not matcher: + raise ValueError('Model resource name format is invalid.') + return matcher.group('project_id'), matcher.group('model_id') + + +def _validate_model(model, update_mask=None): + if not isinstance(model, Model): + raise TypeError('Model must be an ml.Model.') + if update_mask is None and not model.display_name: + raise ValueError('Model must have a display name.') + + +def _validate_model_id(model_id): + if not _MODEL_ID_PATTERN.match(model_id): + raise ValueError('Model ID format is invalid.') + + +def _validate_operation_name(op_name): + if not _OPERATION_NAME_PATTERN.match(op_name): + raise ValueError('Operation name format is invalid.') + return op_name + + +def _validate_display_name(display_name): + if not _DISPLAY_NAME_PATTERN.match(display_name): + raise ValueError('Display name format is invalid.') + return display_name + + +def _validate_tags(tags): + if not isinstance(tags, list) or not \ + all(isinstance(tag, str) for tag in tags): + raise TypeError('Tags must be a list of strings.') + if not all(_TAG_PATTERN.match(tag) for tag in tags): + raise ValueError('Tag format is invalid.') + return tags + + +def _validate_gcs_tflite_uri(uri): + # GCS Bucket naming rules are complex. The regex is not comprehensive. + # See https://cloud.google.com/storage/docs/naming for full details. + if not _GCS_TFLITE_URI_PATTERN.match(uri): + raise ValueError('GCS TFLite URI format is invalid.') + return uri + +def _validate_auto_ml_model(model): + if not _AUTO_ML_MODEL_PATTERN.match(model): + raise ValueError('Model resource name format is invalid.') + return model + + +def _validate_model_format(model_format): + if not isinstance(model_format, ModelFormat): + raise TypeError('Model format must be a ModelFormat object.') + return model_format + + +def _validate_list_filter(list_filter): + if list_filter is not None: + if not isinstance(list_filter, str): + raise TypeError('List filter must be a string or None.') + + +def _validate_page_size(page_size): + if page_size is not None: + if type(page_size) is not int: # pylint: disable=unidiomatic-typecheck + # Specifically type() to disallow boolean which is a subtype of int + raise TypeError('Page size must be a number or None.') + if page_size < 1 or page_size > _MAX_PAGE_SIZE: + raise ValueError('Page size must be a positive integer between ' + '1 and {0}'.format(_MAX_PAGE_SIZE)) + + +def _validate_page_token(page_token): + if page_token is not None: + if not isinstance(page_token, str): + raise TypeError('Page token must be a string or None.') + + +class _MLService: + """Firebase ML service.""" + + PROJECT_URL = 'https://firebaseml.googleapis.com/v1beta2/projects/{0}/' + OPERATION_URL = 'https://firebaseml.googleapis.com/v1beta2/' + POLL_EXPONENTIAL_BACKOFF_FACTOR = 1.5 + POLL_BASE_WAIT_TIME_SECONDS = 3 + + def __init__(self, app): + self._project_id = app.project_id + if not self._project_id: + raise ValueError( + 'Project ID is required to access ML service. Either set the ' + 'projectId option, or use service account credentials.') + self._project_url = _MLService.PROJECT_URL.format(self._project_id) + ml_headers = { + 'X-FIREBASE-CLIENT': 'fire-admin-python/{0}'.format(firebase_admin.__version__), + } + self._client = _http_client.JsonHttpClient( + credential=app.credential.get_credential(), + headers=ml_headers, + base_url=self._project_url) + self._operation_client = _http_client.JsonHttpClient( + credential=app.credential.get_credential(), + headers=ml_headers, + base_url=_MLService.OPERATION_URL) + + def get_operation(self, op_name): + _validate_operation_name(op_name) + try: + return self._operation_client.body('get', url=op_name) + except requests.exceptions.RequestException as error: + raise _utils.handle_platform_error_from_requests(error) + + def _exponential_backoff(self, current_attempt, stop_time): + """Sleeps for the appropriate amount of time. Or throws deadline exceeded.""" + delay_factor = pow(_MLService.POLL_EXPONENTIAL_BACKOFF_FACTOR, current_attempt) + wait_time_seconds = delay_factor * _MLService.POLL_BASE_WAIT_TIME_SECONDS + + if stop_time is not None: + max_seconds_left = (stop_time - datetime.datetime.now()).total_seconds() + if max_seconds_left < 1: # allow a bit of time for rpc + raise exceptions.DeadlineExceededError('Polling max time exceeded.') + wait_time_seconds = min(wait_time_seconds, max_seconds_left - 1) + time.sleep(wait_time_seconds) + + def handle_operation(self, operation, wait_for_operation=False, max_time_seconds=None): + """Handles long running operations. + + Args: + operation: The operation to handle. + wait_for_operation: Should we allow polling for the operation to complete. + If no polling is requested, a locked model will be returned instead. + max_time_seconds: The maximum seconds to try polling for operation complete. + (None for no limit) + + Returns: + dict: A dictionary of the returned model properties. + + Raises: + TypeError: if the operation is not a dictionary. + ValueError: If the operation is malformed. + UnknownError: If the server responds with an unexpected response. + err: If the operation exceeds polling attempts or stop_time + """ + if not isinstance(operation, dict): + raise TypeError('Operation must be a dictionary.') + + if operation.get('done'): + # Operations which are immediately done don't have an operation name + if operation.get('response'): + return operation.get('response') + if operation.get('error'): + raise _utils.handle_operation_error(operation.get('error')) + raise exceptions.UnknownError(message='Internal Error: Malformed Operation.') + + op_name = _validate_operation_name(operation.get('name')) + metadata = operation.get('metadata', {}) + metadata_type = metadata.get('@type', '') + if not metadata_type.endswith('ModelOperationMetadata'): + raise TypeError('Unknown type of operation metadata.') + _, model_id = _validate_and_parse_name(metadata.get('name')) + current_attempt = 0 + start_time = datetime.datetime.now() + stop_time = (None if max_time_seconds is None else + start_time + datetime.timedelta(seconds=max_time_seconds)) + while wait_for_operation and not operation.get('done'): + # We just got this operation. Wait before getting another + # so we don't exceed the GetOperation maximum request rate. + self._exponential_backoff(current_attempt, stop_time) + operation = self.get_operation(op_name) + current_attempt += 1 + + if operation.get('done'): + if operation.get('response'): + return operation.get('response') + if operation.get('error'): + raise _utils.handle_operation_error(operation.get('error')) + + # If the operation is not complete or timed out, return a (locked) model instead + return get_model(model_id).as_dict() + + + def create_model(self, model): + _validate_model(model) + try: + return self.handle_operation( + self._client.body('post', url='models', json=model.as_dict(for_upload=True))) + except requests.exceptions.RequestException as error: + raise _utils.handle_platform_error_from_requests(error) + + def update_model(self, model, update_mask=None): + _validate_model(model, update_mask) + path = 'models/{0}'.format(model.model_id) + if update_mask is not None: + path = path + '?updateMask={0}'.format(update_mask) + try: + return self.handle_operation( + self._client.body('patch', url=path, json=model.as_dict(for_upload=True))) + except requests.exceptions.RequestException as error: + raise _utils.handle_platform_error_from_requests(error) + + def set_published(self, model_id, publish): + _validate_model_id(model_id) + model_name = 'projects/{0}/models/{1}'.format(self._project_id, model_id) + model = Model.from_dict({ + 'name': model_name, + 'state': { + 'published': publish + } + }) + return self.update_model(model, update_mask='state.published') + + def get_model(self, model_id): + _validate_model_id(model_id) + try: + return self._client.body('get', url='models/{0}'.format(model_id)) + except requests.exceptions.RequestException as error: + raise _utils.handle_platform_error_from_requests(error) + + def list_models(self, list_filter, page_size, page_token): + """ lists Firebase ML models.""" + _validate_list_filter(list_filter) + _validate_page_size(page_size) + _validate_page_token(page_token) + params = {} + if list_filter: + params['filter'] = list_filter + if page_size: + params['page_size'] = page_size + if page_token: + params['page_token'] = page_token + path = 'models' + if params: + param_str = parse.urlencode(sorted(params.items()), True) + path = path + '?' + param_str + try: + return self._client.body('get', url=path) + except requests.exceptions.RequestException as error: + raise _utils.handle_platform_error_from_requests(error) + + def delete_model(self, model_id): + _validate_model_id(model_id) + try: + self._client.body('delete', url='models/{0}'.format(model_id)) + except requests.exceptions.RequestException as error: + raise _utils.handle_platform_error_from_requests(error) diff --git a/venv/Lib/site-packages/firebase_admin/project_management.py b/venv/Lib/site-packages/firebase_admin/project_management.py new file mode 100644 index 000000000..ed292b80f --- /dev/null +++ b/venv/Lib/site-packages/firebase_admin/project_management.py @@ -0,0 +1,664 @@ +# Copyright 2018 Google Inc. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +"""Firebase Project Management module. + +This module enables management of resources in Firebase projects, such as Android and iOS apps. +""" + +import base64 +import re +import time + +import requests + +import firebase_admin +from firebase_admin import exceptions +from firebase_admin import _http_client +from firebase_admin import _utils + + +_PROJECT_MANAGEMENT_ATTRIBUTE = '_project_management' + + +def _get_project_management_service(app): + return _utils.get_app_service(app, _PROJECT_MANAGEMENT_ATTRIBUTE, _ProjectManagementService) + + +def android_app(app_id, app=None): + """Obtains a reference to an Android app in the associated Firebase project. + + Args: + app_id: The app ID that identifies this Android app. + app: An App instance (optional). + + Returns: + AndroidApp: An ``AndroidApp`` instance. + """ + return AndroidApp(app_id=app_id, service=_get_project_management_service(app)) + + +def ios_app(app_id, app=None): + """Obtains a reference to an iOS app in the associated Firebase project. + + Args: + app_id: The app ID that identifies this iOS app. + app: An App instance (optional). + + Returns: + IOSApp: An ``IOSApp`` instance. + """ + return IOSApp(app_id=app_id, service=_get_project_management_service(app)) + + +def list_android_apps(app=None): + """Lists all Android apps in the associated Firebase project. + + Args: + app: An App instance (optional). + + Returns: + list: a list of ``AndroidApp`` instances referring to each Android app in the Firebase + project. + """ + return _get_project_management_service(app).list_android_apps() + + +def list_ios_apps(app=None): + """Lists all iOS apps in the associated Firebase project. + + Args: + app: An App instance (optional). + + Returns: + list: a list of ``IOSApp`` instances referring to each iOS app in the Firebase project. + """ + return _get_project_management_service(app).list_ios_apps() + + +def create_android_app(package_name, display_name=None, app=None): + """Creates a new Android app in the associated Firebase project. + + Args: + package_name: The package name of the Android app to be created. + display_name: A nickname for this Android app (optional). + app: An App instance (optional). + + Returns: + AndroidApp: An ``AndroidApp`` instance that is a reference to the newly created app. + """ + return _get_project_management_service(app).create_android_app(package_name, display_name) + + +def create_ios_app(bundle_id, display_name=None, app=None): + """Creates a new iOS app in the associated Firebase project. + + Args: + bundle_id: The bundle ID of the iOS app to be created. + display_name: A nickname for this iOS app (optional). + app: An App instance (optional). + + Returns: + IOSApp: An ``IOSApp`` instance that is a reference to the newly created app. + """ + return _get_project_management_service(app).create_ios_app(bundle_id, display_name) + + +def _check_is_string_or_none(obj, field_name): + if obj is None or isinstance(obj, str): + return obj + raise ValueError('{0} must be a string.'.format(field_name)) + + +def _check_is_nonempty_string(obj, field_name): + if isinstance(obj, str) and obj: + return obj + raise ValueError('{0} must be a non-empty string.'.format(field_name)) + + +def _check_is_nonempty_string_or_none(obj, field_name): + if obj is None: + return None + return _check_is_nonempty_string(obj, field_name) + + +def _check_not_none(obj, field_name): + if obj is None: + raise ValueError('{0} cannot be None.'.format(field_name)) + return obj + + +class AndroidApp: + """A reference to an Android app within a Firebase project. + + Note: Unless otherwise specified, all methods defined in this class make an RPC. + + Please use the module-level function ``android_app(app_id)`` to obtain instances of this class + instead of instantiating it directly. + """ + + def __init__(self, app_id, service): + self._app_id = app_id + self._service = service + + @property + def app_id(self): + """Returns the app ID of the Android app to which this instance refers. + + Note: This method does not make an RPC. + + Returns: + string: The app ID of the Android app to which this instance refers. + """ + return self._app_id + + def get_metadata(self): + """Retrieves detailed information about this Android app. + + Returns: + AndroidAppMetadata: An ``AndroidAppMetadata`` instance. + + Raises: + FirebaseError: If an error occurs while communicating with the Firebase Project + Management Service. + """ + return self._service.get_android_app_metadata(self._app_id) + + def set_display_name(self, new_display_name): + """Updates the display name attribute of this Android app to the one given. + + Args: + new_display_name: The new display name for this Android app. + + Returns: + NoneType: None. + + Raises: + FirebaseError: If an error occurs while communicating with the Firebase Project + Management Service. + """ + return self._service.set_android_app_display_name(self._app_id, new_display_name) + + def get_config(self): + """Retrieves the configuration artifact associated with this Android app.""" + return self._service.get_android_app_config(self._app_id) + + def get_sha_certificates(self): + """Retrieves the entire list of SHA certificates associated with this Android app. + + Returns: + list: A list of ``SHACertificate`` instances. + + Raises: + FirebaseError: If an error occurs while communicating with the Firebase Project + Management Service. + """ + return self._service.get_sha_certificates(self._app_id) + + def add_sha_certificate(self, certificate_to_add): + """Adds a SHA certificate to this Android app. + + Args: + certificate_to_add: The SHA certificate to add. + + Returns: + NoneType: None. + + Raises: + FirebaseError: If an error occurs while communicating with the Firebase Project + Management Service. (For example, if the certificate_to_add already exists.) + """ + return self._service.add_sha_certificate(self._app_id, certificate_to_add) + + def delete_sha_certificate(self, certificate_to_delete): + """Removes a SHA certificate from this Android app. + + Args: + certificate_to_delete: The SHA certificate to delete. + + Returns: + NoneType: None. + + Raises: + FirebaseError: If an error occurs while communicating with the Firebase Project + Management Service. (For example, if the certificate_to_delete is not found.) + """ + return self._service.delete_sha_certificate(certificate_to_delete) + + +class IOSApp: + """A reference to an iOS app within a Firebase project. + + Note: Unless otherwise specified, all methods defined in this class make an RPC. + + Please use the module-level function ``ios_app(app_id)`` to obtain instances of this class + instead of instantiating it directly. + """ + + def __init__(self, app_id, service): + self._app_id = app_id + self._service = service + + @property + def app_id(self): + """Returns the app ID of the iOS app to which this instance refers. + + Note: This method does not make an RPC. + + Returns: + string: The app ID of the iOS app to which this instance refers. + """ + return self._app_id + + def get_metadata(self): + """Retrieves detailed information about this iOS app. + + Returns: + IOSAppMetadata: An ``IOSAppMetadata`` instance. + + Raises: + FirebaseError: If an error occurs while communicating with the Firebase Project + Management Service. + """ + return self._service.get_ios_app_metadata(self._app_id) + + def set_display_name(self, new_display_name): + """Updates the display name attribute of this iOS app to the one given. + + Args: + new_display_name: The new display name for this iOS app. + + Returns: + NoneType: None. + + Raises: + FirebaseError: If an error occurs while communicating with the Firebase Project + Management Service. + """ + return self._service.set_ios_app_display_name(self._app_id, new_display_name) + + def get_config(self): + """Retrieves the configuration artifact associated with this iOS app.""" + return self._service.get_ios_app_config(self._app_id) + + +class _AppMetadata: + """Detailed information about a Firebase Android or iOS app.""" + + def __init__(self, name, app_id, display_name, project_id): + # _name is the fully qualified resource name of this Android or iOS app; currently it is not + # exposed to client code. + self._name = _check_is_nonempty_string(name, 'name') + self._app_id = _check_is_nonempty_string(app_id, 'app_id') + self._display_name = _check_is_string_or_none(display_name, 'display_name') + self._project_id = _check_is_nonempty_string(project_id, 'project_id') + + @property + def app_id(self): + """The globally unique, Firebase-assigned identifier of this Android or iOS app. + + This ID is unique even across apps of different platforms. + """ + return self._app_id + + @property + def display_name(self): + """The user-assigned display name of this Android or iOS app. + + Note that the display name can be None if it has never been set by the user.""" + return self._display_name + + @property + def project_id(self): + """The permanent, globally unique, user-assigned ID of the parent Firebase project.""" + return self._project_id + + def __eq__(self, other): + if not isinstance(other, type(self)): + return False + # pylint: disable=protected-access + return (self._name == other._name and self.app_id == other.app_id and + self.display_name == other.display_name and self.project_id == other.project_id) + # pylint: enable=protected-access + + +class AndroidAppMetadata(_AppMetadata): + """Android-specific information about an Android Firebase app.""" + + def __init__(self, package_name, name, app_id, display_name, project_id): + """Clients should not instantiate this class directly.""" + super(AndroidAppMetadata, self).__init__(name, app_id, display_name, project_id) + self._package_name = _check_is_nonempty_string(package_name, 'package_name') + + @property + def package_name(self): + """The canonical package name of this Android app as it would appear in the Play Store.""" + return self._package_name + + def __eq__(self, other): + return (super(AndroidAppMetadata, self).__eq__(other) and + self.package_name == other.package_name) + + def __ne__(self, other): + return not self.__eq__(other) + + def __hash__(self): + return hash( + (self._name, self.app_id, self.display_name, self.project_id, self.package_name)) + + +class IOSAppMetadata(_AppMetadata): + """iOS-specific information about an iOS Firebase app.""" + + def __init__(self, bundle_id, name, app_id, display_name, project_id): + """Clients should not instantiate this class directly.""" + super(IOSAppMetadata, self).__init__(name, app_id, display_name, project_id) + self._bundle_id = _check_is_nonempty_string(bundle_id, 'bundle_id') + + @property + def bundle_id(self): + """The canonical bundle ID of this iOS app as it would appear in the iOS AppStore.""" + return self._bundle_id + + def __eq__(self, other): + return super(IOSAppMetadata, self).__eq__(other) and self.bundle_id == other.bundle_id + + def __ne__(self, other): + return not self.__eq__(other) + + def __hash__(self): + return hash((self._name, self.app_id, self.display_name, self.project_id, self.bundle_id)) + + +class SHACertificate: + """Represents a SHA-1 or SHA-256 certificate associated with an Android app.""" + + SHA_1 = 'SHA_1' + SHA_256 = 'SHA_256' + + _SHA_1_RE = re.compile('^[0-9A-Fa-f]{40}$') + _SHA_256_RE = re.compile('^[0-9A-Fa-f]{64}$') + + def __init__(self, sha_hash, name=None): + """Creates a new SHACertificate instance. + + Args: + sha_hash: A string; the certificate hash for the Android app. + name: The fully qualified resource name of this certificate; note that this field should + be omitted if the instance is being constructed for the purpose of calling the + add_sha_certificate() method on an ``AndroidApp``. + + Raises: + ValueError: If the sha_hash is not a valid SHA-1 or SHA-256 certificate hash. + """ + _check_is_nonempty_string(sha_hash, 'sha_hash') + _check_is_nonempty_string_or_none(name, 'name') + self._name = name + self._sha_hash = sha_hash.lower() + if SHACertificate._SHA_1_RE.match(sha_hash): + self._cert_type = SHACertificate.SHA_1 + elif SHACertificate._SHA_256_RE.match(sha_hash): + self._cert_type = SHACertificate.SHA_256 + else: + raise ValueError( + 'The supplied certificate hash is neither a valid SHA-1 nor SHA_256 hash.') + + @property + def name(self): + """Returns the fully qualified resource name of this certificate, if known. + + Returns: + string: The fully qualified resource name of this certificate, if known; otherwise, the + empty string. + """ + return self._name + + @property + def sha_hash(self): + """Returns the certificate hash. + + Returns: + string: The certificate hash. + """ + return self._sha_hash + + @property + def cert_type(self): + """Returns the type of the SHA certificate encoded in the hash. + + Returns: + string: One of 'SHA_1' or 'SHA_256'. + """ + return self._cert_type + + def __eq__(self, other): + if not isinstance(other, SHACertificate): + return False + return (self.name == other.name and self.sha_hash == other.sha_hash and + self.cert_type == other.cert_type) + + def __ne__(self, other): + return not self.__eq__(other) + + def __hash__(self): + return hash((self.name, self.sha_hash, self.cert_type)) + + +class _ProjectManagementService: + """Provides methods for interacting with the Firebase Project Management Service.""" + + BASE_URL = 'https://firebase.googleapis.com' + MAXIMUM_LIST_APPS_PAGE_SIZE = 100 + MAXIMUM_POLLING_ATTEMPTS = 8 + POLL_BASE_WAIT_TIME_SECONDS = 0.5 + POLL_EXPONENTIAL_BACKOFF_FACTOR = 1.5 + + ANDROID_APPS_RESOURCE_NAME = 'androidApps' + ANDROID_APP_IDENTIFIER_NAME = 'packageName' + IOS_APPS_RESOURCE_NAME = 'iosApps' + IOS_APP_IDENTIFIER_NAME = 'bundleId' + + def __init__(self, app): + project_id = app.project_id + if not project_id: + raise ValueError( + 'Project ID is required to access the Firebase Project Management Service. Either ' + 'set the projectId option, or use service account credentials. Alternatively, set ' + 'the GOOGLE_CLOUD_PROJECT environment variable.') + self._project_id = project_id + version_header = 'Python/Admin/{0}'.format(firebase_admin.__version__) + timeout = app.options.get('httpTimeout', _http_client.DEFAULT_TIMEOUT_SECONDS) + self._client = _http_client.JsonHttpClient( + credential=app.credential.get_credential(), + base_url=_ProjectManagementService.BASE_URL, + headers={'X-Client-Version': version_header}, + timeout=timeout) + + def get_android_app_metadata(self, app_id): + return self._get_app_metadata( + platform_resource_name=_ProjectManagementService.ANDROID_APPS_RESOURCE_NAME, + identifier_name=_ProjectManagementService.ANDROID_APP_IDENTIFIER_NAME, + metadata_class=AndroidAppMetadata, + app_id=app_id) + + def get_ios_app_metadata(self, app_id): + return self._get_app_metadata( + platform_resource_name=_ProjectManagementService.IOS_APPS_RESOURCE_NAME, + identifier_name=_ProjectManagementService.IOS_APP_IDENTIFIER_NAME, + metadata_class=IOSAppMetadata, + app_id=app_id) + + def _get_app_metadata(self, platform_resource_name, identifier_name, metadata_class, app_id): + """Retrieves detailed information about an Android or iOS app.""" + _check_is_nonempty_string(app_id, 'app_id') + path = '/v1beta1/projects/-/{0}/{1}'.format(platform_resource_name, app_id) + response = self._make_request('get', path) + return metadata_class( + response[identifier_name], + name=response['name'], + app_id=response['appId'], + display_name=response.get('displayName') or None, + project_id=response['projectId']) + + def set_android_app_display_name(self, app_id, new_display_name): + self._set_display_name( + app_id=app_id, + new_display_name=new_display_name, + platform_resource_name=_ProjectManagementService.ANDROID_APPS_RESOURCE_NAME) + + def set_ios_app_display_name(self, app_id, new_display_name): + self._set_display_name( + app_id=app_id, + new_display_name=new_display_name, + platform_resource_name=_ProjectManagementService.IOS_APPS_RESOURCE_NAME) + + def _set_display_name(self, app_id, new_display_name, platform_resource_name): + """Sets the display name of an Android or iOS app.""" + path = '/v1beta1/projects/-/{0}/{1}?updateMask=displayName'.format( + platform_resource_name, app_id) + request_body = {'displayName': new_display_name} + self._make_request('patch', path, json=request_body) + + def list_android_apps(self): + return self._list_apps( + platform_resource_name=_ProjectManagementService.ANDROID_APPS_RESOURCE_NAME, + app_class=AndroidApp) + + def list_ios_apps(self): + return self._list_apps( + platform_resource_name=_ProjectManagementService.IOS_APPS_RESOURCE_NAME, + app_class=IOSApp) + + def _list_apps(self, platform_resource_name, app_class): + """Lists all the Android or iOS apps within the Firebase project.""" + path = '/v1beta1/projects/{0}/{1}?pageSize={2}'.format( + self._project_id, + platform_resource_name, + _ProjectManagementService.MAXIMUM_LIST_APPS_PAGE_SIZE) + response = self._make_request('get', path) + apps_list = [] + while True: + apps = response.get('apps') + if not apps: + break + apps_list.extend(app_class(app_id=app['appId'], service=self) for app in apps) + next_page_token = response.get('nextPageToken') + if not next_page_token: + break + # Retrieve the next page of apps. + path = '/v1beta1/projects/{0}/{1}?pageToken={2}&pageSize={3}'.format( + self._project_id, + platform_resource_name, + next_page_token, + _ProjectManagementService.MAXIMUM_LIST_APPS_PAGE_SIZE) + response = self._make_request('get', path) + return apps_list + + def create_android_app(self, package_name, display_name=None): + return self._create_app( + platform_resource_name=_ProjectManagementService.ANDROID_APPS_RESOURCE_NAME, + identifier_name=_ProjectManagementService.ANDROID_APP_IDENTIFIER_NAME, + identifier=package_name, + display_name=display_name, + app_class=AndroidApp) + + def create_ios_app(self, bundle_id, display_name=None): + return self._create_app( + platform_resource_name=_ProjectManagementService.IOS_APPS_RESOURCE_NAME, + identifier_name=_ProjectManagementService.IOS_APP_IDENTIFIER_NAME, + identifier=bundle_id, + display_name=display_name, + app_class=IOSApp) + + def _create_app( + self, + platform_resource_name, + identifier_name, + identifier, + display_name, + app_class): + """Creates an Android or iOS app.""" + _check_is_string_or_none(display_name, 'display_name') + path = '/v1beta1/projects/{0}/{1}'.format(self._project_id, platform_resource_name) + request_body = {identifier_name: identifier} + if display_name: + request_body['displayName'] = display_name + response = self._make_request('post', path, json=request_body) + operation_name = response['name'] + poll_response = self._poll_app_creation(operation_name) + return app_class(app_id=poll_response['appId'], service=self) + + def _poll_app_creation(self, operation_name): + """Polls the Long-Running Operation repeatedly until it is done with exponential backoff.""" + for current_attempt in range(_ProjectManagementService.MAXIMUM_POLLING_ATTEMPTS): + delay_factor = pow( + _ProjectManagementService.POLL_EXPONENTIAL_BACKOFF_FACTOR, current_attempt) + wait_time_seconds = delay_factor * _ProjectManagementService.POLL_BASE_WAIT_TIME_SECONDS + time.sleep(wait_time_seconds) + path = '/v1/{0}'.format(operation_name) + poll_response, http_response = self._body_and_response('get', path) + done = poll_response.get('done') + if done: + response = poll_response.get('response') + if response: + return response + + raise exceptions.UnknownError( + 'Polling finished, but the operation terminated in an error.', + http_response=http_response) + raise exceptions.DeadlineExceededError('Polling deadline exceeded.') + + def get_android_app_config(self, app_id): + return self._get_app_config( + platform_resource_name=_ProjectManagementService.ANDROID_APPS_RESOURCE_NAME, + app_id=app_id) + + def get_ios_app_config(self, app_id): + return self._get_app_config( + platform_resource_name=_ProjectManagementService.IOS_APPS_RESOURCE_NAME, app_id=app_id) + + def _get_app_config(self, platform_resource_name, app_id): + path = '/v1beta1/projects/-/{0}/{1}/config'.format(platform_resource_name, app_id) + response = self._make_request('get', path) + # In Python 2.7, the base64 module works with strings, while in Python 3, it works with + # bytes objects. This line works in both versions. + return base64.standard_b64decode(response['configFileContents']).decode(encoding='utf-8') + + def get_sha_certificates(self, app_id): + path = '/v1beta1/projects/-/androidApps/{0}/sha'.format(app_id) + response = self._make_request('get', path) + cert_list = response.get('certificates') or [] + return [SHACertificate(sha_hash=cert['shaHash'], name=cert['name']) for cert in cert_list] + + def add_sha_certificate(self, app_id, certificate_to_add): + path = '/v1beta1/projects/-/androidApps/{0}/sha'.format(app_id) + sha_hash = _check_not_none(certificate_to_add, 'certificate_to_add').sha_hash + cert_type = certificate_to_add.cert_type + request_body = {'shaHash': sha_hash, 'certType': cert_type} + self._make_request('post', path, json=request_body) + + def delete_sha_certificate(self, certificate_to_delete): + name = _check_not_none(certificate_to_delete, 'certificate_to_delete').name + path = '/v1beta1/{0}'.format(name) + self._make_request('delete', path) + + def _make_request(self, method, url, json=None): + body, _ = self._body_and_response(method, url, json) + return body + + def _body_and_response(self, method, url, json=None): + try: + return self._client.body_and_response(method=method, url=url, json=json) + except requests.exceptions.RequestException as error: + raise _utils.handle_platform_error_from_requests(error) diff --git a/venv/Lib/site-packages/firebase_admin/storage.py b/venv/Lib/site-packages/firebase_admin/storage.py new file mode 100644 index 000000000..16f48e273 --- /dev/null +++ b/venv/Lib/site-packages/firebase_admin/storage.py @@ -0,0 +1,82 @@ +# Copyright 2017 Google Inc. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +"""Firebase Cloud Storage module. + +This module contains utilities for accessing Google Cloud Storage buckets associated with +Firebase apps. This requires the ``google-cloud-storage`` Python module. +""" + +# pylint: disable=import-error,no-name-in-module +try: + from google.cloud import storage +except ImportError: + raise ImportError('Failed to import the Cloud Storage library for Python. Make sure ' + 'to install the "google-cloud-storage" module.') + +from firebase_admin import _utils + + +_STORAGE_ATTRIBUTE = '_storage' + +def bucket(name=None, app=None): + """Returns a handle to a Google Cloud Storage bucket. + + If the name argument is not provided, uses the 'storageBucket' option specified when + initializing the App. If that is also not available raises an error. This function + does not make any RPC calls. + + Args: + name: Name of a cloud storage bucket (optional). + app: An App instance (optional). + + Returns: + google.cloud.storage.Bucket: A handle to the specified bucket. + + Raises: + ValueError: If a bucket name is not specified either via options or method arguments, + or if the specified bucket name is not a valid string. + """ + client = _utils.get_app_service(app, _STORAGE_ATTRIBUTE, _StorageClient.from_app) + return client.bucket(name) + + +class _StorageClient: + """Holds a Google Cloud Storage client instance.""" + + def __init__(self, credentials, project, default_bucket): + self._client = storage.Client(credentials=credentials, project=project) + self._default_bucket = default_bucket + + @classmethod + def from_app(cls, app): + credentials = app.credential.get_credential() + default_bucket = app.options.get('storageBucket') + # Specifying project ID is not required, but providing it when available + # significantly speeds up the initialization of the storage client. + return _StorageClient(credentials, app.project_id, default_bucket) + + def bucket(self, name=None): + """Returns a handle to the specified Cloud Storage Bucket.""" + bucket_name = name if name is not None else self._default_bucket + if bucket_name is None: + raise ValueError( + 'Storage bucket name not specified. Specify the bucket name via the ' + '"storageBucket" option when initializing the App, or specify the bucket ' + 'name explicitly when calling the storage.bucket() function.') + if not bucket_name or not isinstance(bucket_name, str): + raise ValueError( + 'Invalid storage bucket name: "{0}". Bucket name must be a non-empty ' + 'string.'.format(bucket_name)) + return self._client.bucket(bucket_name) diff --git a/venv/Lib/site-packages/firebase_admin/tenant_mgt.py b/venv/Lib/site-packages/firebase_admin/tenant_mgt.py new file mode 100644 index 000000000..396a819fb --- /dev/null +++ b/venv/Lib/site-packages/firebase_admin/tenant_mgt.py @@ -0,0 +1,445 @@ +# Copyright 2020 Google Inc. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +"""Firebase tenant management module. + +This module contains functions for creating and configuring authentication tenants within a +Google Cloud Identity Platform (GCIP) instance. +""" + +import re +import threading + +import requests + +import firebase_admin +from firebase_admin import auth +from firebase_admin import _auth_utils +from firebase_admin import _http_client +from firebase_admin import _utils + + +_TENANT_MGT_ATTRIBUTE = '_tenant_mgt' +_MAX_LIST_TENANTS_RESULTS = 100 +_DISPLAY_NAME_PATTERN = re.compile('^[a-zA-Z][a-zA-Z0-9-]{3,19}$') + + +__all__ = [ + 'ListTenantsPage', + 'Tenant', + 'TenantIdMismatchError', + 'TenantNotFoundError', + + 'auth_for_tenant', + 'create_tenant', + 'delete_tenant', + 'get_tenant', + 'list_tenants', + 'update_tenant', +] + + +TenantIdMismatchError = _auth_utils.TenantIdMismatchError +TenantNotFoundError = _auth_utils.TenantNotFoundError + + +def auth_for_tenant(tenant_id, app=None): + """Gets an Auth Client instance scoped to the given tenant ID. + + Args: + tenant_id: A tenant ID string. + app: An App instance (optional). + + Returns: + auth.Client: An ``auth.Client`` object. + + Raises: + ValueError: If the tenant ID is None, empty or not a string. + """ + tenant_mgt_service = _get_tenant_mgt_service(app) + return tenant_mgt_service.auth_for_tenant(tenant_id) + + +def get_tenant(tenant_id, app=None): + """Gets the tenant corresponding to the given ``tenant_id``. + + Args: + tenant_id: A tenant ID string. + app: An App instance (optional). + + Returns: + Tenant: A tenant object. + + Raises: + ValueError: If the tenant ID is None, empty or not a string. + TenantNotFoundError: If no tenant exists by the given ID. + FirebaseError: If an error occurs while retrieving the tenant. + """ + tenant_mgt_service = _get_tenant_mgt_service(app) + return tenant_mgt_service.get_tenant(tenant_id) + + +def create_tenant( + display_name, allow_password_sign_up=None, enable_email_link_sign_in=None, app=None): + """Creates a new tenant from the given options. + + Args: + display_name: Display name string for the new tenant. Must begin with a letter and contain + only letters, digits and hyphens. Length must be between 4 and 20. + allow_password_sign_up: A boolean indicating whether to enable or disable the email sign-in + provider (optional). + enable_email_link_sign_in: A boolean indicating whether to enable or disable email link + sign-in (optional). Disabling this makes the password required for email sign-in. + app: An App instance (optional). + + Returns: + Tenant: A tenant object. + + Raises: + ValueError: If any of the given arguments are invalid. + FirebaseError: If an error occurs while creating the tenant. + """ + tenant_mgt_service = _get_tenant_mgt_service(app) + return tenant_mgt_service.create_tenant( + display_name=display_name, allow_password_sign_up=allow_password_sign_up, + enable_email_link_sign_in=enable_email_link_sign_in) + + +def update_tenant( + tenant_id, display_name=None, allow_password_sign_up=None, enable_email_link_sign_in=None, + app=None): + """Updates an existing tenant with the given options. + + Args: + tenant_id: ID of the tenant to update. + display_name: Updated display name string for the tenant (optional). + allow_password_sign_up: A boolean indicating whether to enable or disable the email sign-in + provider. + enable_email_link_sign_in: A boolean indicating whether to enable or disable email link + sign-in. Disabling this makes the password required for email sign-in. + app: An App instance (optional). + + Returns: + Tenant: The updated tenant object. + + Raises: + ValueError: If any of the given arguments are invalid. + TenantNotFoundError: If no tenant exists by the given ID. + FirebaseError: If an error occurs while creating the tenant. + """ + tenant_mgt_service = _get_tenant_mgt_service(app) + return tenant_mgt_service.update_tenant( + tenant_id, display_name=display_name, allow_password_sign_up=allow_password_sign_up, + enable_email_link_sign_in=enable_email_link_sign_in) + + +def delete_tenant(tenant_id, app=None): + """Deletes the tenant corresponding to the given ``tenant_id``. + + Args: + tenant_id: A tenant ID string. + app: An App instance (optional). + + Raises: + ValueError: If the tenant ID is None, empty or not a string. + TenantNotFoundError: If no tenant exists by the given ID. + FirebaseError: If an error occurs while retrieving the tenant. + """ + tenant_mgt_service = _get_tenant_mgt_service(app) + tenant_mgt_service.delete_tenant(tenant_id) + + +def list_tenants(page_token=None, max_results=_MAX_LIST_TENANTS_RESULTS, app=None): + """Retrieves a page of tenants from a Firebase project. + + The ``page_token`` argument governs the starting point of the page. The ``max_results`` + argument governs the maximum number of tenants that may be included in the returned page. + This function never returns None. If there are no user accounts in the Firebase project, this + returns an empty page. + + Args: + page_token: A non-empty page token string, which indicates the starting point of the page + (optional). Defaults to ``None``, which will retrieve the first page of users. + max_results: A positive integer indicating the maximum number of users to include in the + returned page (optional). Defaults to 100, which is also the maximum number allowed. + app: An App instance (optional). + + Returns: + ListTenantsPage: A page of tenants. + + Raises: + ValueError: If ``max_results`` or ``page_token`` are invalid. + FirebaseError: If an error occurs while retrieving the user accounts. + """ + tenant_mgt_service = _get_tenant_mgt_service(app) + def download(page_token, max_results): + return tenant_mgt_service.list_tenants(page_token, max_results) + return ListTenantsPage(download, page_token, max_results) + + +def _get_tenant_mgt_service(app): + return _utils.get_app_service(app, _TENANT_MGT_ATTRIBUTE, _TenantManagementService) + + +class Tenant: + """Represents a tenant in a multi-tenant application. + + Multi-tenancy support requires Google Cloud Identity Platform (GCIP). To learn more about + GCIP including pricing and features, see https://cloud.google.com/identity-platform. + + Before multi-tenancy can be used in a Google Cloud Identity Platform project, tenants must be + enabled in that project via the Cloud Console UI. A Tenant instance provides information + such as the display name, tenant identifier and email authentication configuration. + """ + + def __init__(self, data): + if not isinstance(data, dict): + raise ValueError('Invalid data argument in Tenant constructor: {0}'.format(data)) + if not 'name' in data: + raise ValueError('Tenant response missing required keys.') + + self._data = data + + @property + def tenant_id(self): + name = self._data['name'] + return name.split('/')[-1] + + @property + def display_name(self): + return self._data.get('displayName') + + @property + def allow_password_sign_up(self): + return self._data.get('allowPasswordSignup', False) + + @property + def enable_email_link_sign_in(self): + return self._data.get('enableEmailLinkSignin', False) + + +class _TenantManagementService: + """Firebase tenant management service.""" + + TENANT_MGT_URL = 'https://identitytoolkit.googleapis.com/v2beta1' + + def __init__(self, app): + credential = app.credential.get_credential() + version_header = 'Python/Admin/{0}'.format(firebase_admin.__version__) + base_url = '{0}/projects/{1}'.format(self.TENANT_MGT_URL, app.project_id) + self.app = app + self.client = _http_client.JsonHttpClient( + credential=credential, base_url=base_url, headers={'X-Client-Version': version_header}) + self.tenant_clients = {} + self.lock = threading.RLock() + + def auth_for_tenant(self, tenant_id): + """Gets an Auth Client instance scoped to the given tenant ID.""" + if not isinstance(tenant_id, str) or not tenant_id: + raise ValueError( + 'Invalid tenant ID: {0}. Tenant ID must be a non-empty string.'.format(tenant_id)) + + with self.lock: + if tenant_id in self.tenant_clients: + return self.tenant_clients[tenant_id] + + client = auth.Client(self.app, tenant_id=tenant_id) + self.tenant_clients[tenant_id] = client + return client + + def get_tenant(self, tenant_id): + """Gets the tenant corresponding to the given ``tenant_id``.""" + if not isinstance(tenant_id, str) or not tenant_id: + raise ValueError( + 'Invalid tenant ID: {0}. Tenant ID must be a non-empty string.'.format(tenant_id)) + + try: + body = self.client.body('get', '/tenants/{0}'.format(tenant_id)) + except requests.exceptions.RequestException as error: + raise _auth_utils.handle_auth_backend_error(error) + else: + return Tenant(body) + + def create_tenant( + self, display_name, allow_password_sign_up=None, enable_email_link_sign_in=None): + """Creates a new tenant from the given parameters.""" + + payload = {'displayName': _validate_display_name(display_name)} + if allow_password_sign_up is not None: + payload['allowPasswordSignup'] = _auth_utils.validate_boolean( + allow_password_sign_up, 'allowPasswordSignup') + if enable_email_link_sign_in is not None: + payload['enableEmailLinkSignin'] = _auth_utils.validate_boolean( + enable_email_link_sign_in, 'enableEmailLinkSignin') + + try: + body = self.client.body('post', '/tenants', json=payload) + except requests.exceptions.RequestException as error: + raise _auth_utils.handle_auth_backend_error(error) + else: + return Tenant(body) + + def update_tenant( + self, tenant_id, display_name=None, allow_password_sign_up=None, + enable_email_link_sign_in=None): + """Updates the specified tenant with the given parameters.""" + if not isinstance(tenant_id, str) or not tenant_id: + raise ValueError('Tenant ID must be a non-empty string.') + + payload = {} + if display_name is not None: + payload['displayName'] = _validate_display_name(display_name) + if allow_password_sign_up is not None: + payload['allowPasswordSignup'] = _auth_utils.validate_boolean( + allow_password_sign_up, 'allowPasswordSignup') + if enable_email_link_sign_in is not None: + payload['enableEmailLinkSignin'] = _auth_utils.validate_boolean( + enable_email_link_sign_in, 'enableEmailLinkSignin') + + if not payload: + raise ValueError('At least one parameter must be specified for update.') + + url = '/tenants/{0}'.format(tenant_id) + update_mask = ','.join(_auth_utils.build_update_mask(payload)) + params = 'updateMask={0}'.format(update_mask) + try: + body = self.client.body('patch', url, json=payload, params=params) + except requests.exceptions.RequestException as error: + raise _auth_utils.handle_auth_backend_error(error) + else: + return Tenant(body) + + def delete_tenant(self, tenant_id): + """Deletes the tenant corresponding to the given ``tenant_id``.""" + if not isinstance(tenant_id, str) or not tenant_id: + raise ValueError( + 'Invalid tenant ID: {0}. Tenant ID must be a non-empty string.'.format(tenant_id)) + + try: + self.client.request('delete', '/tenants/{0}'.format(tenant_id)) + except requests.exceptions.RequestException as error: + raise _auth_utils.handle_auth_backend_error(error) + + def list_tenants(self, page_token=None, max_results=_MAX_LIST_TENANTS_RESULTS): + """Retrieves a batch of tenants.""" + if page_token is not None: + if not isinstance(page_token, str) or not page_token: + raise ValueError('Page token must be a non-empty string.') + if not isinstance(max_results, int): + raise ValueError('Max results must be an integer.') + if max_results < 1 or max_results > _MAX_LIST_TENANTS_RESULTS: + raise ValueError( + 'Max results must be a positive integer less than or equal to ' + '{0}.'.format(_MAX_LIST_TENANTS_RESULTS)) + + payload = {'pageSize': max_results} + if page_token: + payload['pageToken'] = page_token + try: + return self.client.body('get', '/tenants', params=payload) + except requests.exceptions.RequestException as error: + raise _auth_utils.handle_auth_backend_error(error) + + +class ListTenantsPage: + """Represents a page of tenants fetched from a Firebase project. + + Provides methods for traversing tenants included in this page, as well as retrieving + subsequent pages of tenants. The iterator returned by ``iterate_all()`` can be used to iterate + through all tenants in the Firebase project starting from this page. + """ + + def __init__(self, download, page_token, max_results): + self._download = download + self._max_results = max_results + self._current = download(page_token, max_results) + + @property + def tenants(self): + """A list of ``ExportedUserRecord`` instances available in this page.""" + return [Tenant(data) for data in self._current.get('tenants', [])] + + @property + def next_page_token(self): + """Page token string for the next page (empty string indicates no more pages).""" + return self._current.get('nextPageToken', '') + + @property + def has_next_page(self): + """A boolean indicating whether more pages are available.""" + return bool(self.next_page_token) + + def get_next_page(self): + """Retrieves the next page of tenants, if available. + + Returns: + ListTenantsPage: Next page of tenants, or None if this is the last page. + """ + if self.has_next_page: + return ListTenantsPage(self._download, self.next_page_token, self._max_results) + return None + + def iterate_all(self): + """Retrieves an iterator for tenants. + + Returned iterator will iterate through all the tenants in the Firebase project + starting from this page. The iterator will never buffer more than one page of tenants + in memory at a time. + + Returns: + iterator: An iterator of Tenant instances. + """ + return _TenantIterator(self) + + +class _TenantIterator: + """An iterator that allows iterating over tenants. + + This implementation loads a page of tenants into memory, and iterates on them. When the whole + page has been traversed, it loads another page. This class never keeps more than one page + of entries in memory. + """ + + def __init__(self, current_page): + if not current_page: + raise ValueError('Current page must not be None.') + self._current_page = current_page + self._index = 0 + + def next(self): + if self._index == len(self._current_page.tenants): + if self._current_page.has_next_page: + self._current_page = self._current_page.get_next_page() + self._index = 0 + if self._index < len(self._current_page.tenants): + result = self._current_page.tenants[self._index] + self._index += 1 + return result + raise StopIteration + + def __next__(self): + return self.next() + + def __iter__(self): + return self + + +def _validate_display_name(display_name): + if not isinstance(display_name, str): + raise ValueError('Invalid type for displayName') + if not _DISPLAY_NAME_PATTERN.search(display_name): + raise ValueError( + 'displayName must start with a letter and only consist of letters, digits and ' + 'hyphens with 4-20 characters.') + return display_name diff --git a/venv/Lib/site-packages/google/_async_resumable_media/__init__.py b/venv/Lib/site-packages/google/_async_resumable_media/__init__.py new file mode 100644 index 000000000..8c3da244e --- /dev/null +++ b/venv/Lib/site-packages/google/_async_resumable_media/__init__.py @@ -0,0 +1,61 @@ +# Copyright 2017 Google Inc. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +"""Utilities for Google Media Downloads and Resumable Uploads. + +This package has some general purposes modules, e.g. +:mod:`~google.resumable_media.common`, but the majority of the +public interface will be contained in subpackages. + +=========== +Subpackages +=========== + +Each subpackage is tailored to a specific transport library: + +* the :mod:`~google.resumable_media.requests` subpackage uses the ``requests`` + transport library. + +.. _requests: http://docs.python-requests.org/ + +========== +Installing +========== + +To install with `pip`_: + +.. code-block:: console + + $ pip install --upgrade google-resumable-media + +.. _pip: https://pip.pypa.io/ +""" + + +from google.resumable_media.common import DataCorruption +from google.resumable_media.common import InvalidResponse +from google.resumable_media.common import PERMANENT_REDIRECT +from google.resumable_media.common import RetryStrategy +from google.resumable_media.common import TOO_MANY_REQUESTS +from google.resumable_media.common import UPLOAD_CHUNK_SIZE + + +__all__ = [ + u"DataCorruption", + u"InvalidResponse", + u"PERMANENT_REDIRECT", + u"RetryStrategy", + u"TOO_MANY_REQUESTS", + u"UPLOAD_CHUNK_SIZE", +] diff --git a/venv/Lib/site-packages/google/_async_resumable_media/__pycache__/__init__.cpython-36.pyc b/venv/Lib/site-packages/google/_async_resumable_media/__pycache__/__init__.cpython-36.pyc new file mode 100644 index 0000000000000000000000000000000000000000..6338182b1ae764dcb329c5fc8eaca46bea322ad8 GIT binary patch literal 1255 zcmaJ=&2H2>6wdr~rsPr(tk@u(1)Bns5f?U$0D;;OR6q;!v$#>qZO?PR@h zn_ZiFyVvRGw&%^AD1;N-!a^B%sZ>^Qc*~ifu&+*Kp(wLJC4&jKRY?<+&UM2Le1Db; z3!0|KG~)Ky z_&y|+1DA6s=?7(mTY_5DcVAaYAyN?1akHQ)hf`4$kZ?$qbW}*rPzJV2&f~He=hHu* zKm8;5AKxF-G~aj!m>SwEltGJ50R^jhDi-M587i$-#z7$xL(OvJ`*)jQFVD^Jj}^Dh z#+z=cxh_%o$!F+P(%MG&bqhTI=i+{9oLoONB!|0K&iaI4c?k(`UplUr8>+2f=?VGj z8Naq(lV9J`QG~rWHcF_g@<`$28garS#_h3FI;x~NRpvNaa%$jFWO<3R!wo!$Ql33} z{NUe68})&wE;`}4NO3W#bYg&`v~bXDhT*BoByP9Dg;?U_5>@3%^hP9+6^;+qD-x}; u8xm@lGQ|-)@8D`DhlB{ULI^hPZ2QS-o1fjoB+>75Mue*X literal 0 HcmV?d00001 diff --git a/venv/Lib/site-packages/google/_async_resumable_media/__pycache__/_download.cpython-36.pyc b/venv/Lib/site-packages/google/_async_resumable_media/__pycache__/_download.cpython-36.pyc new file mode 100644 index 0000000000000000000000000000000000000000..67e18add276e23cf8ab447746035098853d0f889 GIT binary patch literal 18490 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 bKmiz%2o(?{Yn)p@*FN`0sdn+rxzGI%*SJ`z literal 0 HcmV?d00001 diff --git a/venv/Lib/site-packages/google/_async_resumable_media/__pycache__/_helpers.cpython-36.pyc b/venv/Lib/site-packages/google/_async_resumable_media/__pycache__/_helpers.cpython-36.pyc new file mode 100644 index 0000000000000000000000000000000000000000..76dec292a54a496e6d3fc425a884d9afbebed139 GIT binary patch literal 6003 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 wG;L>_Vx_eD%Id3?mnuK_523U0`v3p{ literal 0 HcmV?d00001 diff --git a/venv/Lib/site-packages/google/_async_resumable_media/__pycache__/_upload.cpython-36.pyc b/venv/Lib/site-packages/google/_async_resumable_media/__pycache__/_upload.cpython-36.pyc new file mode 100644 index 0000000000000000000000000000000000000000..ba8290cb2cd4cb57220c5312b6d257ce99a521ab GIT binary patch literal 33053 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 D75U6Z literal 0 HcmV?d00001 diff --git a/venv/Lib/site-packages/google/_async_resumable_media/_download.py b/venv/Lib/site-packages/google/_async_resumable_media/_download.py new file mode 100644 index 000000000..0c9e61ef3 --- /dev/null +++ b/venv/Lib/site-packages/google/_async_resumable_media/_download.py @@ -0,0 +1,553 @@ +# Copyright 2017 Google Inc. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +"""Virtual bases classes for downloading media from Google APIs.""" + + +import re + +from six.moves import http_client + + +from google._async_resumable_media import _helpers +from google.resumable_media import common + + +_CONTENT_RANGE_RE = re.compile( + r"bytes (?P\d+)-(?P\d+)/(?P\d+)", + flags=re.IGNORECASE, +) +_ACCEPTABLE_STATUS_CODES = (http_client.OK, http_client.PARTIAL_CONTENT) +_GET = u"GET" +_ZERO_CONTENT_RANGE_HEADER = u"bytes */0" + + +class DownloadBase(object): + """Base class for download helpers. + + Defines core shared behavior across different download types. + + Args: + media_url (str): The URL containing the media to be downloaded. + stream (IO[bytes]): A write-able stream (i.e. file-like object) that + the downloaded resource can be written to. + start (int): The first byte in a range to be downloaded. + end (int): The last byte in a range to be downloaded. + headers (Optional[Mapping[str, str]]): Extra headers that should + be sent with the request, e.g. headers for encrypted data. + + Attributes: + media_url (str): The URL containing the media to be downloaded. + start (Optional[int]): The first byte in a range to be downloaded. + end (Optional[int]): The last byte in a range to be downloaded. + """ + + def __init__(self, media_url, stream=None, start=None, end=None, headers=None): + self.media_url = media_url + self._stream = stream + self.start = start + self.end = end + if headers is None: + headers = {} + self._headers = headers + self._finished = False + self._retry_strategy = common.RetryStrategy() + + @property + def finished(self): + """bool: Flag indicating if the download has completed.""" + return self._finished + + @staticmethod + def _get_status_code(response): + """Access the status code from an HTTP response. + + Args: + response (object): The HTTP response object. + + Raises: + NotImplementedError: Always, since virtual. + """ + raise NotImplementedError(u"This implementation is virtual.") + + @staticmethod + def _get_headers(response): + """Access the headers from an HTTP response. + + Args: + response (object): The HTTP response object. + + Raises: + NotImplementedError: Always, since virtual. + """ + raise NotImplementedError(u"This implementation is virtual.") + + @staticmethod + def _get_body(response): + """Access the response body from an HTTP response. + + Args: + response (object): The HTTP response object. + + Raises: + NotImplementedError: Always, since virtual. + """ + raise NotImplementedError(u"This implementation is virtual.") + + +class Download(DownloadBase): + """Helper to manage downloading a resource from a Google API. + + "Slices" of the resource can be retrieved by specifying a range + with ``start`` and / or ``end``. However, in typical usage, neither + ``start`` nor ``end`` is expected to be provided. + + Args: + media_url (str): The URL containing the media to be downloaded. + stream (IO[bytes]): A write-able stream (i.e. file-like object) that + the downloaded resource can be written to. + start (int): The first byte in a range to be downloaded. If not + provided, but ``end`` is provided, will download from the + beginning to ``end`` of the media. + end (int): The last byte in a range to be downloaded. If not + provided, but ``start`` is provided, will download from the + ``start`` to the end of the media. + headers (Optional[Mapping[str, str]]): Extra headers that should + be sent with the request, e.g. headers for encrypted data. + checksum Optional([str]): The type of checksum to compute to verify + the integrity of the object. The response headers must contain + a checksum of the requested type. If the headers lack an + appropriate checksum (for instance in the case of transcoded or + ranged downloads where the remote service does not know the + correct checksum) an INFO-level log will be emitted. Supported + values are "md5", "crc32c" and None. + """ + + def __init__( + self, media_url, stream=None, start=None, end=None, headers=None, checksum="md5" + ): + super(Download, self).__init__( + media_url, stream=stream, start=start, end=end, headers=headers + ) + self.checksum = checksum + + def _prepare_request(self): + """Prepare the contents of an HTTP request. + + This is everything that must be done before a request that doesn't + require network I/O (or other I/O). This is based on the `sans-I/O`_ + philosophy. + + Returns: + Tuple[str, str, NoneType, Mapping[str, str]]: The quadruple + + * HTTP verb for the request (always GET) + * the URL for the request + * the body of the request (always :data:`None`) + * headers for the request + + Raises: + ValueError: If the current :class:`Download` has already + finished. + + .. _sans-I/O: https://sans-io.readthedocs.io/ + """ + if self.finished: + raise ValueError(u"A download can only be used once.") + + add_bytes_range(self.start, self.end, self._headers) + return _GET, self.media_url, None, self._headers + + def _process_response(self, response): + """Process the response from an HTTP request. + + This is everything that must be done after a request that doesn't + require network I/O (or other I/O). This is based on the `sans-I/O`_ + philosophy. + + Args: + response (object): The HTTP response object. + + .. _sans-I/O: https://sans-io.readthedocs.io/ + """ + # Tombstone the current Download so it cannot be used again. + self._finished = True + _helpers.require_status_code( + response, _ACCEPTABLE_STATUS_CODES, self._get_status_code + ) + + def consume(self, transport, timeout=None): + """Consume the resource to be downloaded. + + If a ``stream`` is attached to this download, then the downloaded + resource will be written to the stream. + + Args: + transport (object): An object which can make authenticated + requests. + timeout (Optional[Union[float, aiohttp.ClientTimeout]]): + The number of seconds to wait for the server response. + Depending on the retry strategy, a request may be repeated + several times using the same timeout each time. + Can also be passed as an `aiohttp.ClientTimeout` object. + + Raises: + NotImplementedError: Always, since virtual. + """ + raise NotImplementedError(u"This implementation is virtual.") + + +class ChunkedDownload(DownloadBase): + """Download a resource in chunks from a Google API. + + Args: + media_url (str): The URL containing the media to be downloaded. + chunk_size (int): The number of bytes to be retrieved in each + request. + stream (IO[bytes]): A write-able stream (i.e. file-like object) that + will be used to concatenate chunks of the resource as they are + downloaded. + start (int): The first byte in a range to be downloaded. If not + provided, defaults to ``0``. + end (int): The last byte in a range to be downloaded. If not + provided, will download to the end of the media. + headers (Optional[Mapping[str, str]]): Extra headers that should + be sent with each request, e.g. headers for data encryption + key headers. + + Attributes: + media_url (str): The URL containing the media to be downloaded. + start (Optional[int]): The first byte in a range to be downloaded. + end (Optional[int]): The last byte in a range to be downloaded. + chunk_size (int): The number of bytes to be retrieved in each request. + + Raises: + ValueError: If ``start`` is negative. + """ + + def __init__(self, media_url, chunk_size, stream, start=0, end=None, headers=None): + if start < 0: + raise ValueError( + u"On a chunked download the starting " u"value cannot be negative." + ) + super(ChunkedDownload, self).__init__( + media_url, stream=stream, start=start, end=end, headers=headers + ) + self.chunk_size = chunk_size + self._bytes_downloaded = 0 + self._total_bytes = None + self._invalid = False + + @property + def bytes_downloaded(self): + """int: Number of bytes that have been downloaded.""" + return self._bytes_downloaded + + @property + def total_bytes(self): + """Optional[int]: The total number of bytes to be downloaded.""" + return self._total_bytes + + @property + def invalid(self): + """bool: Indicates if the download is in an invalid state. + + This will occur if a call to :meth:`consume_next_chunk` fails. + """ + return self._invalid + + def _get_byte_range(self): + """Determines the byte range for the next request. + + Returns: + Tuple[int, int]: The pair of begin and end byte for the next + chunked request. + """ + curr_start = self.start + self.bytes_downloaded + curr_end = curr_start + self.chunk_size - 1 + # Make sure ``curr_end`` does not exceed ``end``. + if self.end is not None: + curr_end = min(curr_end, self.end) + # Make sure ``curr_end`` does not exceed ``total_bytes - 1``. + if self.total_bytes is not None: + curr_end = min(curr_end, self.total_bytes - 1) + return curr_start, curr_end + + def _prepare_request(self): + """Prepare the contents of an HTTP request. + + This is everything that must be done before a request that doesn't + require network I/O (or other I/O). This is based on the `sans-I/O`_ + philosophy. + + .. note: + + This method will be used multiple times, so ``headers`` will + be mutated in between requests. However, we don't make a copy + since the same keys are being updated. + + Returns: + Tuple[str, str, NoneType, Mapping[str, str]]: The quadruple + + * HTTP verb for the request (always GET) + * the URL for the request + * the body of the request (always :data:`None`) + * headers for the request + + Raises: + ValueError: If the current download has finished. + ValueError: If the current download is invalid. + + .. _sans-I/O: https://sans-io.readthedocs.io/ + """ + if self.finished: + raise ValueError(u"Download has finished.") + if self.invalid: + raise ValueError(u"Download is invalid and cannot be re-used.") + + curr_start, curr_end = self._get_byte_range() + add_bytes_range(curr_start, curr_end, self._headers) + return _GET, self.media_url, None, self._headers + + def _make_invalid(self): + """Simple setter for ``invalid``. + + This is intended to be passed along as a callback to helpers that + raise an exception so they can mark this instance as invalid before + raising. + """ + self._invalid = True + + async def _process_response(self, response): + """Process the response from an HTTP request. + + This is everything that must be done after a request that doesn't + require network I/O. This is based on the `sans-I/O`_ philosophy. + + For the time being, this **does require** some form of I/O to write + a chunk to ``stream``. However, this will (almost) certainly not be + network I/O. + + Updates the current state after consuming a chunk. First, + increments ``bytes_downloaded`` by the number of bytes in the + ``content-length`` header. + + If ``total_bytes`` is already set, this assumes (but does not check) + that we already have the correct value and doesn't bother to check + that it agrees with the headers. + + We expect the **total** length to be in the ``content-range`` header, + but this header is only present on requests which sent the ``range`` + header. This response header should be of the form + ``bytes {start}-{end}/{total}`` and ``{end} - {start} + 1`` + should be the same as the ``Content-Length``. + + Args: + response (object): The HTTP response object (need headers). + + Raises: + ~google.resumable_media.common.InvalidResponse: If the number + of bytes in the body doesn't match the content length header. + + .. _sans-I/O: https://sans-io.readthedocs.io/ + """ + # Verify the response before updating the current instance. + if _check_for_zero_content_range( + response, self._get_status_code, self._get_headers + ): + self._finished = True + return + + _helpers.require_status_code( + response, + _ACCEPTABLE_STATUS_CODES, + self._get_status_code, + callback=self._make_invalid, + ) + headers = self._get_headers(response) + response_body = await self._get_body(response) + + start_byte, end_byte, total_bytes = get_range_info( + response, self._get_headers, callback=self._make_invalid + ) + + transfer_encoding = headers.get(u"transfer-encoding") + + if transfer_encoding is None: + content_length = _helpers.header_required( + response, + u"content-length", + self._get_headers, + callback=self._make_invalid, + ) + num_bytes = int(content_length) + + if len(response_body) != num_bytes: + self._make_invalid() + raise common.InvalidResponse( + response, + u"Response is different size than content-length", + u"Expected", + num_bytes, + u"Received", + len(response_body), + ) + else: + # 'content-length' header not allowed with chunked encoding. + num_bytes = end_byte - start_byte + 1 + + # First update ``bytes_downloaded``. + self._bytes_downloaded += num_bytes + # If the end byte is past ``end`` or ``total_bytes - 1`` we are done. + if self.end is not None and end_byte >= self.end: + self._finished = True + elif end_byte >= total_bytes - 1: + self._finished = True + # NOTE: We only use ``total_bytes`` if not already known. + if self.total_bytes is None: + self._total_bytes = total_bytes + # Write the response body to the stream. + self._stream.write(response_body) + + def consume_next_chunk(self, transport, timeout=None): + """Consume the next chunk of the resource to be downloaded. + + Args: + transport (object): An object which can make authenticated + requests. + timeout (Optional[Union[float, aiohttp.ClientTimeout]]): + The number of seconds to wait for the server response. + Depending on the retry strategy, a request may be repeated + several times using the same timeout each time. + Can also be passed as an `aiohttp.ClientTimeout` object. + Raises: + NotImplementedError: Always, since virtual. + """ + raise NotImplementedError(u"This implementation is virtual.") + + +def add_bytes_range(start, end, headers): + """Add a bytes range to a header dictionary. + + Some possible inputs and the corresponding bytes ranges:: + + >>> headers = {} + >>> add_bytes_range(None, None, headers) + >>> headers + {} + >>> add_bytes_range(500, 999, headers) + >>> headers['range'] + 'bytes=500-999' + >>> add_bytes_range(None, 499, headers) + >>> headers['range'] + 'bytes=0-499' + >>> add_bytes_range(-500, None, headers) + >>> headers['range'] + 'bytes=-500' + >>> add_bytes_range(9500, None, headers) + >>> headers['range'] + 'bytes=9500-' + + Args: + start (Optional[int]): The first byte in a range. Can be zero, + positive, negative or :data:`None`. + end (Optional[int]): The last byte in a range. Assumed to be + positive. + headers (Mapping[str, str]): A headers mapping which can have the + bytes range added if at least one of ``start`` or ``end`` + is not :data:`None`. + """ + if start is None: + if end is None: + # No range to add. + return + else: + # NOTE: This assumes ``end`` is non-negative. + bytes_range = u"0-{:d}".format(end) + else: + if end is None: + if start < 0: + bytes_range = u"{:d}".format(start) + else: + bytes_range = u"{:d}-".format(start) + else: + # NOTE: This is invalid if ``start < 0``. + bytes_range = u"{:d}-{:d}".format(start, end) + + headers[_helpers.RANGE_HEADER] = u"bytes=" + bytes_range + + +def get_range_info(response, get_headers, callback=_helpers.do_nothing): + """Get the start, end and total bytes from a content range header. + + Args: + response (object): An HTTP response object. + get_headers (Callable[Any, Mapping[str, str]]): Helper to get headers + from an HTTP response. + callback (Optional[Callable]): A callback that takes no arguments, + to be executed when an exception is being raised. + + Returns: + Tuple[int, int, int]: The start byte, end byte and total bytes. + + Raises: + ~google.resumable_media.common.InvalidResponse: If the + ``Content-Range`` header is not of the form + ``bytes {start}-{end}/{total}``. + """ + content_range = _helpers.header_required( + response, _helpers.CONTENT_RANGE_HEADER, get_headers, callback=callback + ) + match = _CONTENT_RANGE_RE.match(content_range) + if match is None: + callback() + raise common.InvalidResponse( + response, + u"Unexpected content-range header", + content_range, + u'Expected to be of the form "bytes {start}-{end}/{total}"', + ) + + return ( + int(match.group(u"start_byte")), + int(match.group(u"end_byte")), + int(match.group(u"total_bytes")), + ) + + +def _check_for_zero_content_range(response, get_status_code, get_headers): + """Validate if response status code is 416 and content range is zero. + + This is the special case for handling zero bytes files. + + Args: + response (object): An HTTP response object. + get_status_code (Callable[Any, int]): Helper to get a status code + from a response. + get_headers (Callable[Any, Mapping[str, str]]): Helper to get headers + from an HTTP response. + + Returns: + bool: True if content range total bytes is zero, false otherwise. + """ + if get_status_code(response) == http_client.REQUESTED_RANGE_NOT_SATISFIABLE: + content_range = _helpers.header_required( + response, + _helpers.CONTENT_RANGE_HEADER, + get_headers, + callback=_helpers.do_nothing, + ) + if content_range == _ZERO_CONTENT_RANGE_HEADER: + return True + return False diff --git a/venv/Lib/site-packages/google/_async_resumable_media/_helpers.py b/venv/Lib/site-packages/google/_async_resumable_media/_helpers.py new file mode 100644 index 000000000..65673b482 --- /dev/null +++ b/venv/Lib/site-packages/google/_async_resumable_media/_helpers.py @@ -0,0 +1,198 @@ +# Copyright 2020 Google Inc. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +"""Shared utilities used by both downloads and uploads.""" + +import logging +import random +import time + + +from six.moves import http_client + + +from google.resumable_media import common + + +RANGE_HEADER = u"range" +CONTENT_RANGE_HEADER = u"content-range" +RETRYABLE = ( + common.TOO_MANY_REQUESTS, + http_client.INTERNAL_SERVER_ERROR, + http_client.BAD_GATEWAY, + http_client.SERVICE_UNAVAILABLE, + http_client.GATEWAY_TIMEOUT, +) + +_SLOW_CRC32C_WARNING = ( + "Currently using crcmod in pure python form. This is a slow " + "implementation. Python 3 has a faster implementation, `google-crc32c`, " + "which will be used if it is installed." +) +_HASH_HEADER = u"x-goog-hash" +_MISSING_CHECKSUM = u"""\ +No {checksum_type} checksum was returned from the service while downloading {} +(which happens for composite objects), so client-side content integrity +checking is not being performed.""" +_LOGGER = logging.getLogger(__name__) + + +def do_nothing(): + """Simple default callback.""" + + +def header_required(response, name, get_headers, callback=do_nothing): + """Checks that a specific header is in a headers dictionary. + + Args: + response (object): An HTTP response object, expected to have a + ``headers`` attribute that is a ``Mapping[str, str]``. + name (str): The name of a required header. + get_headers (Callable[Any, Mapping[str, str]]): Helper to get headers + from an HTTP response. + callback (Optional[Callable]): A callback that takes no arguments, + to be executed when an exception is being raised. + + Returns: + str: The desired header. + + Raises: + ~google.resumable_media.common.InvalidResponse: If the header + is missing. + """ + headers = get_headers(response) + if name not in headers: + callback() + raise common.InvalidResponse( + response, u"Response headers must contain header", name + ) + + return headers[name] + + +def require_status_code(response, status_codes, get_status_code, callback=do_nothing): + """Require a response has a status code among a list. + + Args: + response (object): The HTTP response object. + status_codes (tuple): The acceptable status codes. + get_status_code (Callable[Any, int]): Helper to get a status code + from a response. + callback (Optional[Callable]): A callback that takes no arguments, + to be executed when an exception is being raised. + + Returns: + int: The status code. + + Raises: + ~google.resumable_media.common.InvalidResponse: If the status code + is not one of the values in ``status_codes``. + """ + status_code = get_status_code(response) + if status_code not in status_codes: + callback() + raise common.InvalidResponse( + response, + u"Request failed with status code", + status_code, + u"Expected one of", + *status_codes + ) + return status_code + + +def calculate_retry_wait(base_wait, max_sleep): + """Calculate the amount of time to wait before a retry attempt. + + Wait time grows exponentially with the number of attempts, until + it hits ``max_sleep``. + + A random amount of jitter (between 0 and 1 seconds) is added to spread out + retry attempts from different clients. + + Args: + base_wait (float): The "base" wait time (i.e. without any jitter) + that will be doubled until it reaches the maximum sleep. + max_sleep (float): Maximum value that a sleep time is allowed to be. + + Returns: + Tuple[float, float]: The new base wait time as well as the wait time + to be applied (with a random amount of jitter between 0 and 1 seconds + added). + """ + new_base_wait = 2.0 * base_wait + if new_base_wait > max_sleep: + new_base_wait = max_sleep + + jitter_ms = random.randint(0, 1000) + return new_base_wait, new_base_wait + 0.001 * jitter_ms + + +async def wait_and_retry(func, get_status_code, retry_strategy): + """Attempts to retry a call to ``func`` until success. + + Expects ``func`` to return an HTTP response and uses ``get_status_code`` + to check if the response is retry-able. + + Will retry until :meth:`~.RetryStrategy.retry_allowed` (on the current + ``retry_strategy``) returns :data:`False`. Uses + :func:`calculate_retry_wait` to double the wait time (with jitter) after + each attempt. + + Args: + func (Callable): A callable that takes no arguments and produces + an HTTP response which will be checked as retry-able. + get_status_code (Callable[Any, int]): Helper to get a status code + from a response. + retry_strategy (~google.resumable_media.common.RetryStrategy): The + strategy to use if the request fails and must be retried. + + Returns: + object: The return value of ``func``. + """ + + response = await func() + + if get_status_code(response) not in RETRYABLE: + return response + + total_sleep = 0.0 + num_retries = 0 + base_wait = 0.5 # When doubled will give 1.0 + while retry_strategy.retry_allowed(total_sleep, num_retries): + base_wait, wait_time = calculate_retry_wait(base_wait, retry_strategy.max_sleep) + num_retries += 1 + total_sleep += wait_time + time.sleep(wait_time) + response = await func() + if get_status_code(response) not in RETRYABLE: + return response + + return response + + +class _DoNothingHash(object): + """Do-nothing hash object. + + Intended as a stand-in for ``hashlib.md5`` or a crc32c checksum + implementation in cases where it isn't necessary to compute the hash. + """ + + def update(self, unused_chunk): + """Do-nothing ``update`` method. + + Intended to match the interface of ``hashlib.md5`` and other checksums. + Args: + unused_chunk (bytes): A chunk of data. + """ diff --git a/venv/Lib/site-packages/google/_async_resumable_media/_upload.py b/venv/Lib/site-packages/google/_async_resumable_media/_upload.py new file mode 100644 index 000000000..f95d91f4d --- /dev/null +++ b/venv/Lib/site-packages/google/_async_resumable_media/_upload.py @@ -0,0 +1,979 @@ +# Copyright 2017 Google Inc. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +"""Virtual bases classes for uploading media via Google APIs. + +Supported here are: + +* simple (media) uploads +* multipart uploads that contain both metadata and a small file as payload +* resumable uploads (with metadata as well) +""" + + +import json +import os +import random +import sys + +import six +from six.moves import http_client + +from google import _async_resumable_media +from google._async_resumable_media import _helpers +from google.resumable_media import _helpers as sync_helpers +from google.resumable_media import _upload as sync_upload +from google.resumable_media import common + + +from google.resumable_media._upload import ( + _CONTENT_TYPE_HEADER, + _CONTENT_RANGE_TEMPLATE, + _RANGE_UNKNOWN_TEMPLATE, + _EMPTY_RANGE_TEMPLATE, + _BOUNDARY_FORMAT, + _MULTIPART_SEP, + _CRLF, + _MULTIPART_BEGIN, + _RELATED_HEADER, + _BYTES_RANGE_RE, + _STREAM_ERROR_TEMPLATE, + _POST, + _PUT, + _UPLOAD_CHECKSUM_MISMATCH_MESSAGE, + _UPLOAD_METADATA_NO_APPROPRIATE_CHECKSUM_MESSAGE, +) + + +class UploadBase(object): + """Base class for upload helpers. + + Defines core shared behavior across different upload types. + + Args: + upload_url (str): The URL where the content will be uploaded. + headers (Optional[Mapping[str, str]]): Extra headers that should + be sent with the request, e.g. headers for encrypted data. + + Attributes: + upload_url (str): The URL where the content will be uploaded. + """ + + def __init__(self, upload_url, headers=None): + self.upload_url = upload_url + if headers is None: + headers = {} + self._headers = headers + self._finished = False + self._retry_strategy = common.RetryStrategy() + + @property + def finished(self): + """bool: Flag indicating if the upload has completed.""" + return self._finished + + def _process_response(self, response): + """Process the response from an HTTP request. + + This is everything that must be done after a request that doesn't + require network I/O (or other I/O). This is based on the `sans-I/O`_ + philosophy. + + Args: + response (object): The HTTP response object. + + Raises: + ~google.resumable_media.common.InvalidResponse: If the status + code is not 200. + + .. _sans-I/O: https://sans-io.readthedocs.io/ + """ + # Tombstone the current upload so it cannot be used again (in either + # failure or success). + self._finished = True + _helpers.require_status_code(response, (http_client.OK,), self._get_status_code) + + @staticmethod + def _get_status_code(response): + """Access the status code from an HTTP response. + + Args: + response (object): The HTTP response object. + + Raises: + NotImplementedError: Always, since virtual. + """ + raise NotImplementedError(u"This implementation is virtual.") + + @staticmethod + def _get_headers(response): + """Access the headers from an HTTP response. + + Args: + response (object): The HTTP response object. + + Raises: + NotImplementedError: Always, since virtual. + """ + raise NotImplementedError(u"This implementation is virtual.") + + @staticmethod + def _get_body(response): + """Access the response body from an HTTP response. + + Args: + response (object): The HTTP response object. + + Raises: + NotImplementedError: Always, since virtual. + """ + raise NotImplementedError(u"This implementation is virtual.") + + +class SimpleUpload(UploadBase): + """Upload a resource to a Google API. + + A **simple** media upload sends no metadata and completes the upload + in a single request. + + Args: + upload_url (str): The URL where the content will be uploaded. + headers (Optional[Mapping[str, str]]): Extra headers that should + be sent with the request, e.g. headers for encrypted data. + + Attributes: + upload_url (str): The URL where the content will be uploaded. + """ + + def _prepare_request(self, data, content_type): + """Prepare the contents of an HTTP request. + + This is everything that must be done before a request that doesn't + require network I/O (or other I/O). This is based on the `sans-I/O`_ + philosophy. + + .. note: + + This method will be used only once, so ``headers`` will be + mutated by having a new key added to it. + + Args: + data (bytes): The resource content to be uploaded. + content_type (str): The content type for the request. + + Returns: + Tuple[str, str, bytes, Mapping[str, str]]: The quadruple + + * HTTP verb for the request (always POST) + * the URL for the request + * the body of the request + * headers for the request + + Raises: + ValueError: If the current upload has already finished. + TypeError: If ``data`` isn't bytes. + + .. _sans-I/O: https://sans-io.readthedocs.io/ + """ + if self.finished: + raise ValueError(u"An upload can only be used once.") + + if not isinstance(data, six.binary_type): + raise TypeError(u"`data` must be bytes, received", type(data)) + self._headers[_CONTENT_TYPE_HEADER] = content_type + return _POST, self.upload_url, data, self._headers + + def transmit(self, transport, data, content_type, timeout=None): + """Transmit the resource to be uploaded. + + Args: + transport (object): An object which can make authenticated + requests. + data (bytes): The resource content to be uploaded. + content_type (str): The content type of the resource, e.g. a JPEG + image has content type ``image/jpeg``. + timeout (Optional[Union[float, aiohttp.ClientTimeout]]): + The number of seconds to wait for the server response. + Depending on the retry strategy, a request may be repeated + several times using the same timeout each time. + Can also be passed as an `aiohttp.ClientTimeout` object. + + Raises: + NotImplementedError: Always, since virtual. + """ + raise NotImplementedError(u"This implementation is virtual.") + + +class MultipartUpload(UploadBase): + """Upload a resource with metadata to a Google API. + + A **multipart** upload sends both metadata and the resource in a single + (multipart) request. + + Args: + upload_url (str): The URL where the content will be uploaded. + headers (Optional[Mapping[str, str]]): Extra headers that should + be sent with the request, e.g. headers for encrypted data. + checksum Optional([str]): The type of checksum to compute to verify + the integrity of the object. The request metadata will be amended + to include the computed value. Using this option will override a + manually-set checksum value. Supported values are "md5", "crc32c" + and None. The default is None. + + Attributes: + upload_url (str): The URL where the content will be uploaded. + """ + + def __init__(self, upload_url, headers=None, checksum=None): + super(MultipartUpload, self).__init__(upload_url, headers=headers) + self._checksum_type = checksum + + def _prepare_request(self, data, metadata, content_type): + """Prepare the contents of an HTTP request. + + This is everything that must be done before a request that doesn't + require network I/O (or other I/O). This is based on the `sans-I/O`_ + philosophy. + + .. note: + + This method will be used only once, so ``headers`` will be + mutated by having a new key added to it. + + Args: + data (bytes): The resource content to be uploaded. + metadata (Mapping[str, str]): The resource metadata, such as an + ACL list. + content_type (str): The content type of the resource, e.g. a JPEG + image has content type ``image/jpeg``. + + Returns: + Tuple[str, str, bytes, Mapping[str, str]]: The quadruple + + * HTTP verb for the request (always POST) + * the URL for the request + * the body of the request + * headers for the request + + Raises: + ValueError: If the current upload has already finished. + TypeError: If ``data`` isn't bytes. + + .. _sans-I/O: https://sans-io.readthedocs.io/ + """ + if self.finished: + raise ValueError(u"An upload can only be used once.") + + if not isinstance(data, six.binary_type): + raise TypeError(u"`data` must be bytes, received", type(data)) + + checksum_object = sync_helpers._get_checksum_object(self._checksum_type) + + if checksum_object: + checksum_object.update(data) + actual_checksum = sync_helpers.prepare_checksum_digest( + checksum_object.digest() + ) + metadata_key = sync_helpers._get_metadata_key(self._checksum_type) + metadata[metadata_key] = actual_checksum + + content, multipart_boundary = construct_multipart_request( + data, metadata, content_type + ) + multipart_content_type = _RELATED_HEADER + multipart_boundary + b'"' + + self._headers[_CONTENT_TYPE_HEADER] = multipart_content_type + + return _POST, self.upload_url, content, self._headers + + def transmit(self, transport, data, metadata, content_type, timeout=None): + """Transmit the resource to be uploaded. + + Args: + transport (object): An object which can make authenticated + requests. + data (bytes): The resource content to be uploaded. + metadata (Mapping[str, str]): The resource metadata, such as an + ACL list. + content_type (str): The content type of the resource, e.g. a JPEG + image has content type ``image/jpeg``. + timeout (Optional[Union[float, aiohttp.ClientTimeout]]): + The number of seconds to wait for the server response. + Depending on the retry strategy, a request may be repeated + several times using the same timeout each time. + Can also be passed as an `aiohttp.ClientTimeout` object. + + Raises: + NotImplementedError: Always, since virtual. + """ + raise NotImplementedError(u"This implementation is virtual.") + + +class ResumableUpload(UploadBase, sync_upload.ResumableUpload): + """Initiate and fulfill a resumable upload to a Google API. + + A **resumable** upload sends an initial request with the resource metadata + and then gets assigned an upload ID / upload URL to send bytes to. + Using the upload URL, the upload is then done in chunks (determined by + the user) until all bytes have been uploaded. + + Args: + upload_url (str): The URL where the resumable upload will be initiated. + chunk_size (int): The size of each chunk used to upload the resource. + headers (Optional[Mapping[str, str]]): Extra headers that should + be sent with the :meth:`initiate` request, e.g. headers for + encrypted data. These **will not** be sent with + :meth:`transmit_next_chunk` or :meth:`recover` requests. + checksum Optional([str]): The type of checksum to compute to verify + the integrity of the object. After the upload is complete, the + server-computed checksum of the resulting object will be read + and google.resumable_media.common.DataCorruption will be raised on + a mismatch. The corrupted file will not be deleted from the remote + host automatically. Supported values are "md5", "crc32c" and None. + The default is None. + + Attributes: + upload_url (str): The URL where the content will be uploaded. + + Raises: + ValueError: If ``chunk_size`` is not a multiple of + :data:`.UPLOAD_CHUNK_SIZE`. + """ + + def __init__(self, upload_url, chunk_size, checksum=None, headers=None): + super(ResumableUpload, self).__init__(upload_url, headers=headers) + if chunk_size % _async_resumable_media.UPLOAD_CHUNK_SIZE != 0: + raise ValueError( + u"{} KB must divide chunk size".format( + _async_resumable_media.UPLOAD_CHUNK_SIZE / 1024 + ) + ) + self._chunk_size = chunk_size + self._stream = None + self._content_type = None + self._bytes_uploaded = 0 + self._bytes_checksummed = 0 + self._checksum_type = checksum + self._checksum_object = None + self._total_bytes = None + self._resumable_url = None + self._invalid = False + + @property + def invalid(self): + """bool: Indicates if the upload is in an invalid state. + + This will occur if a call to :meth:`transmit_next_chunk` fails. + To recover from such a failure, call :meth:`recover`. + """ + return self._invalid + + @property + def chunk_size(self): + """int: The size of each chunk used to upload the resource.""" + return self._chunk_size + + @property + def resumable_url(self): + """Optional[str]: The URL of the in-progress resumable upload.""" + return self._resumable_url + + @property + def bytes_uploaded(self): + """int: Number of bytes that have been uploaded.""" + return self._bytes_uploaded + + @property + def total_bytes(self): + """Optional[int]: The total number of bytes to be uploaded. + + If this upload is initiated (via :meth:`initiate`) with + ``stream_final=True``, this value will be populated based on the size + of the ``stream`` being uploaded. (By default ``stream_final=True``.) + + If this upload is initiated with ``stream_final=False``, + :attr:`total_bytes` will be :data:`None` since it cannot be + determined from the stream. + """ + return self._total_bytes + + def _prepare_initiate_request( + self, stream, metadata, content_type, total_bytes=None, stream_final=True + ): + """Prepare the contents of HTTP request to initiate upload. + + This is everything that must be done before a request that doesn't + require network I/O (or other I/O). This is based on the `sans-I/O`_ + philosophy. + + Args: + stream (IO[bytes]): The stream (i.e. file-like object) that will + be uploaded. The stream **must** be at the beginning (i.e. + ``stream.tell() == 0``). + metadata (Mapping[str, str]): The resource metadata, such as an + ACL list. + content_type (str): The content type of the resource, e.g. a JPEG + image has content type ``image/jpeg``. + total_bytes (Optional[int]): The total number of bytes to be + uploaded. If specified, the upload size **will not** be + determined from the stream (even if ``stream_final=True``). + stream_final (Optional[bool]): Indicates if the ``stream`` is + "final" (i.e. no more bytes will be added to it). In this case + we determine the upload size from the size of the stream. If + ``total_bytes`` is passed, this argument will be ignored. + + Returns: + Tuple[str, str, bytes, Mapping[str, str]]: The quadruple + + * HTTP verb for the request (always POST) + * the URL for the request + * the body of the request + * headers for the request + + Raises: + ValueError: If the current upload has already been initiated. + ValueError: If ``stream`` is not at the beginning. + + .. _sans-I/O: https://sans-io.readthedocs.io/ + """ + if self.resumable_url is not None: + raise ValueError(u"This upload has already been initiated.") + if stream.tell() != 0: + raise ValueError(u"Stream must be at beginning.") + + self._stream = stream + self._content_type = content_type + headers = { + _CONTENT_TYPE_HEADER: u"application/json; charset=UTF-8", + u"x-upload-content-type": content_type, + } + # Set the total bytes if possible. + if total_bytes is not None: + self._total_bytes = total_bytes + elif stream_final: + self._total_bytes = get_total_bytes(stream) + # Add the total bytes to the headers if set. + if self._total_bytes is not None: + content_length = u"{:d}".format(self._total_bytes) + headers[u"x-upload-content-length"] = content_length + + headers.update(self._headers) + payload = json.dumps(metadata).encode(u"utf-8") + return _POST, self.upload_url, payload, headers + + def _process_initiate_response(self, response): + """Process the response from an HTTP request that initiated upload. + + This is everything that must be done after a request that doesn't + require network I/O (or other I/O). This is based on the `sans-I/O`_ + philosophy. + + This method takes the URL from the ``Location`` header and stores it + for future use. Within that URL, we assume the ``upload_id`` query + parameter has been included, but we do not check. + + Args: + response (object): The HTTP response object (need headers). + + .. _sans-I/O: https://sans-io.readthedocs.io/ + """ + _helpers.require_status_code( + response, + (http_client.OK,), + self._get_status_code, + callback=self._make_invalid, + ) + self._resumable_url = _helpers.header_required( + response, u"location", self._get_headers + ) + + def initiate( + self, + transport, + stream, + metadata, + content_type, + total_bytes=None, + stream_final=True, + timeout=None, + ): + """Initiate a resumable upload. + + By default, this method assumes your ``stream`` is in a "final" + state ready to transmit. However, ``stream_final=False`` can be used + to indicate that the size of the resource is not known. This can happen + if bytes are being dynamically fed into ``stream``, e.g. if the stream + is attached to application logs. + + If ``stream_final=False`` is used, :attr:`chunk_size` bytes will be + read from the stream every time :meth:`transmit_next_chunk` is called. + If one of those reads produces strictly fewer bites than the chunk + size, the upload will be concluded. + + Args: + transport (object): An object which can make authenticated + requests. + stream (IO[bytes]): The stream (i.e. file-like object) that will + be uploaded. The stream **must** be at the beginning (i.e. + ``stream.tell() == 0``). + metadata (Mapping[str, str]): The resource metadata, such as an + ACL list. + content_type (str): The content type of the resource, e.g. a JPEG + image has content type ``image/jpeg``. + total_bytes (Optional[int]): The total number of bytes to be + uploaded. If specified, the upload size **will not** be + determined from the stream (even if ``stream_final=True``). + stream_final (Optional[bool]): Indicates if the ``stream`` is + "final" (i.e. no more bytes will be added to it). In this case + we determine the upload size from the size of the stream. If + ``total_bytes`` is passed, this argument will be ignored. + timeout (Optional[Union[float, aiohttp.ClientTimeout]]): + The number of seconds to wait for the server response. + Depending on the retry strategy, a request may be repeated + several times using the same timeout each time. + Can also be passed as an `aiohttp.ClientTimeout` object. + + Raises: + NotImplementedError: Always, since virtual. + """ + raise NotImplementedError(u"This implementation is virtual.") + + def _prepare_request(self): + """Prepare the contents of HTTP request to upload a chunk. + + This is everything that must be done before a request that doesn't + require network I/O. This is based on the `sans-I/O`_ philosophy. + + For the time being, this **does require** some form of I/O to read + a chunk from ``stream`` (via :func:`get_next_chunk`). However, this + will (almost) certainly not be network I/O. + + Returns: + Tuple[str, str, bytes, Mapping[str, str]]: The quadruple + + * HTTP verb for the request (always PUT) + * the URL for the request + * the body of the request + * headers for the request + + The headers **do not** incorporate the ``_headers`` on the + current instance. + + Raises: + ValueError: If the current upload has finished. + ValueError: If the current upload is in an invalid state. + ValueError: If the current upload has not been initiated. + ValueError: If the location in the stream (i.e. ``stream.tell()``) + does not agree with ``bytes_uploaded``. + + .. _sans-I/O: https://sans-io.readthedocs.io/ + """ + if self.finished: + raise ValueError(u"Upload has finished.") + if self.invalid: + raise ValueError( + u"Upload is in an invalid state. To recover call `recover()`." + ) + if self.resumable_url is None: + raise ValueError( + u"This upload has not been initiated. Please call " + u"initiate() before beginning to transmit chunks." + ) + + start_byte, payload, content_range = get_next_chunk( + self._stream, self._chunk_size, self._total_bytes + ) + if start_byte != self.bytes_uploaded: + msg = _STREAM_ERROR_TEMPLATE.format(start_byte, self.bytes_uploaded) + raise ValueError(msg) + + self._update_checksum(start_byte, payload) + + headers = { + _CONTENT_TYPE_HEADER: self._content_type, + _helpers.CONTENT_RANGE_HEADER: content_range, + } + return _PUT, self.resumable_url, payload, headers + + def _make_invalid(self): + """Simple setter for ``invalid``. + + This is intended to be passed along as a callback to helpers that + raise an exception so they can mark this instance as invalid before + raising. + """ + self._invalid = True + + async def _process_response(self, response, bytes_sent): + """Process the response from an HTTP request. + + This is everything that must be done after a request that doesn't + require network I/O (or other I/O). This is based on the `sans-I/O`_ + philosophy. + + Args: + response (object): The HTTP response object. + bytes_sent (int): The number of bytes sent in the request that + ``response`` was returned for. + + Raises: + ~google.resumable_media.common.InvalidResponse: If the status + code is 308 and the ``range`` header is not of the form + ``bytes 0-{end}``. + ~google.resumable_media.common.InvalidResponse: If the status + code is not 200 or 308. + + .. _sans-I/O: https://sans-io.readthedocs.io/ + """ + status_code = _helpers.require_status_code( + response, + (http_client.OK, _async_resumable_media.PERMANENT_REDIRECT), + self._get_status_code, + callback=self._make_invalid, + ) + if status_code == http_client.OK: + # NOTE: We use the "local" information of ``bytes_sent`` to update + # ``bytes_uploaded``, but do not verify this against other + # state. However, there may be some other information: + # + # * a ``size`` key in JSON response body + # * the ``total_bytes`` attribute (if set) + # * ``stream.tell()`` (relying on fact that ``initiate()`` + # requires stream to be at the beginning) + self._bytes_uploaded = self._bytes_uploaded + bytes_sent + # Tombstone the current upload so it cannot be used again. + self._finished = True + # Validate the checksum. This can raise an exception on failure. + await self._validate_checksum(response) + else: + bytes_range = _helpers.header_required( + response, + _helpers.RANGE_HEADER, + self._get_headers, + callback=self._make_invalid, + ) + match = _BYTES_RANGE_RE.match(bytes_range) + if match is None: + self._make_invalid() + raise common.InvalidResponse( + response, + u'Unexpected "range" header', + bytes_range, + u'Expected to be of the form "bytes=0-{end}"', + ) + self._bytes_uploaded = int(match.group(u"end_byte")) + 1 + + async def _validate_checksum(self, response): + """Check the computed checksum, if any, against the response headers. + Args: + response (object): The HTTP response object. + Raises: + ~google.resumable_media.common.DataCorruption: If the checksum + computed locally and the checksum reported by the remote host do + not match. + """ + if self._checksum_type is None: + return + metadata_key = sync_helpers._get_metadata_key(self._checksum_type) + metadata = await response.json() + remote_checksum = metadata.get(metadata_key) + if remote_checksum is None: + raise common.InvalidResponse( + response, + _UPLOAD_METADATA_NO_APPROPRIATE_CHECKSUM_MESSAGE.format(metadata_key), + self._get_headers(response), + ) + local_checksum = sync_helpers.prepare_checksum_digest( + self._checksum_object.digest() + ) + if local_checksum != remote_checksum: + raise common.DataCorruption( + response, + _UPLOAD_CHECKSUM_MISMATCH_MESSAGE.format( + self._checksum_type.upper(), local_checksum, remote_checksum + ), + ) + + def transmit_next_chunk(self, transport, timeout=None): + """Transmit the next chunk of the resource to be uploaded. + + If the current upload was initiated with ``stream_final=False``, + this method will dynamically determine if the upload has completed. + The upload will be considered complete if the stream produces + fewer than :attr:`chunk_size` bytes when a chunk is read from it. + + Args: + transport (object): An object which can make authenticated + requests. + timeout (Optional[Union[float, aiohttp.ClientTimeout]]): + The number of seconds to wait for the server response. + Depending on the retry strategy, a request may be repeated + several times using the same timeout each time. + Can also be passed as an `aiohttp.ClientTimeout` object. + + Raises: + NotImplementedError: Always, since virtual. + """ + raise NotImplementedError(u"This implementation is virtual.") + + def _prepare_recover_request(self): + """Prepare the contents of HTTP request to recover from failure. + + This is everything that must be done before a request that doesn't + require network I/O. This is based on the `sans-I/O`_ philosophy. + + We assume that the :attr:`resumable_url` is set (i.e. the only way + the upload can end up :attr:`invalid` is if it has been initiated. + + Returns: + Tuple[str, str, NoneType, Mapping[str, str]]: The quadruple + + * HTTP verb for the request (always PUT) + * the URL for the request + * the body of the request (always :data:`None`) + * headers for the request + + The headers **do not** incorporate the ``_headers`` on the + current instance. + + Raises: + ValueError: If the current upload is not in an invalid state. + + .. _sans-I/O: https://sans-io.readthedocs.io/ + """ + if not self.invalid: + raise ValueError(u"Upload is not in invalid state, no need to recover.") + + headers = {_helpers.CONTENT_RANGE_HEADER: u"bytes */*"} + return _PUT, self.resumable_url, None, headers + + def _process_recover_response(self, response): + """Process the response from an HTTP request to recover from failure. + + This is everything that must be done after a request that doesn't + require network I/O (or other I/O). This is based on the `sans-I/O`_ + philosophy. + + Args: + response (object): The HTTP response object. + + Raises: + ~google.resumable_media.common.InvalidResponse: If the status + code is not 308. + ~google.resumable_media.common.InvalidResponse: If the status + code is 308 and the ``range`` header is not of the form + ``bytes 0-{end}``. + + .. _sans-I/O: https://sans-io.readthedocs.io/ + """ + _helpers.require_status_code( + response, + (_async_resumable_media.PERMANENT_REDIRECT,), + self._get_status_code, + ) + headers = self._get_headers(response) + if _helpers.RANGE_HEADER in headers: + bytes_range = headers[_helpers.RANGE_HEADER] + match = _BYTES_RANGE_RE.match(bytes_range) + if match is None: + raise common.InvalidResponse( + response, + u'Unexpected "range" header', + bytes_range, + u'Expected to be of the form "bytes=0-{end}"', + ) + self._bytes_uploaded = int(match.group(u"end_byte")) + 1 + else: + # In this case, the upload has not "begun". + self._bytes_uploaded = 0 + + self._stream.seek(self._bytes_uploaded) + self._invalid = False + + def recover(self, transport): + """Recover from a failure. + + This method should be used when a :class:`ResumableUpload` is in an + :attr:`~ResumableUpload.invalid` state due to a request failure. + + This will verify the progress with the server and make sure the + current upload is in a valid state before :meth:`transmit_next_chunk` + can be used again. + + Args: + transport (object): An object which can make authenticated + requests. + + Raises: + NotImplementedError: Always, since virtual. + """ + raise NotImplementedError(u"This implementation is virtual.") + + +def get_boundary(): + """Get a random boundary for a multipart request. + + Returns: + bytes: The boundary used to separate parts of a multipart request. + """ + random_int = random.randrange(sys.maxsize) + boundary = _BOUNDARY_FORMAT.format(random_int) + # NOTE: Neither % formatting nor .format() are available for byte strings + # in Python 3.4, so we must use unicode strings as templates. + return boundary.encode(u"utf-8") + + +def construct_multipart_request(data, metadata, content_type): + """Construct a multipart request body. + + Args: + data (bytes): The resource content (UTF-8 encoded as bytes) + to be uploaded. + metadata (Mapping[str, str]): The resource metadata, such as an + ACL list. + content_type (str): The content type of the resource, e.g. a JPEG + image has content type ``image/jpeg``. + + Returns: + Tuple[bytes, bytes]: The multipart request body and the boundary used + between each part. + """ + multipart_boundary = get_boundary() + json_bytes = json.dumps(metadata).encode(u"utf-8") + content_type = content_type.encode(u"utf-8") + # Combine the two parts into a multipart payload. + # NOTE: We'd prefer a bytes template but are restricted by Python 3.4. + boundary_sep = _MULTIPART_SEP + multipart_boundary + content = ( + boundary_sep + + _MULTIPART_BEGIN + + json_bytes + + _CRLF + + boundary_sep + + _CRLF + + b"content-type: " + + content_type + + _CRLF + + _CRLF + + data # Empty line between headers and body. + + _CRLF + + boundary_sep + + _MULTIPART_SEP + ) + + return content, multipart_boundary + + +def get_total_bytes(stream): + """Determine the total number of bytes in a stream. + + Args: + stream (IO[bytes]): The stream (i.e. file-like object). + + Returns: + int: The number of bytes. + """ + current_position = stream.tell() + # NOTE: ``.seek()`` **should** return the same value that ``.tell()`` + # returns, but in Python 2, ``file`` objects do not. + stream.seek(0, os.SEEK_END) + end_position = stream.tell() + # Go back to the initial position. + stream.seek(current_position) + + return end_position + + +def get_next_chunk(stream, chunk_size, total_bytes): + """Get a chunk from an I/O stream. + + The ``stream`` may have fewer bytes remaining than ``chunk_size`` + so it may not always be the case that + ``end_byte == start_byte + chunk_size - 1``. + + Args: + stream (IO[bytes]): The stream (i.e. file-like object). + chunk_size (int): The size of the chunk to be read from the ``stream``. + total_bytes (Optional[int]): The (expected) total number of bytes + in the ``stream``. + + Returns: + Tuple[int, bytes, str]: Triple of: + + * the start byte index + * the content in between the start and end bytes (inclusive) + * content range header for the chunk (slice) that has been read + + Raises: + ValueError: If ``total_bytes == 0`` but ``stream.read()`` yields + non-empty content. + ValueError: If there is no data left to consume. This corresponds + exactly to the case ``end_byte < start_byte``, which can only + occur if ``end_byte == start_byte - 1``. + """ + start_byte = stream.tell() + if total_bytes is not None and start_byte + chunk_size >= total_bytes > 0: + payload = stream.read(total_bytes - start_byte) + else: + payload = stream.read(chunk_size) + end_byte = stream.tell() - 1 + + num_bytes_read = len(payload) + if total_bytes is None: + if num_bytes_read < chunk_size: + # We now **KNOW** the total number of bytes. + total_bytes = end_byte + 1 + elif total_bytes == 0: + # NOTE: We also expect ``start_byte == 0`` here but don't check + # because ``_prepare_initiate_request()`` requires the + # stream to be at the beginning. + if num_bytes_read != 0: + raise ValueError( + u"Stream specified as empty, but produced non-empty content." + ) + else: + if num_bytes_read == 0: + raise ValueError( + u"Stream is already exhausted. There is no content remaining." + ) + + content_range = get_content_range(start_byte, end_byte, total_bytes) + return start_byte, payload, content_range + + +def get_content_range(start_byte, end_byte, total_bytes): + """Convert start, end and total into content range header. + + If ``total_bytes`` is not known, uses "bytes {start}-{end}/*". + If we are dealing with an empty range (i.e. ``end_byte < start_byte``) + then "bytes */{total}" is used. + + This function **ASSUMES** that if the size is not known, the caller will + not also pass an empty range. + + Args: + start_byte (int): The start (inclusive) of the byte range. + end_byte (int): The end (inclusive) of the byte range. + total_bytes (Optional[int]): The number of bytes in the byte + range (if known). + + Returns: + str: The content range header. + """ + if total_bytes is None: + return _RANGE_UNKNOWN_TEMPLATE.format(start_byte, end_byte) + elif end_byte < start_byte: + return _EMPTY_RANGE_TEMPLATE.format(total_bytes) + else: + return _CONTENT_RANGE_TEMPLATE.format(start_byte, end_byte, total_bytes) diff --git a/venv/Lib/site-packages/google/_async_resumable_media/requests/__init__.py b/venv/Lib/site-packages/google/_async_resumable_media/requests/__init__.py new file mode 100644 index 000000000..aaaa28369 --- /dev/null +++ b/venv/Lib/site-packages/google/_async_resumable_media/requests/__init__.py @@ -0,0 +1,678 @@ +# Copyright 2017 Google Inc. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +"""``requests`` utilities for Google Media Downloads and Resumable Uploads. + +This sub-package assumes callers will use the `requests`_ library +as transport and `google-auth`_ for sending authenticated HTTP traffic +with ``requests``. + +.. _requests: http://docs.python-requests.org/ +.. _google-auth: https://google-auth.readthedocs.io/ + +==================== +Authorized Transport +==================== + +To use ``google-auth`` and ``requests`` to create an authorized transport +that has read-only access to Google Cloud Storage (GCS): + +.. testsetup:: get-credentials + + import google.auth + import google.auth.credentials as creds_mod + import mock + + def mock_default(scopes=None): + credentials = mock.Mock(spec=creds_mod.Credentials) + return credentials, u'mock-project' + + # Patch the ``default`` function on the module. + original_default = google.auth.default + google.auth.default = mock_default + +.. doctest:: get-credentials + + >>> import google.auth + >>> import google.auth.transport.requests as tr_requests + >>> + >>> ro_scope = u'https://www.googleapis.com/auth/devstorage.read_only' + >>> credentials, _ = google.auth.default(scopes=(ro_scope,)) + >>> transport = tr_requests.AuthorizedSession(credentials) + >>> transport + + +.. testcleanup:: get-credentials + + # Put back the correct ``default`` function on the module. + google.auth.default = original_default + +================ +Simple Downloads +================ + +To download an object from Google Cloud Storage, construct the media URL +for the GCS object and download it with an authorized transport that has +access to the resource: + +.. testsetup:: basic-download + + import mock + import requests + from six.moves import http_client + + bucket = u'bucket-foo' + blob_name = u'file.txt' + + fake_response = requests.Response() + fake_response.status_code = int(http_client.OK) + fake_response.headers[u'Content-Length'] = u'1364156' + fake_content = mock.MagicMock(spec=['__len__']) + fake_content.__len__.return_value = 1364156 + fake_response._content = fake_content + + get_method = mock.Mock(return_value=fake_response, spec=[]) + transport = mock.Mock(request=get_method, spec=['request']) + +.. doctest:: basic-download + + >>> from google.resumable_media.requests import Download + >>> + >>> url_template = ( + ... u'https://www.googleapis.com/download/storage/v1/b/' + ... u'{bucket}/o/{blob_name}?alt=media') + >>> media_url = url_template.format( + ... bucket=bucket, blob_name=blob_name) + >>> + >>> download = Download(media_url) + >>> response = download.consume(transport) + >>> download.finished + True + >>> response + + >>> response.headers[u'Content-Length'] + '1364156' + >>> len(response.content) + 1364156 + +To download only a portion of the bytes in the object, +specify ``start`` and ``end`` byte positions (both optional): + +.. testsetup:: basic-download-with-slice + + import mock + import requests + from six.moves import http_client + + from google.resumable_media.requests import Download + + media_url = u'http://test.invalid' + start = 4096 + end = 8191 + slice_size = end - start + 1 + + fake_response = requests.Response() + fake_response.status_code = int(http_client.PARTIAL_CONTENT) + fake_response.headers[u'Content-Length'] = u'{:d}'.format(slice_size) + content_range = u'bytes {:d}-{:d}/1364156'.format(start, end) + fake_response.headers[u'Content-Range'] = content_range + fake_content = mock.MagicMock(spec=['__len__']) + fake_content.__len__.return_value = slice_size + fake_response._content = fake_content + + get_method = mock.Mock(return_value=fake_response, spec=[]) + transport = mock.Mock(request=get_method, spec=['request']) + +.. doctest:: basic-download-with-slice + + >>> download = Download(media_url, start=4096, end=8191) + >>> response = download.consume(transport) + >>> download.finished + True + >>> response + + >>> response.headers[u'Content-Length'] + '4096' + >>> response.headers[u'Content-Range'] + 'bytes 4096-8191/1364156' + >>> len(response.content) + 4096 + +================= +Chunked Downloads +================= + +For very large objects or objects of unknown size, it may make more sense +to download the object in chunks rather than all at once. This can be done +to avoid dropped connections with a poor internet connection or can allow +multiple chunks to be downloaded in parallel to speed up the total +download. + +A :class:`.ChunkedDownload` uses the same media URL and authorized +transport that a basic :class:`.Download` would use, but also +requires a chunk size and a write-able byte ``stream``. The chunk size is used +to determine how much of the resouce to consume with each request and the +stream is to allow the resource to be written out (e.g. to disk) without +having to fit in memory all at once. + +.. testsetup:: chunked-download + + import io + + import mock + import requests + from six.moves import http_client + + media_url = u'http://test.invalid' + + fifty_mb = 50 * 1024 * 1024 + one_gb = 1024 * 1024 * 1024 + fake_response = requests.Response() + fake_response.status_code = int(http_client.PARTIAL_CONTENT) + fake_response.headers[u'Content-Length'] = u'{:d}'.format(fifty_mb) + content_range = u'bytes 0-{:d}/{:d}'.format(fifty_mb - 1, one_gb) + fake_response.headers[u'Content-Range'] = content_range + fake_content_begin = b'The beginning of the chunk...' + fake_content = fake_content_begin + b'1' * (fifty_mb - 29) + fake_response._content = fake_content + + get_method = mock.Mock(return_value=fake_response, spec=[]) + transport = mock.Mock(request=get_method, spec=['request']) + +.. doctest:: chunked-download + + >>> from google.resumable_media.requests import ChunkedDownload + >>> + >>> chunk_size = 50 * 1024 * 1024 # 50MB + >>> stream = io.BytesIO() + >>> download = ChunkedDownload( + ... media_url, chunk_size, stream) + >>> # Check the state of the download before starting. + >>> download.bytes_downloaded + 0 + >>> download.total_bytes is None + True + >>> response = download.consume_next_chunk(transport) + >>> # Check the state of the download after consuming one chunk. + >>> download.finished + False + >>> download.bytes_downloaded # chunk_size + 52428800 + >>> download.total_bytes # 1GB + 1073741824 + >>> response + + >>> response.headers[u'Content-Length'] + '52428800' + >>> response.headers[u'Content-Range'] + 'bytes 0-52428799/1073741824' + >>> len(response.content) == chunk_size + True + >>> stream.seek(0) + 0 + >>> stream.read(29) + b'The beginning of the chunk...' + +The download will change it's ``finished`` status to :data:`True` +once the final chunk is consumed. In some cases, the final chunk may +not be the same size as the other chunks: + +.. testsetup:: chunked-download-end + + import mock + import requests + from six.moves import http_client + + from google.resumable_media.requests import ChunkedDownload + + media_url = u'http://test.invalid' + + fifty_mb = 50 * 1024 * 1024 + one_gb = 1024 * 1024 * 1024 + stream = mock.Mock(spec=['write']) + download = ChunkedDownload(media_url, fifty_mb, stream) + download._bytes_downloaded = 20 * fifty_mb + download._total_bytes = one_gb + + fake_response = requests.Response() + fake_response.status_code = int(http_client.PARTIAL_CONTENT) + slice_size = one_gb - 20 * fifty_mb + fake_response.headers[u'Content-Length'] = u'{:d}'.format(slice_size) + content_range = u'bytes {:d}-{:d}/{:d}'.format( + 20 * fifty_mb, one_gb - 1, one_gb) + fake_response.headers[u'Content-Range'] = content_range + fake_content = mock.MagicMock(spec=['__len__']) + fake_content.__len__.return_value = slice_size + fake_response._content = fake_content + + get_method = mock.Mock(return_value=fake_response, spec=[]) + transport = mock.Mock(request=get_method, spec=['request']) + +.. doctest:: chunked-download-end + + >>> # The state of the download in progress. + >>> download.finished + False + >>> download.bytes_downloaded # 20 chunks at 50MB + 1048576000 + >>> download.total_bytes # 1GB + 1073741824 + >>> response = download.consume_next_chunk(transport) + >>> # The state of the download after consuming the final chunk. + >>> download.finished + True + >>> download.bytes_downloaded == download.total_bytes + True + >>> response + + >>> response.headers[u'Content-Length'] + '25165824' + >>> response.headers[u'Content-Range'] + 'bytes 1048576000-1073741823/1073741824' + >>> len(response.content) < download.chunk_size + True + +In addition, a :class:`.ChunkedDownload` can also take optional +``start`` and ``end`` byte positions. + +============== +Simple Uploads +============== + +Among the three supported upload classes, the simplest is +:class:`.SimpleUpload`. A simple upload should be used when the resource +being uploaded is small and when there is no metadata (other than the name) +associated with the resource. + +.. testsetup:: simple-upload + + import json + + import mock + import requests + from six.moves import http_client + + bucket = u'some-bucket' + blob_name = u'file.txt' + + fake_response = requests.Response() + fake_response.status_code = int(http_client.OK) + payload = { + u'bucket': bucket, + u'contentType': u'text/plain', + u'md5Hash': u'M0XLEsX9/sMdiI+4pB4CAQ==', + u'name': blob_name, + u'size': u'27', + } + fake_response._content = json.dumps(payload).encode(u'utf-8') + + post_method = mock.Mock(return_value=fake_response, spec=[]) + transport = mock.Mock(request=post_method, spec=['request']) + +.. doctest:: simple-upload + :options: +NORMALIZE_WHITESPACE + + >>> from google.resumable_media.requests import SimpleUpload + >>> + >>> url_template = ( + ... u'https://www.googleapis.com/upload/storage/v1/b/{bucket}/o?' + ... u'uploadType=media&' + ... u'name={blob_name}') + >>> upload_url = url_template.format( + ... bucket=bucket, blob_name=blob_name) + >>> + >>> upload = SimpleUpload(upload_url) + >>> data = b'Some not too large content.' + >>> content_type = u'text/plain' + >>> response = upload.transmit(transport, data, content_type) + >>> upload.finished + True + >>> response + + >>> json_response = response.json() + >>> json_response[u'bucket'] == bucket + True + >>> json_response[u'name'] == blob_name + True + >>> json_response[u'contentType'] == content_type + True + >>> json_response[u'md5Hash'] + 'M0XLEsX9/sMdiI+4pB4CAQ==' + >>> int(json_response[u'size']) == len(data) + True + +In the rare case that an upload fails, an :exc:`.InvalidResponse` +will be raised: + +.. testsetup:: simple-upload-fail + + import time + + import mock + import requests + from six.moves import http_client + + from google import resumable_media + from google.resumable_media import _helpers + from google.resumable_media.requests import SimpleUpload as constructor + + upload_url = u'http://test.invalid' + data = b'Some not too large content.' + content_type = u'text/plain' + + fake_response = requests.Response() + fake_response.status_code = int(http_client.SERVICE_UNAVAILABLE) + + post_method = mock.Mock(return_value=fake_response, spec=[]) + transport = mock.Mock(request=post_method, spec=['request']) + + time_sleep = time.sleep + def dont_sleep(seconds): + raise RuntimeError(u'No sleep', seconds) + + def SimpleUpload(*args, **kwargs): + upload = constructor(*args, **kwargs) + # Mock the cumulative sleep to avoid retries (and `time.sleep()`). + upload._retry_strategy = resumable_media.RetryStrategy( + max_cumulative_retry=-1.0) + return upload + + time.sleep = dont_sleep + +.. doctest:: simple-upload-fail + :options: +NORMALIZE_WHITESPACE + + >>> upload = SimpleUpload(upload_url) + >>> error = None + >>> try: + ... upload.transmit(transport, data, content_type) + ... except resumable_media.InvalidResponse as caught_exc: + ... error = caught_exc + ... + >>> error + InvalidResponse('Request failed with status code', 503, + 'Expected one of', ) + >>> error.response + + >>> + >>> upload.finished + True + +.. testcleanup:: simple-upload-fail + + # Put back the correct ``sleep`` function on the ``time`` module. + time.sleep = time_sleep + +Even in the case of failure, we see that the upload is +:attr:`~.SimpleUpload.finished`, i.e. it cannot be re-used. + +================= +Multipart Uploads +================= + +After the simple upload, the :class:`.MultipartUpload` can be used to +achieve essentially the same task. However, a multipart upload allows some +metadata about the resource to be sent along as well. (This is the "multi": +we send a first part with the metadata and a second part with the actual +bytes in the resource.) + +Usage is similar to the simple upload, but :meth:`~.MultipartUpload.transmit` +accepts an extra required argument: ``metadata``. + +.. testsetup:: multipart-upload + + import json + + import mock + import requests + from six.moves import http_client + + bucket = u'some-bucket' + blob_name = u'file.txt' + data = b'Some not too large content.' + content_type = u'text/plain' + + fake_response = requests.Response() + fake_response.status_code = int(http_client.OK) + payload = { + u'bucket': bucket, + u'name': blob_name, + u'metadata': {u'color': u'grurple'}, + } + fake_response._content = json.dumps(payload).encode(u'utf-8') + + post_method = mock.Mock(return_value=fake_response, spec=[]) + transport = mock.Mock(request=post_method, spec=['request']) + +.. doctest:: multipart-upload + + >>> from google.resumable_media.requests import MultipartUpload + >>> + >>> url_template = ( + ... u'https://www.googleapis.com/upload/storage/v1/b/{bucket}/o?' + ... u'uploadType=multipart') + >>> upload_url = url_template.format(bucket=bucket) + >>> + >>> upload = MultipartUpload(upload_url) + >>> metadata = { + ... u'name': blob_name, + ... u'metadata': { + ... u'color': u'grurple', + ... }, + ... } + >>> response = upload.transmit(transport, data, metadata, content_type) + >>> upload.finished + True + >>> response + + >>> json_response = response.json() + >>> json_response[u'bucket'] == bucket + True + >>> json_response[u'name'] == blob_name + True + >>> json_response[u'metadata'] == metadata[u'metadata'] + True + +As with the simple upload, in the case of failure an :exc:`.InvalidResponse` +is raised, enclosing the :attr:`~.InvalidResponse.response` that caused +the failure and the ``upload`` object cannot be re-used after a failure. + +================= +Resumable Uploads +================= + +A :class:`.ResumableUpload` deviates from the other two upload classes: +it transmits a resource over the course of multiple requests. This +is intended to be used in cases where: + +* the size of the resource is not known (i.e. it is generated on the fly) +* requests must be short-lived +* the client has request **size** limitations +* the resource is too large to fit into memory + +In general, a resource should be sent in a **single** request to avoid +latency and reduce QPS. See `GCS best practices`_ for more things to +consider when using a resumable upload. + +.. _GCS best practices: https://cloud.google.com/storage/docs/\ + best-practices#uploading + +After creating a :class:`.ResumableUpload` instance, a +**resumable upload session** must be initiated to let the server know that +a series of chunked upload requests will be coming and to obtain an +``upload_id`` for the session. In contrast to the other two upload classes, +:meth:`~.ResumableUpload.initiate` takes a byte ``stream`` as input rather +than raw bytes as ``data``. This can be a file object, a :class:`~io.BytesIO` +object or any other stream implementing the same interface. + +.. testsetup:: resumable-initiate + + import io + + import mock + import requests + from six.moves import http_client + + bucket = u'some-bucket' + blob_name = u'file.txt' + data = b'Some resumable bytes.' + content_type = u'text/plain' + + fake_response = requests.Response() + fake_response.status_code = int(http_client.OK) + fake_response._content = b'' + upload_id = u'ABCdef189XY_super_serious' + resumable_url_template = ( + u'https://www.googleapis.com/upload/storage/v1/b/{bucket}' + u'/o?uploadType=resumable&upload_id={upload_id}') + resumable_url = resumable_url_template.format( + bucket=bucket, upload_id=upload_id) + fake_response.headers[u'location'] = resumable_url + fake_response.headers[u'x-guploader-uploadid'] = upload_id + + post_method = mock.Mock(return_value=fake_response, spec=[]) + transport = mock.Mock(request=post_method, spec=['request']) + +.. doctest:: resumable-initiate + + >>> from google.resumable_media.requests import ResumableUpload + >>> + >>> url_template = ( + ... u'https://www.googleapis.com/upload/storage/v1/b/{bucket}/o?' + ... u'uploadType=resumable') + >>> upload_url = url_template.format(bucket=bucket) + >>> + >>> chunk_size = 1024 * 1024 # 1MB + >>> upload = ResumableUpload(upload_url, chunk_size) + >>> stream = io.BytesIO(data) + >>> # The upload doesn't know how "big" it is until seeing a stream. + >>> upload.total_bytes is None + True + >>> metadata = {u'name': blob_name} + >>> response = upload.initiate(transport, stream, metadata, content_type) + >>> response + + >>> upload.resumable_url == response.headers[u'Location'] + True + >>> upload.total_bytes == len(data) + True + >>> upload_id = response.headers[u'X-GUploader-UploadID'] + >>> upload_id + 'ABCdef189XY_super_serious' + >>> upload.resumable_url == upload_url + u'&upload_id=' + upload_id + True + +Once a :class:`.ResumableUpload` has been initiated, the resource is +transmitted in chunks until completion: + +.. testsetup:: resumable-transmit + + import io + import json + + import mock + import requests + from six.moves import http_client + + from google import resumable_media + import google.resumable_media.requests.upload as upload_mod + + data = b'01234567891' + stream = io.BytesIO(data) + # Create an "already initiated" upload. + upload_url = u'http://test.invalid' + chunk_size = 256 * 1024 # 256KB + upload = upload_mod.ResumableUpload(upload_url, chunk_size) + upload._resumable_url = u'http://test.invalid?upload_id=mocked' + upload._stream = stream + upload._content_type = u'text/plain' + upload._total_bytes = len(data) + + # After-the-fact update the chunk size so that len(data) + # is split into three. + upload._chunk_size = 4 + # Make three fake responses. + fake_response0 = requests.Response() + fake_response0.status_code = resumable_media.PERMANENT_REDIRECT + fake_response0.headers[u'range'] = u'bytes=0-3' + + fake_response1 = requests.Response() + fake_response1.status_code = resumable_media.PERMANENT_REDIRECT + fake_response1.headers[u'range'] = u'bytes=0-7' + + fake_response2 = requests.Response() + fake_response2.status_code = int(http_client.OK) + bucket = u'some-bucket' + blob_name = u'file.txt' + payload = { + u'bucket': bucket, + u'name': blob_name, + u'size': u'{:d}'.format(len(data)), + } + fake_response2._content = json.dumps(payload).encode(u'utf-8') + + # Use the fake responses to mock a transport. + responses = [fake_response0, fake_response1, fake_response2] + put_method = mock.Mock(side_effect=responses, spec=[]) + transport = mock.Mock(request=put_method, spec=['request']) + +.. doctest:: resumable-transmit + + >>> response0 = upload.transmit_next_chunk(transport) + >>> response0 + + >>> upload.finished + False + >>> upload.bytes_uploaded == upload.chunk_size + True + >>> + >>> response1 = upload.transmit_next_chunk(transport) + >>> response1 + + >>> upload.finished + False + >>> upload.bytes_uploaded == 2 * upload.chunk_size + True + >>> + >>> response2 = upload.transmit_next_chunk(transport) + >>> response2 + + >>> upload.finished + True + >>> upload.bytes_uploaded == upload.total_bytes + True + >>> json_response = response2.json() + >>> json_response[u'bucket'] == bucket + True + >>> json_response[u'name'] == blob_name + True +""" +from google._async_resumable_media.requests.download import ChunkedDownload +from google._async_resumable_media.requests.download import Download +from google._async_resumable_media.requests.upload import MultipartUpload +from google._async_resumable_media.requests.download import RawChunkedDownload +from google._async_resumable_media.requests.download import RawDownload +from google._async_resumable_media.requests.upload import ResumableUpload +from google._async_resumable_media.requests.upload import SimpleUpload + + +__all__ = [ + u"ChunkedDownload", + u"Download", + u"MultipartUpload", + u"RawChunkedDownload", + u"RawDownload", + u"ResumableUpload", + u"SimpleUpload", +] diff --git a/venv/Lib/site-packages/google/_async_resumable_media/requests/__pycache__/__init__.cpython-36.pyc b/venv/Lib/site-packages/google/_async_resumable_media/requests/__pycache__/__init__.cpython-36.pyc new file mode 100644 index 0000000000000000000000000000000000000000..40235643bce565e8e957f2d38b6832efb251a1f1 GIT binary patch literal 21110 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 T-(X4aUH;hp@4a^}*Z=)DdHX@2 literal 0 HcmV?d00001 diff --git a/venv/Lib/site-packages/google/_async_resumable_media/requests/__pycache__/_request_helpers.cpython-36.pyc b/venv/Lib/site-packages/google/_async_resumable_media/requests/__pycache__/_request_helpers.cpython-36.pyc new file mode 100644 index 0000000000000000000000000000000000000000..4eb89f12a575192126c6ad7fc978c947f4a9d2f2 GIT binary patch literal 4329 zcmd^C%WfOV73~LKq9~d6_%U%ZlfrC91Z*14coV}(EXay&#FhhzUQ7=s%~Ds1Y^vGa zQ&p5qfzHO>Cde+E{6PL8$tFNHS!5gZHY@)^R&%Pl*&<~RvK=4|boJ}jtz(cjd9g)>!kc#hU!1H?DUT z&+Dv(=N7+;=WEPi4&OL(*#_HuYkSw3b6|BYoxMI7QNbCRsxS&w$R(LdJRZ)-VWLKa zC8u$eP$mhDVU(KtZnN1Ng|IC9UgiDy|1r2^kCo|7Oail7qqRC_Lsw z2^z~Z5lVKO?+_GguVZHof5fAd3yJ$$kW3~?99qP(-u(;)?;fD(I9WYN;+O}@Ta!s} z>~Gsaz~Px5Q7WpYk^~9k{X=**>L-Yl2v2yQae1tgv_Fl*(?lHi zXPgRhuP=eE1aryVe!z$KetP#O{Zu4+mHiVw3WEqp0{hzt){!DdG~n<$NQN;sP7)J2 zL+1%h7`MICIhUW{7ql3n3o_)GP*zQHs|IGo~1T~guFv7M%%)UPqIOmg8Vj6%X zTy}S;DDoynRGt6YI4z*D2aL`_~dU3yLEeSVTG^vNoWDw~;!EB4SrX{idP{~u zp4mkU6NpXST+@xtKue7#j;N!#g;O@rG^!P+)oNWbZv(t24^5GWIOWG^7IlofS__z3 zRbeiOfgtYF(-mJnOtK$glvR@bA5hE{m*BQ&qw&@SJw@J(HBAa43FtIST-D7vPzECn z-fwW`j9G8mn>P0Kg+S+NHYZJ0T-U?g(2WL6+|i6X$J*))28CGaLN!2U=KE`9sL519 zL_xZwxD+ZSH@l^ubDc_F?mxpLhSqrmqoNd`+_RODs2EPQqC+=kY>Rw-ZjOSHo1AB` zd@8bqdbBKUiq}VpFxjv0@VwhpM9Y1!Jo25kddXz#MXHqrjlMDo_UmG@Tj-V1{ZQ5_kZ3Lquf(o$h1D7&v-=`HZ*YpHNUc)6h8r=E{zf>3-fbR4i66vpLL-# zecn^E=Q3td;PQfrB}4X-6BT#bPYPmvSWoA^UH>ro1d^cTeO`RjS*cqtyX(Iv zOe)$!e5U(ce($TPGG4vtVL2rM%xBK`@@4A2Rbno%AUH|cJ z&)<3Sa_?7o;q7`KmmPLq?CtIDlt_Bl$}ju7+m99idmB4Zi0swNNg=eJ%xd|cRSu;t yFD80Rfj1S;DA~q?T;u%w3d|%yQ*j$k%WgTFh(0i=Re(XoZdTfN+t(c1vA+dcklalG literal 0 HcmV?d00001 diff --git a/venv/Lib/site-packages/google/_async_resumable_media/requests/__pycache__/download.cpython-36.pyc b/venv/Lib/site-packages/google/_async_resumable_media/requests/__pycache__/download.cpython-36.pyc new file mode 100644 index 0000000000000000000000000000000000000000..e709e7f63bd4cc9c4723a78d1dc23de655832d81 GIT binary patch literal 16289 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 literal 0 HcmV?d00001 diff --git a/venv/Lib/site-packages/google/_async_resumable_media/requests/_request_helpers.py b/venv/Lib/site-packages/google/_async_resumable_media/requests/_request_helpers.py new file mode 100644 index 000000000..f628ea467 --- /dev/null +++ b/venv/Lib/site-packages/google/_async_resumable_media/requests/_request_helpers.py @@ -0,0 +1,155 @@ +# Copyright 2017 Google Inc. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +"""Shared utilities used by both downloads and uploads. + +This utilities are explicitly catered to ``requests``-like transports. +""" + + +import functools + +from google._async_resumable_media import _helpers +from google.resumable_media import common + +import google.auth.transport._aiohttp_requests as aiohttp_requests +import aiohttp + +_DEFAULT_RETRY_STRATEGY = common.RetryStrategy() +_SINGLE_GET_CHUNK_SIZE = 8192 + + +# The number of seconds to wait to establish a connection +# (connect() call on socket). Avoid setting this to a multiple of 3 to not +# Align with TCP Retransmission timing. (typically 2.5-3s) +_DEFAULT_CONNECT_TIMEOUT = 61 +# The number of seconds to wait between bytes sent from the server. +_DEFAULT_READ_TIMEOUT = 60 +_DEFAULT_TIMEOUT = aiohttp.ClientTimeout( + connect=_DEFAULT_CONNECT_TIMEOUT, sock_read=_DEFAULT_READ_TIMEOUT +) + + +class RequestsMixin(object): + """Mix-in class implementing ``requests``-specific behavior. + + These are methods that are more general purpose, with implementations + specific to the types defined in ``requests``. + """ + + @staticmethod + def _get_status_code(response): + """Access the status code from an HTTP response. + + Args: + response (~requests.Response): The HTTP response object. + + Returns: + int: The status code. + """ + return response.status + + @staticmethod + def _get_headers(response): + """Access the headers from an HTTP response. + + Args: + response (~requests.Response): The HTTP response object. + + Returns: + ~requests.structures.CaseInsensitiveDict: The header mapping (keys + are case-insensitive). + """ + # For Async testing,`_headers` is modified instead of headers + # access via the internal field. + return response._headers + + @staticmethod + async def _get_body(response): + """Access the response body from an HTTP response. + + Args: + response (~requests.Response): The HTTP response object. + + Returns: + bytes: The body of the ``response``. + """ + wrapped_response = aiohttp_requests._CombinedResponse(response) + content = await wrapped_response.data.read() + return content + + +class RawRequestsMixin(RequestsMixin): + @staticmethod + async def _get_body(response): + """Access the response body from an HTTP response. + + Args: + response (~requests.Response): The HTTP response object. + + Returns: + bytes: The body of the ``response``. + """ + + wrapped_response = aiohttp_requests._CombinedResponse(response) + content = await wrapped_response.raw_content() + return content + + +async def http_request( + transport, + method, + url, + data=None, + headers=None, + retry_strategy=_DEFAULT_RETRY_STRATEGY, + **transport_kwargs +): + """Make an HTTP request. + + Args: + transport (~requests.Session): A ``requests`` object which can make + authenticated requests via a ``request()`` method. This method + must accept an HTTP method, an upload URL, a ``data`` keyword + argument and a ``headers`` keyword argument. + method (str): The HTTP method for the request. + url (str): The URL for the request. + data (Optional[bytes]): The body of the request. + headers (Mapping[str, str]): The headers for the request (``transport`` + may also add additional headers). + retry_strategy (~google.resumable_media.common.RetryStrategy): The + strategy to use if the request fails and must be retried. + transport_kwargs (Dict[str, str]): Extra keyword arguments to be + passed along to ``transport.request``. + + Returns: + ~requests.Response: The return value of ``transport.request()``. + """ + + # NOTE(asyncio/aiohttp): Sync versions use a tuple for two timeouts, + # default connect timeout and read timeout. Since async requests only + # accepts a single value, this is using the connect timeout. This logic + # diverges from the sync implementation. + if "timeout" not in transport_kwargs: + timeout = _DEFAULT_TIMEOUT + transport_kwargs["timeout"] = timeout + + func = functools.partial( + transport.request, method, url, data=data, headers=headers, **transport_kwargs + ) + + resp = await _helpers.wait_and_retry( + func, RequestsMixin._get_status_code, retry_strategy + ) + return resp diff --git a/venv/Lib/site-packages/google/_async_resumable_media/requests/download.py b/venv/Lib/site-packages/google/_async_resumable_media/requests/download.py new file mode 100644 index 000000000..5ac97c598 --- /dev/null +++ b/venv/Lib/site-packages/google/_async_resumable_media/requests/download.py @@ -0,0 +1,461 @@ +# Copyright 2017 Google Inc. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +"""Support for downloading media from Google APIs.""" + +import urllib3.response + +from google._async_resumable_media import _download +from google._async_resumable_media import _helpers +from google._async_resumable_media.requests import _request_helpers +from google.resumable_media import common +from google.resumable_media import _helpers as sync_helpers +from google.resumable_media.requests import download + +_CHECKSUM_MISMATCH = download._CHECKSUM_MISMATCH + + +class Download(_request_helpers.RequestsMixin, _download.Download): + """Helper to manage downloading a resource from a Google API. + + "Slices" of the resource can be retrieved by specifying a range + with ``start`` and / or ``end``. However, in typical usage, neither + ``start`` nor ``end`` is expected to be provided. + + Args: + media_url (str): The URL containing the media to be downloaded. + stream (IO[bytes]): A write-able stream (i.e. file-like object) that + the downloaded resource can be written to. + start (int): The first byte in a range to be downloaded. If not + provided, but ``end`` is provided, will download from the + beginning to ``end`` of the media. + end (int): The last byte in a range to be downloaded. If not + provided, but ``start`` is provided, will download from the + ``start`` to the end of the media. + headers (Optional[Mapping[str, str]]): Extra headers that should + be sent with the request, e.g. headers for encrypted data. + checksum Optional([str]): The type of checksum to compute to verify + the integrity of the object. The response headers must contain + a checksum of the requested type. If the headers lack an + appropriate checksum (for instance in the case of transcoded or + ranged downloads where the remote service does not know the + correct checksum) an INFO-level log will be emitted. Supported + values are "md5", "crc32c" and None. The default is "md5". + + Attributes: + media_url (str): The URL containing the media to be downloaded. + start (Optional[int]): The first byte in a range to be downloaded. + end (Optional[int]): The last byte in a range to be downloaded. + """ + + async def _write_to_stream(self, response): + """Write response body to a write-able stream. + + .. note: + + This method assumes that the ``_stream`` attribute is set on the + current download. + + Args: + response (~requests.Response): The HTTP response object. + + Raises: + ~google.resumable_media.common.DataCorruption: If the download's + checksum doesn't agree with server-computed checksum. + """ + + # `_get_expected_checksum()` may return None even if a checksum was + # requested, in which case it will emit an info log _MISSING_CHECKSUM. + # If an invalid checksum type is specified, this will raise ValueError. + expected_checksum, checksum_object = sync_helpers._get_expected_checksum( + response, self._get_headers, self.media_url, checksum_type=self.checksum + ) + + local_checksum_object = _add_decoder(response, checksum_object) + + async for chunk in response.content.iter_chunked( + _request_helpers._SINGLE_GET_CHUNK_SIZE + ): + self._stream.write(chunk) + local_checksum_object.update(chunk) + + if expected_checksum is None: + return + + else: + actual_checksum = sync_helpers.prepare_checksum_digest( + checksum_object.digest() + ) + if actual_checksum != expected_checksum: + msg = _CHECKSUM_MISMATCH.format( + self.media_url, + expected_checksum, + actual_checksum, + checksum_type=self.checksum.upper(), + ) + raise common.DataCorruption(response, msg) + + async def consume(self, transport, timeout=_request_helpers._DEFAULT_TIMEOUT): + """Consume the resource to be downloaded. + + If a ``stream`` is attached to this download, then the downloaded + resource will be written to the stream. + + Args: + transport (~requests.Session): A ``requests`` object which can + make authenticated requests. + timeout (Optional[Union[float, aiohttp.ClientTimeout]]): + The number of seconds to wait for the server response. + Depending on the retry strategy, a request may be repeated + several times using the same timeout each time. + Can also be passed as an `aiohttp.ClientTimeout` object. + + Returns: + ~requests.Response: The HTTP response returned by ``transport``. + + Raises: + ~google.resumable_media.common.DataCorruption: If the download's + checksum doesn't agree with server-computed checksum. + ValueError: If the current :class:`Download` has already + finished. + """ + method, url, payload, headers = self._prepare_request() + # NOTE: We assume "payload is None" but pass it along anyway. + request_kwargs = { + u"data": payload, + u"headers": headers, + u"retry_strategy": self._retry_strategy, + u"timeout": timeout, + } + + if self._stream is not None: + request_kwargs[u"stream"] = True + + result = await _request_helpers.http_request( + transport, method, url, **request_kwargs + ) + + self._process_response(result) + + if self._stream is not None: + await self._write_to_stream(result) + + return result + + +class RawDownload(_request_helpers.RawRequestsMixin, _download.Download): + """Helper to manage downloading a raw resource from a Google API. + + "Slices" of the resource can be retrieved by specifying a range + with ``start`` and / or ``end``. However, in typical usage, neither + ``start`` nor ``end`` is expected to be provided. + + Args: + media_url (str): The URL containing the media to be downloaded. + stream (IO[bytes]): A write-able stream (i.e. file-like object) that + the downloaded resource can be written to. + start (int): The first byte in a range to be downloaded. If not + provided, but ``end`` is provided, will download from the + beginning to ``end`` of the media. + end (int): The last byte in a range to be downloaded. If not + provided, but ``start`` is provided, will download from the + ``start`` to the end of the media. + headers (Optional[Mapping[str, str]]): Extra headers that should + be sent with the request, e.g. headers for encrypted data. + checksum Optional([str]): The type of checksum to compute to verify + the integrity of the object. The response headers must contain + a checksum of the requested type. If the headers lack an + appropriate checksum (for instance in the case of transcoded or + ranged downloads where the remote service does not know the + correct checksum) an INFO-level log will be emitted. Supported + values are "md5", "crc32c" and None. The default is "md5". + + Attributes: + media_url (str): The URL containing the media to be downloaded. + start (Optional[int]): The first byte in a range to be downloaded. + end (Optional[int]): The last byte in a range to be downloaded. + """ + + async def _write_to_stream(self, response): + """Write response body to a write-able stream. + + .. note: + + This method assumes that the ``_stream`` attribute is set on the + current download. + + Args: + response (~requests.Response): The HTTP response object. + + Raises: + ~google.resumable_media.common.DataCorruption: If the download's + checksum doesn't agree with server-computed checksum. + """ + + # `_get_expected_checksum()` may return None even if a checksum was + # requested, in which case it will emit an info log _MISSING_CHECKSUM. + # If an invalid checksum type is specified, this will raise ValueError. + expected_checksum, checksum_object = sync_helpers._get_expected_checksum( + response, self._get_headers, self.media_url, checksum_type=self.checksum + ) + + async for chunk in response.content.iter_chunked( + _request_helpers._SINGLE_GET_CHUNK_SIZE + ): + self._stream.write(chunk) + checksum_object.update(chunk) + + if expected_checksum is None: + return + else: + actual_checksum = sync_helpers.prepare_checksum_digest( + checksum_object.digest() + ) + + if actual_checksum != expected_checksum: + msg = _CHECKSUM_MISMATCH.format( + self.media_url, + expected_checksum, + actual_checksum, + checksum_type=self.checksum.upper(), + ) + raise common.DataCorruption(response, msg) + + async def consume(self, transport, timeout=_request_helpers._DEFAULT_TIMEOUT): + """Consume the resource to be downloaded. + + If a ``stream`` is attached to this download, then the downloaded + resource will be written to the stream. + + Args: + transport (~requests.Session): A ``requests`` object which can + make authenticated requests. + timeout (Optional[Union[float, Tuple[float, float]]]): + The number of seconds to wait for the server response. + Depending on the retry strategy, a request may be repeated + several times using the same timeout each time. + Can also be passed as a tuple (connect_timeout, read_timeout). + See :meth:`requests.Session.request` documentation for details. + + Returns: + ~requests.Response: The HTTP response returned by ``transport``. + + Raises: + ~google.resumable_media.common.DataCorruption: If the download's + checksum doesn't agree with server-computed checksum. + ValueError: If the current :class:`Download` has already + finished. + """ + method, url, payload, headers = self._prepare_request() + # NOTE: We assume "payload is None" but pass it along anyway. + result = await _request_helpers.http_request( + transport, + method, + url, + data=payload, + headers=headers, + retry_strategy=self._retry_strategy, + ) + + self._process_response(result) + + if self._stream is not None: + await self._write_to_stream(result) + + return result + + +class ChunkedDownload(_request_helpers.RequestsMixin, _download.ChunkedDownload): + """Download a resource in chunks from a Google API. + + Args: + media_url (str): The URL containing the media to be downloaded. + chunk_size (int): The number of bytes to be retrieved in each + request. + stream (IO[bytes]): A write-able stream (i.e. file-like object) that + will be used to concatenate chunks of the resource as they are + downloaded. + start (int): The first byte in a range to be downloaded. If not + provided, defaults to ``0``. + end (int): The last byte in a range to be downloaded. If not + provided, will download to the end of the media. + headers (Optional[Mapping[str, str]]): Extra headers that should + be sent with each request, e.g. headers for data encryption + key headers. + + Attributes: + media_url (str): The URL containing the media to be downloaded. + start (Optional[int]): The first byte in a range to be downloaded. + end (Optional[int]): The last byte in a range to be downloaded. + chunk_size (int): The number of bytes to be retrieved in each request. + + Raises: + ValueError: If ``start`` is negative. + """ + + async def consume_next_chunk( + self, transport, timeout=_request_helpers._DEFAULT_TIMEOUT + ): + + """ + Consume the next chunk of the resource to be downloaded. + + Args: + transport (~requests.Session): A ``requests`` object which can + make authenticated requests. + timeout (Optional[Union[float, aiohttp.ClientTimeout]]): + The number of seconds to wait for the server response. + Depending on the retry strategy, a request may be repeated + several times using the same timeout each time. + Can also be passed as an `aiohttp.ClientTimeout` object. + + Returns: + ~requests.Response: The HTTP response returned by ``transport``. + + Raises: + ValueError: If the current download has finished. + """ + method, url, payload, headers = self._prepare_request() + # NOTE: We assume "payload is None" but pass it along anyway. + result = await _request_helpers.http_request( + transport, + method, + url, + data=payload, + headers=headers, + retry_strategy=self._retry_strategy, + timeout=timeout, + ) + + await self._process_response(result) + return result + + +class RawChunkedDownload(_request_helpers.RawRequestsMixin, _download.ChunkedDownload): + """Download a raw resource in chunks from a Google API. + + Args: + media_url (str): The URL containing the media to be downloaded. + chunk_size (int): The number of bytes to be retrieved in each + request. + stream (IO[bytes]): A write-able stream (i.e. file-like object) that + will be used to concatenate chunks of the resource as they are + downloaded. + start (int): The first byte in a range to be downloaded. If not + provided, defaults to ``0``. + end (int): The last byte in a range to be downloaded. If not + provided, will download to the end of the media. + headers (Optional[Mapping[str, str]]): Extra headers that should + be sent with each request, e.g. headers for data encryption + key headers. + + Attributes: + media_url (str): The URL containing the media to be downloaded. + start (Optional[int]): The first byte in a range to be downloaded. + end (Optional[int]): The last byte in a range to be downloaded. + chunk_size (int): The number of bytes to be retrieved in each request. + + Raises: + ValueError: If ``start`` is negative. + """ + + async def consume_next_chunk( + self, transport, timeout=_request_helpers._DEFAULT_TIMEOUT + ): + """Consume the next chunk of the resource to be downloaded. + + Args: + transport (~requests.Session): A ``requests`` object which can + make authenticated requests. + timeout (Optional[Union[float, aiohttp.ClientTimeout]]): + The number of seconds to wait for the server response. + Depending on the retry strategy, a request may be repeated + several times using the same timeout each time. + Can also be passed as an `aiohttp.ClientTimeout` object. + + Returns: + ~requests.Response: The HTTP response returned by ``transport``. + + Raises: + ValueError: If the current download has finished. + """ + method, url, payload, headers = self._prepare_request() + # NOTE: We assume "payload is None" but pass it along anyway. + result = await _request_helpers.http_request( + transport, + method, + url, + data=payload, + headers=headers, + retry_strategy=self._retry_strategy, + timeout=timeout, + ) + await self._process_response(result) + return result + + +def _add_decoder(response_raw, checksum): + """Patch the ``_decoder`` on a ``urllib3`` response. + + This is so that we can intercept the compressed bytes before they are + decoded. + + Only patches if the content encoding is ``gzip``. + + Args: + response_raw (urllib3.response.HTTPResponse): The raw response for + an HTTP request. + checksum (object): + A checksum which will be updated with compressed bytes. + + Returns: + object: Either the original ``checksum`` if ``_decoder`` is not + patched, or a ``_DoNothingHash`` if the decoder is patched, since the + caller will no longer need to hash to decoded bytes. + """ + + encoding = response_raw.headers.get(u"content-encoding", u"").lower() + if encoding != u"gzip": + return checksum + + response_raw._decoder = _GzipDecoder(checksum) + return _helpers._DoNothingHash() + + +class _GzipDecoder(urllib3.response.GzipDecoder): + """Custom subclass of ``urllib3`` decoder for ``gzip``-ed bytes. + + Allows a checksum function to see the compressed bytes before they are + decoded. This way the checksum of the compressed value can be computed. + + Args: + checksum (object): + A checksum which will be updated with compressed bytes. + """ + + def __init__(self, checksum): + super(_GzipDecoder, self).__init__() + self._checksum = checksum + + def decompress(self, data): + """Decompress the bytes. + + Args: + data (bytes): The compressed bytes to be decompressed. + + Returns: + bytes: The decompressed bytes from ``data``. + """ + self._checksum.update(data) + return super(_GzipDecoder, self).decompress(data) diff --git a/venv/Lib/site-packages/google/_async_resumable_media/requests/upload.py b/venv/Lib/site-packages/google/_async_resumable_media/requests/upload.py new file mode 100644 index 000000000..8a1291a5b --- /dev/null +++ b/venv/Lib/site-packages/google/_async_resumable_media/requests/upload.py @@ -0,0 +1,515 @@ +# Copyright 2017 Google Inc. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +"""Support for resumable uploads. + +Also supported here are simple (media) uploads and multipart +uploads that contain both metadata and a small file as payload. +""" + + +from google._async_resumable_media import _upload +from google._async_resumable_media.requests import _request_helpers + + +class SimpleUpload(_request_helpers.RequestsMixin, _upload.SimpleUpload): + """Upload a resource to a Google API. + + A **simple** media upload sends no metadata and completes the upload + in a single request. + + Args: + upload_url (str): The URL where the content will be uploaded. + headers (Optional[Mapping[str, str]]): Extra headers that should + be sent with the request, e.g. headers for encrypted data. + + Attributes: + upload_url (str): The URL where the content will be uploaded. + """ + + async def transmit( + self, + transport, + data, + content_type, + timeout=_request_helpers._DEFAULT_TIMEOUT, + ): + """Transmit the resource to be uploaded. + + Args: + transport (~requests.Session): A ``requests`` object which can + make authenticated requests. + data (bytes): The resource content to be uploaded. + content_type (str): The content type of the resource, e.g. a JPEG + image has content type ``image/jpeg``. + timeout (Optional[Union[float, aiohttp.ClientTimeout]]): + The number of seconds to wait for the server response. + Depending on the retry strategy, a request may be repeated + several times using the same timeout each time. + Can also be passed as an `aiohttp.ClientTimeout` object. + + Returns: + ~requests.Response: The HTTP response returned by ``transport``. + """ + method, url, payload, headers = self._prepare_request(data, content_type) + + response = await _request_helpers.http_request( + transport, + method, + url, + data=payload, + headers=headers, + retry_strategy=self._retry_strategy, + timeout=timeout, + ) + self._process_response(response) + return response + + +class MultipartUpload(_request_helpers.RequestsMixin, _upload.MultipartUpload): + """Upload a resource with metadata to a Google API. + + A **multipart** upload sends both metadata and the resource in a single + (multipart) request. + + Args: + upload_url (str): The URL where the content will be uploaded. + headers (Optional[Mapping[str, str]]): Extra headers that should + be sent with the request, e.g. headers for encrypted data. + checksum Optional([str]): The type of checksum to compute to verify + the integrity of the object. The request metadata will be amended + to include the computed value. Using this option will override a + manually-set checksum value. Supported values are "md5", + "crc32c" and None. The default is None. + + Attributes: + upload_url (str): The URL where the content will be uploaded. + """ + + async def transmit( + self, + transport, + data, + metadata, + content_type, + timeout=_request_helpers._DEFAULT_TIMEOUT, + ): + """Transmit the resource to be uploaded. + + Args: + transport (~requests.Session): A ``requests`` object which can + make authenticated requests. + data (bytes): The resource content to be uploaded. + metadata (Mapping[str, str]): The resource metadata, such as an + ACL list. + content_type (str): The content type of the resource, e.g. a JPEG + image has content type ``image/jpeg``. + timeout (Optional[Union[float, aiohttp.ClientTimeout]]): + The number of seconds to wait for the server response. + Depending on the retry strategy, a request may be repeated + several times using the same timeout each time. + Can also be passed as an `aiohttp.ClientTimeout` object. + + Returns: + ~requests.Response: The HTTP response returned by ``transport``. + """ + method, url, payload, headers = self._prepare_request( + data, metadata, content_type + ) + + response = await _request_helpers.http_request( + transport, + method, + url, + data=payload, + headers=headers, + retry_strategy=self._retry_strategy, + timeout=timeout, + ) + self._process_response(response) + return response + + +class ResumableUpload(_request_helpers.RequestsMixin, _upload.ResumableUpload): + """Initiate and fulfill a resumable upload to a Google API. + + A **resumable** upload sends an initial request with the resource metadata + and then gets assigned an upload ID / upload URL to send bytes to. + Using the upload URL, the upload is then done in chunks (determined by + the user) until all bytes have been uploaded. + + When constructing a resumable upload, only the resumable upload URL and + the chunk size are required: + + .. testsetup:: resumable-constructor + + bucket = u'bucket-foo' + + .. doctest:: resumable-constructor + + >>> from google.resumable_media.requests import ResumableUpload + >>> + >>> url_template = ( + ... u'https://www.googleapis.com/upload/storage/v1/b/{bucket}/o?' + ... u'uploadType=resumable') + >>> upload_url = url_template.format(bucket=bucket) + >>> + >>> chunk_size = 3 * 1024 * 1024 # 3MB + >>> upload = ResumableUpload(upload_url, chunk_size) + + When initiating an upload (via :meth:`initiate`), the caller is expected + to pass the resource being uploaded as a file-like ``stream``. If the size + of the resource is explicitly known, it can be passed in directly: + + .. testsetup:: resumable-explicit-size + + import os + import tempfile + + import mock + import requests + from six.moves import http_client + + from google.resumable_media.requests import ResumableUpload + + upload_url = u'http://test.invalid' + chunk_size = 3 * 1024 * 1024 # 3MB + upload = ResumableUpload(upload_url, chunk_size) + + file_desc, filename = tempfile.mkstemp() + os.close(file_desc) + + data = b'some bytes!' + with open(filename, u'wb') as file_obj: + file_obj.write(data) + + fake_response = requests.Response() + fake_response.status_code = int(http_client.OK) + fake_response._content = b'' + resumable_url = u'http://test.invalid?upload_id=7up' + fake_response.headers[u'location'] = resumable_url + + post_method = mock.Mock(return_value=fake_response, spec=[]) + transport = mock.Mock(request=post_method, spec=['request']) + + .. doctest:: resumable-explicit-size + + >>> import os + >>> + >>> upload.total_bytes is None + True + >>> + >>> stream = open(filename, u'rb') + >>> total_bytes = os.path.getsize(filename) + >>> metadata = {u'name': filename} + >>> response = upload.initiate( + ... transport, stream, metadata, u'text/plain', + ... total_bytes=total_bytes) + >>> response + + >>> + >>> upload.total_bytes == total_bytes + True + + .. testcleanup:: resumable-explicit-size + + os.remove(filename) + + If the stream is in a "final" state (i.e. it won't have any more bytes + written to it), the total number of bytes can be determined implicitly + from the ``stream`` itself: + + .. testsetup:: resumable-implicit-size + + import io + + import mock + import requests + from six.moves import http_client + + from google.resumable_media.requests import ResumableUpload + + upload_url = u'http://test.invalid' + chunk_size = 3 * 1024 * 1024 # 3MB + upload = ResumableUpload(upload_url, chunk_size) + + fake_response = requests.Response() + fake_response.status_code = int(http_client.OK) + fake_response._content = b'' + resumable_url = u'http://test.invalid?upload_id=7up' + fake_response.headers[u'location'] = resumable_url + + post_method = mock.Mock(return_value=fake_response, spec=[]) + transport = mock.Mock(request=post_method, spec=['request']) + + data = b'some MOAR bytes!' + metadata = {u'name': u'some-file.jpg'} + content_type = u'image/jpeg' + + .. doctest:: resumable-implicit-size + + >>> stream = io.BytesIO(data) + >>> response = upload.initiate( + ... transport, stream, metadata, content_type) + >>> + >>> upload.total_bytes == len(data) + True + + If the size of the resource is **unknown** when the upload is initiated, + the ``stream_final`` argument can be used. This might occur if the + resource is being dynamically created on the client (e.g. application + logs). To use this argument: + + .. testsetup:: resumable-unknown-size + + import io + + import mock + import requests + from six.moves import http_client + + from google.resumable_media.requests import ResumableUpload + + upload_url = u'http://test.invalid' + chunk_size = 3 * 1024 * 1024 # 3MB + upload = ResumableUpload(upload_url, chunk_size) + + fake_response = requests.Response() + fake_response.status_code = int(http_client.OK) + fake_response._content = b'' + resumable_url = u'http://test.invalid?upload_id=7up' + fake_response.headers[u'location'] = resumable_url + + post_method = mock.Mock(return_value=fake_response, spec=[]) + transport = mock.Mock(request=post_method, spec=['request']) + + metadata = {u'name': u'some-file.jpg'} + content_type = u'application/octet-stream' + + stream = io.BytesIO(b'data') + + .. doctest:: resumable-unknown-size + + >>> response = upload.initiate( + ... transport, stream, metadata, content_type, + ... stream_final=False) + >>> + >>> upload.total_bytes is None + True + + Args: + upload_url (str): The URL where the resumable upload will be initiated. + chunk_size (int): The size of each chunk used to upload the resource. + headers (Optional[Mapping[str, str]]): Extra headers that should + be sent with the :meth:`initiate` request, e.g. headers for + encrypted data. These **will not** be sent with + :meth:`transmit_next_chunk` or :meth:`recover` requests. + checksum Optional([str]): The type of checksum to compute to verify + the integrity of the object. After the upload is complete, the + server-computed checksum of the resulting object will be checked + and google.resumable_media.common.DataCorruption will be raised on + a mismatch. The corrupted file will not be deleted from the remote + host automatically. Supported values are "md5", "crc32c" and None. + The default is None. + + Attributes: + upload_url (str): The URL where the content will be uploaded. + + Raises: + ValueError: If ``chunk_size`` is not a multiple of + :data:`.UPLOAD_CHUNK_SIZE`. + """ + + async def initiate( + self, + transport, + stream, + metadata, + content_type, + total_bytes=None, + stream_final=True, + timeout=_request_helpers._DEFAULT_TIMEOUT, + ): + """Initiate a resumable upload. + + By default, this method assumes your ``stream`` is in a "final" + state ready to transmit. However, ``stream_final=False`` can be used + to indicate that the size of the resource is not known. This can happen + if bytes are being dynamically fed into ``stream``, e.g. if the stream + is attached to application logs. + + If ``stream_final=False`` is used, :attr:`chunk_size` bytes will be + read from the stream every time :meth:`transmit_next_chunk` is called. + If one of those reads produces strictly fewer bites than the chunk + size, the upload will be concluded. + + Args: + transport (~requests.Session): A ``requests`` object which can + make authenticated requests. + stream (IO[bytes]): The stream (i.e. file-like object) that will + be uploaded. The stream **must** be at the beginning (i.e. + ``stream.tell() == 0``). + metadata (Mapping[str, str]): The resource metadata, such as an + ACL list. + content_type (str): The content type of the resource, e.g. a JPEG + image has content type ``image/jpeg``. + total_bytes (Optional[int]): The total number of bytes to be + uploaded. If specified, the upload size **will not** be + determined from the stream (even if ``stream_final=True``). + stream_final (Optional[bool]): Indicates if the ``stream`` is + "final" (i.e. no more bytes will be added to it). In this case + we determine the upload size from the size of the stream. If + ``total_bytes`` is passed, this argument will be ignored. + timeout (Optional[Union[float, aiohttp.ClientTimeout]]): + The number of seconds to wait for the server response. + Depending on the retry strategy, a request may be repeated + several times using the same timeout each time. + Can also be passed as an `aiohttp.ClientTimeout` object. + + Returns: + ~requests.Response: The HTTP response returned by ``transport``. + """ + method, url, payload, headers = self._prepare_initiate_request( + stream, + metadata, + content_type, + total_bytes=total_bytes, + stream_final=stream_final, + ) + response = await _request_helpers.http_request( + transport, + method, + url, + data=payload, + headers=headers, + retry_strategy=self._retry_strategy, + timeout=timeout, + ) + self._process_initiate_response(response) + return response + + async def transmit_next_chunk( + self, transport, timeout=_request_helpers._DEFAULT_TIMEOUT + ): + """Transmit the next chunk of the resource to be uploaded. + + If the current upload was initiated with ``stream_final=False``, + this method will dynamically determine if the upload has completed. + The upload will be considered complete if the stream produces + fewer than :attr:`chunk_size` bytes when a chunk is read from it. + + In the case of failure, an exception is thrown that preserves the + failed response: + + .. testsetup:: bad-response + + import io + + import mock + import requests + from six.moves import http_client + + from google import resumable_media + import google.resumable_media.requests.upload as upload_mod + + transport = mock.Mock(spec=['request']) + fake_response = requests.Response() + fake_response.status_code = int(http_client.BAD_REQUEST) + transport.request.return_value = fake_response + + upload_url = u'http://test.invalid' + upload = upload_mod.ResumableUpload( + upload_url, resumable_media.UPLOAD_CHUNK_SIZE) + # Fake that the upload has been initiate()-d + data = b'data is here' + upload._stream = io.BytesIO(data) + upload._total_bytes = len(data) + upload._resumable_url = u'http://test.invalid?upload_id=nope' + + .. doctest:: bad-response + :options: +NORMALIZE_WHITESPACE + + >>> error = None + >>> try: + ... upload.transmit_next_chunk(transport) + ... except resumable_media.InvalidResponse as caught_exc: + ... error = caught_exc + ... + >>> error + InvalidResponse('Request failed with status code', 400, + 'Expected one of', , 308) + >>> error.response + + + Args: + transport (~requests.Session): A ``requests`` object which can + make authenticated requests. + timeout (Optional[Union[float, aiohttp.ClientTimeout]]): + The number of seconds to wait for the server response. + Depending on the retry strategy, a request may be repeated + several times using the same timeout each time. + Can also be passed as an `aiohttp.ClientTimeout` object. + + Returns: + ~requests.Response: The HTTP response returned by ``transport``. + + Raises: + ~google.resumable_media.common.InvalidResponse: If the status + code is not 200 or 308. + ~google.resumable_media.common.DataCorruption: If this is the final + chunk, a checksum validation was requested, and the checksum + does not match or is not available. + """ + method, url, payload, headers = self._prepare_request() + response = await _request_helpers.http_request( + transport, + method, + url, + data=payload, + headers=headers, + retry_strategy=self._retry_strategy, + timeout=timeout, + ) + await self._process_response(response, len(payload)) + return response + + async def recover(self, transport): + """Recover from a failure. + + This method should be used when a :class:`ResumableUpload` is in an + :attr:`~ResumableUpload.invalid` state due to a request failure. + + This will verify the progress with the server and make sure the + current upload is in a valid state before :meth:`transmit_next_chunk` + can be used again. + + Args: + transport (~requests.Session): A ``requests`` object which can + make authenticated requests. + + Returns: + ~requests.Response: The HTTP response returned by ``transport``. + """ + method, url, payload, headers = self._prepare_recover_request() + # NOTE: We assume "payload is None" but pass it along anyway. + response = await _request_helpers.http_request( + transport, + method, + url, + data=payload, + headers=headers, + retry_strategy=self._retry_strategy, + ) + self._process_recover_response(response) + return response diff --git a/venv/Lib/site-packages/google/api_core/__init__.py b/venv/Lib/site-packages/google/api_core/__init__.py new file mode 100644 index 000000000..605dd8be7 --- /dev/null +++ b/venv/Lib/site-packages/google/api_core/__init__.py @@ -0,0 +1,22 @@ +# Copyright 2017 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +"""Google API Core. + +This package contains common code and utilties used by Google client libraries. +""" + +from google.api_core import version as api_core_version + +__version__ = api_core_version.__version__ diff --git a/venv/Lib/site-packages/google/api_core/__pycache__/__init__.cpython-36.pyc b/venv/Lib/site-packages/google/api_core/__pycache__/__init__.cpython-36.pyc new file mode 100644 index 0000000000000000000000000000000000000000..6abd8c0e357887f12187f19d48c7b4f251dd4a89 GIT binary patch literal 451 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 literal 0 HcmV?d00001 diff --git a/venv/Lib/site-packages/google/api_core/__pycache__/datetime_helpers.cpython-36.pyc b/venv/Lib/site-packages/google/api_core/__pycache__/datetime_helpers.cpython-36.pyc new file mode 100644 index 0000000000000000000000000000000000000000..8eeaca6cc32c8305d68aa50f4f246824de873ec3 GIT binary patch literal 8065 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 literal 0 HcmV?d00001 diff --git a/venv/Lib/site-packages/google/api_core/__pycache__/exceptions.cpython-36.pyc b/venv/Lib/site-packages/google/api_core/__pycache__/exceptions.cpython-36.pyc new file mode 100644 index 0000000000000000000000000000000000000000..1aa8e211d80437d204994464cd7e50a41014fabb GIT binary patch literal 16234 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 literal 0 HcmV?d00001 diff --git a/venv/Lib/site-packages/google/api_core/__pycache__/general_helpers.cpython-36.pyc b/venv/Lib/site-packages/google/api_core/__pycache__/general_helpers.cpython-36.pyc new file mode 100644 index 0000000000000000000000000000000000000000..c829e178481be0f99e6c5e9ce929c1214373f2a1 GIT binary patch literal 657 zcmYjPO>Yx15cPgFX=&kJE-CWl&@Hy&#|@6FgRj*bp4^ZV>qOvoSdV1>AUi{_poNHQTZkYO22 zg4TzVQ0`448O!9JOkx?1N!qzhKS5c6b#!Jd%|V0ZCB54C!e}~MY2lU8yi|VE`-?@% zsP1H$G$PAH(8RbJk4ngUH1{0Alkda_^YAXT$3B|J7$q|JfqdKOE*O)RJ-U6@-;x+p zy55cDm7_(ghx&qhT5v5(aJ1sqE7WDCa}eH9)V7m&-b;hJ%bioX202Ri>I3DJcAjei z^?utyQ@rl%YSfWa-|D30s*kg){+H`Pf0%vk4+kHz{&+mN9DV*cx*lWMPLouD{7LL1 zZ0p}|@rtb+&WcUBUlq(Cqg88Q65PU@imkM|F?PW=z%9LC4wm3NSbD|;+f_vL(V84OpR@?6bIK;EM X`+8~Qs)RRBFmg>=9CpKQ5=Z|5M>)Dx literal 0 HcmV?d00001 diff --git a/venv/Lib/site-packages/google/api_core/__pycache__/grpc_helpers.cpython-36.pyc b/venv/Lib/site-packages/google/api_core/__pycache__/grpc_helpers.cpython-36.pyc new file mode 100644 index 0000000000000000000000000000000000000000..a6c5abd9dd92007506fdbf8718637becdc0c4a44 GIT binary patch literal 14356 zcmeHOOKcoRdhYIda`+VWmLy@>*iYQyVV>-=dSI@AA!|8E# zk7UjcjldMJiy+Q9m)vp*b`b;!5Cl2okW&shrNQQ4-~+T76MWi3*-4Z);*&%skb^3|gEz%GFPcSuuw% zXT-c%!1JtF5+}ssQ@wspyedwLQ+PY?>a7dnw0P~vsK3PT7sTs$zX)g-#U((yb@^lx0|x-Y}bBEq}-_L zQN{h*al4`CcLMyHZ@L{<+HGrB^?P{B0eShNXAbu|?%*7XP#b`tM@DdJptbatG0-f7 zht2i>=9c&M)n3@*K>9OtrxffcVBJvI?n1gm7(vqgW3~mcY|#+^i5YvU)IcryIx@0LIeyq z9pCgCX2*4fD{2fVDklSORC7^j*AA#@G-X*%+YSQDl6lM*y^t)TVj`zfuds_#tEzS400(ajHLRXsaY&mZ8{U5#a z?p9a&E!PRR9=n(zk*O1US3!qHXf|xeHKptL&5lP)WCjQ5ypN`x$6KFzJ6nMlx>vg( zoZWPTt)}lc+wL{H>sgL3-D|Ye$x7C`2hl03YlqIRmCk~wyh7_q^V5nIT~_c+m)yV) z`a;VdETIUsUuj3Wu7y}`di$l;;QjWre54=h106h<>wkF9?y3b)Z1-8mmIqh4#N33r z8A{jQk1Ix4AgDPQgfAL$0rxAogIg#LD!&514fH?9AbB9t(y9|q%Nc%a&g24B0utjN`3JvJ#8`WZzC&EPK2VLhT@kx{mysx8*w7tN!8q(jF zH1TMjUM;2}vlCb&Z_8#775AR-Gl#8H)ny5dnHl61bvw(AE$Qyt-L5NAVt;^-0r8Ax z7t{nrVn&TysvoutJ8NO;L6i%Xw@knrDbQYf- zPt`>H8@PiO3Ri!^cysgAGMD{7v6j1YVS~J2OWu_RGP7yiZala0+bpqgkf?eO5nB|QHhoau%gpl={8*2eOU;KZ-^@t^FR=J*y@%Ab*BZi0W`f> zF!Vh5WiFT3=ZyZV$CId*^iFp$32nNWRJ4@`yb1aruw;brVA7f-CEJ0I?P+oyN$YUe z4k3HOp6mpurPFh%#?BzL-`!_ikXTedWvADygs8Z z8vR$E!%RdGhu0C^=}9-Q4WUANtcA6p6(FfM^7jL|}o$nFoV%ABYG$ zw2#4L8CX2YVDi>;Fc}B=f+$USfn_@(jI?8LSpgpX3@)!d50?bi3nDQWdN6RwNWg45 z&0{dB0*k{8Ce`O)G79ho(K!*q`e_4^?^~xgfz6*}FuL+QjK*QY-*{M^XJb05SQgxo zUK>_^G-Fv`_3XB?`6Zcr(xieUAlv4UL@>fhTJUa_v}+_WuOz;av|y5GB?-NZkQs`> zGx%@=H+wE+y>gSBt3%8f7Sw4mQB_Kj%&tjVC5S< zgd>#L>Eyno%2;V=7$X66%U3;5!ecOZywKc-ePXu#rst3cB;BhpKv_#E(-QuZ8>{ya z3mrR0Y(bhkez?o(F5X(E*Le&(lwA%o+2M^aq|{*W8{Ax(2j*kD-Gjl93>r^e`Bo07 z$QNn1)S~}m{5V)jEc!!(91C){k8+2(5ElF(Cvx9GL&H*oriX6-8FYJ|Eqz$|VX;*j zK=T{#uS^om`s6!yhF8>a9Kx&hX|H2GuU%mgnvdxu^@uD6;4#4Co6wkN+Pfi%)DS9af zpachCR$jyJlox&_{k9qXOI$%O` zmEC9+dZ;B{mvYn_(sMhaeV}-TnT#8!F#@)(!Rq9k33KOw`EF##m^S!cIa|bo6hVN= zE&Z`?J-iU2#vwZuWL4Pzg*+x%(m{@r!hDm>`68T58iWXM{hJ?TrY>2>V3$$^w~ zHrwWkici3l?gbELn36K7e{tEn}{6CTp^4J#VT2| zBNUH&K4S_eJyw}gvF9`1l?b^}%|{gv7IF}hWd`qR^WlS=Yxk^257zEm>z}S|Zr!fgA<4&eNaWB(jxb4bX6b*x%RrNh104(v6BZ#X z{aYBa@(PKXRvykI9EIc?mbj&^S`PA3hGlFO z`ci03VZ%sRqZJZVhpKkEHPf0s(hiH)SN)u z9G;7V+@O3!4olwtQ%qzX0hEwDG^hxFzw1*J$aLVHx(FSC>zES)*XdznIJ{Ll=#uH!X4S6m?+iG#5# zI7~+|tS4T(O<_HEzYEt3PG{hN)nNxw;}KYyafVEc(3dCu&OYV}#wSLPT3M0jOj!2^e5wgR!stj)ikc+h~EHoyfM7v{dXLrT>~tPqHYyCe8b7?_$`88{qI z;sLjlaHMSZ82MNf5OQ?w_d+E$u*ut)*khLm%px_MP2fO21m?;nEC3ff=nG8dOP-C- zv0TWfwikpZ^mN=*#XFfZXgNmaf%xTP&v6MsH-Pj6+xQ&_Fvu0mnpQ9~BmO+H%4E`v zz#{-%1WwT#>pOu;&n{08w6kP0S19gQTUX4xKEi=NO=h^c`Dw!5Bg1EqjcFdQBhLpI zDgHb#h1Y1fk{F3N5F87WhZK)m5Yzms=Z7|I2#(KMo=AD7W2R(|ztThjp6R;-1}DBG z^~WHNlb6TLG2Udnvq8dm2al|Qze6G81TN{uj0{gULL3IJebVc;d1^yCvKYYDRhFMU z0XAcwp`_Y0!VLGHX|v3ovNhZb)uf@H;qMwE>P5w#8`YB>)~KI72HB{nW`z(e zA&R|qOOPkhGgIHbz9v7R;B7$ekB0|0meNcaCNSfdgdi)Ws{C&0X^+kp; z!VJ+A)NBXAA{jhe9Ro*&y-(Za|)z|@g$MWuKO_4yRPu0r^%BD+OY z&kmb$vN+6qi9TZYAn_0@q-^WI11iC5D71@Zgr16sWS*gzrm<+8(ksSX4mvwuG0J)w zU*rw6b6A(-h15M6)IY%;tfGK93d5gVgh4^*-xZ)cb@>KqROr%D!x$7PMSx_$$ZwUH zvTHC2u+*eIZF5vZPLQ@N2u3w#XiInui69_l7}vxyl(J2*;}9`bh8yy3`%omyyM7Ro zf4fR7vpf_rnN@?#i_O#jn;Q84br!Vpf4k1gFq9J6|EuksabcBgytNnBz==**xjVQt zLU2kIYqIAaTt$vnKutA+q2ZF60n{}yVqle6O{ZH^vLg}5+i(lBO~yYbih4YEkTn2O z(;C7lRr*QC|2Yj`EwFx(A42r9N|7JY+jSHh_;v%&Xy(q^rga;+e(U!7{iw_-QxK^> zH%cW|i-@@tmB>_ZNlPh^JOaVx2uuC+L`^cTcjgkcqZH?VpnE`R5N*lOlRqex+=3xL zL2Wc`K_l<_f?QSk2UJs{z^UJZ9#3?iQmFG*Y<xpH{9ft$1AX{MBN zq?9YA9BD}uL=jojg2=;vD@U_d;w5i}y`BCQDr2kMHJKmYya&(4OIksZAWKFE0gxT1 z;pn0#g(uf>2NeBO8Bi!i%|f!4PhwD+Yf_o#vM|hlmnh1MsUWr*TNGr(sMJ?9mAnP= zM}Qm^9FQuAQ%&+Ns_Lb<*VtlkarWU!@@)i}hsUV9}!R2TS7iurMiGg}GM<#n zp2@+|Gb(x>7GHh>YbX%a+{Ok@YjCWgHt$>(U6MNr9pm zvDlU%v-eq`iLM$~atKW*-4-O26cc-!xPGT!`z>gWs4|k;0q7n^xvt+u0FVSvW}%te zPFpd^gIJ*Pv9T>$b&`(Sto#C{L$Aq|!^;ia0cCu%0=r2^nbZN7e0;zKf}0Px6va6{ z&Zpye%XvP|r{jRj1wP29ke3VbeA(xAMyhX<`7j?X4CO+OWE6Nc5m!j!drI66K zFM>1IOavS_TAOZmTBWRAFjN3Bf%)jhSVV)MK-wIbP8;!bT6Q=cE{=)CF(rg1Qud97 zH!~curoX?BLuwTIsF@!hu>C{P3vdY7RjE}LMOVxNzsDgl$L}<}CPf!H=FN~2nWv}!HKB7)m5{50F~8I z--uOW)Nn2b3iLXYEIsR%A@fQ#wc}#iTsLp|{yNiXB?fXm3#>YMj2cdgpyN=uUx(WE zt?tgdHB_(Aez?B8W6R}Ce>4DUYTO$9Mhg`y*#C&fUjG7(`^#TuT2sVK;?N%k;oWup zy2$|33B(Pu$PTemF^DhT{<5Y9z`*ekYCbn@oSuyLahz3P(#4!)JFqY)Vn-{MF0e=v z5b>DGalM0}*>Ye8KIBTgXaNbB$F}tRUXXU@1R?@cJb~|9&sR;APXO2L*a4E52}i~K z$Jcx~^Z3lp@#{fd=}PFwYoD%1b&T36xq%Vc-Jl3&86T3(WJ=;t4H0nyE*n0$rPmQF z%e7i9%M%n#B4);pt#MW>SV`JehtLV#F}}%g%B$vQgcl+hD*Q{tPso)C1WslYMXmt+ zLFwF;FVgwam|(t1EPdsB8}*l~!$uRhdVDftM5nRo`Tw7 zn=Y0+V-!|m>X=EJZ-J(~t7@Le5dV2p1yP5C4w0EWD^FZse&^lymPZ+oYM9!S&t8$G z!uGu8k!=raADV^FU$M15n`lB}%OF00rL4c9l|;&u&8NR2RY{pK80-1|sddHDo5a!S zQ9{evQF~?X&<)63*%0`}BOOCDc@8nEd4pD<~dt}-oexu_Ami4!UI+0w1A6n7p^#0iq zFDDR-o*_eWA9HFav3OOxy>oGb5OXe8JWR+n_XqMBE>J5f4X zj9J-&ib0Cd>$@^Kornwzht<>SXC{>y>F-n1${3warp*tWO*L!d#IsQcA%4Jgq=Pw0 zLB%LnM>7f&1?e9%=$^|`KilZPgs+0Hj&A>c_+}yf({cD_8~s3h-yETD3_v}8FN9}D zK>c%yalU^(OW~1Lw?+aN=%P5B*j*hV>Ax|GEku`te-&}ZG2P(hPGS+SqJMoZ#NqkS zN8SNxZYLb)hbeeX3f8}*s2cs#Bd8`VMg+(tEXQ|X3i}v5)$vzJc#h*W-Rq>i|22cz zh>*y%8F5=D;kGnFL8tA*Kp2w?G4&=M1x1*Ly8K%Pl@nPa@z<&Whdg`hx2khv{<-{| zX3M@g2_d;dg-b<)iY67iRCrXhsMw=oxR3dbRn!(fvtcy$6o<| z`Ep)Tn`!}(0-zQ@@*LP33s*pHv&x}JMsbn*!)8u>oe#0j!zj!o1rWSZ8}Y+;R-ss8fhZ;5jxKL%vEh9a82i*%X{S@qP< zeMbK(vdKr%M}ma)^Qv;fC;1M+B4xryX`=i(MLvn3>U<3yl;J3@`~+`Ng**=tB4g~T z=+PajEvkI8(&FS(*Gn;TF#RVjUR3@_o$vfHomA(4(?AS{QhWxTe#4Xg5DuccIlYoY jP^eO#Tl}PazI>Md!44X_@?rXRC6DCbOm5-b^1^=tge^Kt literal 0 HcmV?d00001 diff --git a/venv/Lib/site-packages/google/api_core/__pycache__/grpc_helpers_async.cpython-36.pyc b/venv/Lib/site-packages/google/api_core/__pycache__/grpc_helpers_async.cpython-36.pyc new file mode 100644 index 0000000000000000000000000000000000000000..6dc0128bc4d7eee606470883c1bb07b7aff27377 GIT binary patch literal 10684 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 F`5#dlg1`U( literal 0 HcmV?d00001 diff --git a/venv/Lib/site-packages/google/api_core/__pycache__/operation.cpython-36.pyc b/venv/Lib/site-packages/google/api_core/__pycache__/operation.cpython-36.pyc new file mode 100644 index 0000000000000000000000000000000000000000..22398b2906d95c41f47bdf2c045e4eaacdfa324f GIT binary patch literal 10647 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 literal 0 HcmV?d00001 diff --git a/venv/Lib/site-packages/google/api_core/__pycache__/operation_async.cpython-36.pyc b/venv/Lib/site-packages/google/api_core/__pycache__/operation_async.cpython-36.pyc new file mode 100644 index 0000000000000000000000000000000000000000..f1ef3b5ec1af72d63bb08db3778b10b7faa6a4c3 GIT binary patch literal 6646 zcmcIo%a7Z}87K9YRx5ATc9N!PFilcqRoGfPc3ekjif%T3B-yUhwS%_G1{B2^Nt7v4 zouRzZV)H=PKu&4U-U}4HrH5X7Eztjh*PeRlt*4&)`-TrmyKAF|R07E%Ih^_Cd;GrN zH`i8IYj*~ZtEy!^5a6MVA8t++Qm*$ zw~JnBT<(;0yW~~I)lOBn%U*4~(pfQ$I|i@t>SKdfMR`;|&UaRMjjud5It`w?Z#3)n z+d0G7QZwIq_a5s{!>JUC^#jSgz#m+eQ{Q*}0ShKV+Myfxib;V!zTm7cgE6}k1Ord7 zZ7-N|w)Mfgs#U8!7z!n_u^iiHJ;A05pM(Lk4{SHo6NE#7!PL|XS!CdCb9;0IIX&9F$4)v-OVXFCrSvwfaQ zJ{Q{N+~R>Rth67=|80t|<>#VLYfb0ah)vsU>zAaI6AO&rFRX4!ajjEAZ!8QBUHlWS zYwR}7s3tyf#6-Ia?$#zU2!r0VZw-Y9vnf2QYo%FA*LOqL_T~Z6%3e#+her(A#x}gy?s?*)k3PP{K5OY<38a`$ zGoRsOOtGciojzdU&n_(D)CoKb3bAH*z2uuHW3Ul;XCavwY#yhSn94!cOV#C8s{~&G)FwxTzCM8&F#?s zmWEGAGLrZIAB1YQ#VU?_Yx2|N!D+JdjRiWIpB z))*j^fyaiy0c;kcdxFD+U)`m_@G%V~c#G|cfi1Zwlu8Y)#d%G!ZkG$2V?NRCUSh}t z2d?K~!ljXdM?y-MbIjJ8Y5jM*p*t4AH0*YnEeF#vpqtE|2osy38>?y8DHBNGM^}WT zKGfT2gvPNkGLK5!{K_Vq z654?=qQVZ6ShQw2!Fb{c0#l39TJ(aYM3@dj`FB2Fvm6za@cL18EV82|Z;)80qomTJFehtuIctj?wTNbGZ=9)`hWf9ksjfqb|> z6Sid6_mvnU$c1EA_Z=~~{^r%!_YqMe;e`8-#L#sB61E?@ml0HbkO12u2H*q(f~CM` zYKD);=;}Y(-*J2U$_>Tk2{NfY5Nbb$zRlF@H?wtGI-#^CGg-qLZsAaCI2qN3S<3#k z+~IS}fZa;X=9ttQKf2PfjYE}ig6+xb=Hb>ExO*?9AsT0yGnJD3@@(GJYMOEdBjR!a z7x_YV`YyFD;`B=#3SWqlb9l63^icx!r}4aa zOk^*Acr#f?igT@>Axfd$wvMxO3E6Bcb&*z7Nt?UPl3qzvxofN2uJE`dIieNqkG4NU z;+E&|M81gA6V^+wKE|QQ>x_KeEaVF2DFdZbI$A5}NLM=aqU&gcSn?=$ghgvJ{rep- zPl*iY9>UWAH%~Jgz(lLT0lrL;xALWw1QAhRW`sdu?N-;UpV1`3*9mwB)gLpv^oBS2Kn08zX!Hzv(ydsB3k)T z?%0rw!$kUdf#;4*`CeEYm2h9y&nm~cPl3myDw)zW{P&WcdG!1utc_OmeSNeVU;ES- zh0s^|Pl4Z~#t}xuR~M)!FCLqVPk(`u>F35C!iywmmJYY>3uKRl;zP2Gv&KcuQqE^? zpE4CC#~6)8Yd5L@NGGU*W6PO7_kET5BnD3pcr`QlK zBsvOy=3AgawXg`|+_ ztl!bp5!90y-Yt?^zCu0Az-+>RXq7(6Q~|frNTo-sW{*$!k35ed6depFqgcsbKrADk z%?8eNt>9nF)e+yN{9*HiS3NnOEyX-7@b5U(22L$xTIBQmf!p^=B91P}ZFc34Vl!vFu2z3+4S4P1$?&%81_L}T2 zs1vA4{29%*_rdl;?3z07?lueBy7C8DpQMn|dTr)n6A(zA(0g<~r56@fW5uia9s23K zWmGEW1@rLbliE)Bz``d>Y9>F?YJMIKQZq#(lxyBaTEsn|77>&?{MYtSP{klK%pSm}U7Q$9<{oRptF1r^QTkHM^P_~)$< zlxd>ra7^-+ZL#3X|D$@6QQ)TRz*cN*bCD|N3`1wir(8xq+anS?n}cQ6WB2w0C{BC$ zDi)e3F)GEJ^n`!Q=g{RF9Ev!dQEmW93b}@Pc=3cbV{tQm5`D|`Nmg6bXX?b1fPxL} z(D_k;64ApLFJ3*{Pe>2(JXGK8YS?U+7o0+)um;ltZCyy>j!|`cYj^wB&d#lO&L%-o zH5>D<=pP4ej$rc?{mVKw*Qwg@?Xl3+hBXfO)T4IYvVJ|az2r^V!VZ&TS(2Qvv--}h z+gl&*Jh1j|J=pt|Cdp9+)Cc@EoN4N*samw6i9bjecERNL@udc#c$wO4WE0uKDOydc z1XML1rpeeWR{9<4q)9CmU{`UdXK|{m7b-b(yq9tmi&0B=^K=>Ao1ERzuZRJj(S8NBQ4UemCt`Fx)nr5a^C-cFtwv z4W~H6+iU>nc383v7=x6qfYVJI6>r%Pu$|55QO$xlJ#rn!50P@1@mZ7trXdP)?mNNGpz0(ERj$x47WU)|G6vQ#uZ@-}q3^tKBcdURrS0KVCtz z6jf=(Arho6441n%Qdl+j;iHt5zKD zF#@h9FBhCMu9<4d3psH#Xm?h0dWko2^&+(-3xaE?BY2A{KaSD&CxnfPxN;!}va4w? MQQvxg{c~gOznnm2G5`Po literal 0 HcmV?d00001 diff --git a/venv/Lib/site-packages/google/api_core/__pycache__/page_iterator.cpython-36.pyc b/venv/Lib/site-packages/google/api_core/__pycache__/page_iterator.cpython-36.pyc new file mode 100644 index 0000000000000000000000000000000000000000..a5f8f7513b5369a358126b01b703c865aacaf045 GIT binary patch literal 17659 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 z z4k5CiD61fjC9BcgC84|iRMaiV_gCzNmR30ijIZiQO^4kYoWN4(VUYZ{3K+Q zy#dezgkrSYh;Q0$s%yKwdT$Nq3Fo~xK*dHetY{34kw9xEO?>SC!#jX&evC&FDTF1O z(}Nd2z?6~O0~In-!>*vtNZcMm!@K6)<@I;(-Sm<;gCzqkHnLR;dBK?Ec*|(=r?JVK zB4`W97TStq@!-41r6o3dvH5L0Hwjy8oiT4N-&%qgn|Ici@2;6YUjEp-&4s;-Lu=Yx zS^j8UiGMf+ZXY1rgcW~>Emn9S>ZGvAw|Pd}?9r~sl4aiEtPY1dPQM?8MAQuUkR`U1 z@Q5+q3tZuMaZ>wUsZhe&_z!EW5uQ~4=I3km+UeS<+MGm%9W;(V^x6FQ3?VakS5;6f z?*5!g{uW43DvEavoVmU9(H&?oi<{PuVAxK!@!>xw5fp$89!M~YWu)f-RdC2e_`U4-3Y;$vPc=Fm}e5HBCB&79bLqD4=vyWGQ^RuwCALMYe!cxNEJH3#vPH@9jL2 zK%{~2{~tvKhFh2p0)a7?GZxLJe9Z&Mw@PzjxrxOplIovm2xMGwDCI`7r#EU&-Qpu; zc~W1Lzkb>!>Y(cfcn~1g3z8aMYC;p8-+z0oE&#?CN9)+%>%9op$o@HRjc2fND#KN2 zEu+M6b`860l?nsnh$@L+7>EBIMMeUcIx0vi2FLN>#jMc8?ugq0tCJj&5@vB9?{jK# z=oE>nNGZksuQ(+22!*S{+?1%oWIyl@8fE-|u6sBYhkpZ5>XyVW@NYw>TF17@iGQfW zKTL-+w_)NV+h+Y49L>r6gLsCC#S54Wgd&7!7zU}$bx}!F04>8pa3Tg@03(DembVEI z47KYGr(+Q)@1Y2#(S4dwsY<~Ds`5fFfsop59VIi)5rdU2n*Az13DZV2H5v+3wXvVE z!csYvC0#UtLm4~HuG)fz%>cgs+tx_IBBD<8G8%M`3kIJ=jv?MKFaBd65WLxw++QuJ`1sgo@O$FwqkUn)|9N3Gd zA(Li)2NxLk#A!%x@hmA5iRi_~xs2KT+6Aq|@l4!(;ahV}Gl#CKHF3x9?aeu9W zM`GAlI^5vR4}Y02(rNq5bTT0b@LGf)#W5t8do#;Gd5P9maa4aZ0<1Q#VA`6BNIpPs zV#M*6BuWjjT~jj>0d`6y!n4u+G`+*;<5VSmyD^o*W|?t?Ro!W8I@PBFYoD7SIIXjj zxT~hF6Oe2a^l!0Cn?^<+gR}?Fr*-Oh9K`H{UPQ5(W53-mzDkHRF(P4* z^P9j7DKP{M0k_}8j{;b#NGDmb@VIB+`12=3c?H6@c$54_)U^?3@j`i zd_7CZ3|I(WPuS7adMQR7?k~Up!Sb4h7|dIDmfySC`bO&M+UmWPH4VV2$Eod55-y4? zeL>7f!}O2TX{JlHbAl{rL}7lq_PodEjajwR>IXQNNI9&i-5yHlzKz@AtYzD@Y?g#J zVRh-98+UOfo23*CB6TXs%)}VRA*>2!8Ni0Mx71(3TwleNl!8iyTA@~)f1_4Co3A~p N&CUOQ?%e$M{}Vpw><|C| literal 0 HcmV?d00001 diff --git a/venv/Lib/site-packages/google/api_core/__pycache__/page_iterator_async.cpython-36.pyc b/venv/Lib/site-packages/google/api_core/__pycache__/page_iterator_async.cpython-36.pyc new file mode 100644 index 0000000000000000000000000000000000000000..c2737213ee41804e6c1b29cbede9fb110214c42a GIT binary patch literal 8682 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 literal 0 HcmV?d00001 diff --git a/venv/Lib/site-packages/google/api_core/__pycache__/path_template.cpython-36.pyc b/venv/Lib/site-packages/google/api_core/__pycache__/path_template.cpython-36.pyc new file mode 100644 index 0000000000000000000000000000000000000000..e45cfd18609858e78f1b3dd573d7e08fedf86c4a GIT binary patch literal 5211 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 o=Rb}AXSiWCpZ{+DgZ%8j0rNuDPXGV_ literal 0 HcmV?d00001 diff --git a/venv/Lib/site-packages/google/api_core/__pycache__/protobuf_helpers.cpython-36.pyc b/venv/Lib/site-packages/google/api_core/__pycache__/protobuf_helpers.cpython-36.pyc new file mode 100644 index 0000000000000000000000000000000000000000..3941a6a34a0e0565530f353d086da805a1d33763 GIT binary patch literal 9215 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 literal 0 HcmV?d00001 diff --git a/venv/Lib/site-packages/google/api_core/__pycache__/retry.cpython-36.pyc b/venv/Lib/site-packages/google/api_core/__pycache__/retry.cpython-36.pyc new file mode 100644 index 0000000000000000000000000000000000000000..c6366e6163eb929bf21051b358a83b110ca59fdf GIT binary patch literal 10332 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 literal 0 HcmV?d00001 diff --git a/venv/Lib/site-packages/google/api_core/__pycache__/retry_async.cpython-36.pyc b/venv/Lib/site-packages/google/api_core/__pycache__/retry_async.cpython-36.pyc new file mode 100644 index 0000000000000000000000000000000000000000..1212743444316b3c54a70e3453a1d11e5f57c7b0 GIT binary patch literal 8810 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 AHvj+t literal 0 HcmV?d00001 diff --git a/venv/Lib/site-packages/google/api_core/__pycache__/version.cpython-36.pyc b/venv/Lib/site-packages/google/api_core/__pycache__/version.cpython-36.pyc new file mode 100644 index 0000000000000000000000000000000000000000..b3278e4dd6b853ada6a10713962f9843307206f4 GIT binary patch literal 271 zcmYjMu}TCn5Y1j8hjRD}X|K3FcHKr1v9l2y!9oT?E}6^5-OYp~yRz1Pi{LL^>t9$I zISU8gW8lraH*>LCo!*&u@w8yU2pVIT$iwLDD}@eblz}%8aln``@Cp=~=CZ26 z2YNx3V8Yg_9=UYMZc>Z;#P?Dm52(mEn{qghb6y_usGH#4?jYKP8!uHS4Ms3TrpK-H aRwxR%{X4nz^I>^CkRE%yIsbh$gZ%*b)KvHY literal 0 HcmV?d00001 diff --git a/venv/Lib/site-packages/google/api_core/bidi.py b/venv/Lib/site-packages/google/api_core/bidi.py new file mode 100644 index 000000000..be52d97d4 --- /dev/null +++ b/venv/Lib/site-packages/google/api_core/bidi.py @@ -0,0 +1,735 @@ +# Copyright 2017, Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# https://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +"""Bi-directional streaming RPC helpers.""" + +import collections +import datetime +import logging +import threading +import time + +from six.moves import queue + +from google.api_core import exceptions + +_LOGGER = logging.getLogger(__name__) +_BIDIRECTIONAL_CONSUMER_NAME = "Thread-ConsumeBidirectionalStream" + + +class _RequestQueueGenerator(object): + """A helper for sending requests to a gRPC stream from a Queue. + + This generator takes requests off a given queue and yields them to gRPC. + + This helper is useful when you have an indeterminate, indefinite, or + otherwise open-ended set of requests to send through a request-streaming + (or bidirectional) RPC. + + The reason this is necessary is because gRPC takes an iterator as the + request for request-streaming RPCs. gRPC consumes this iterator in another + thread to allow it to block while generating requests for the stream. + However, if the generator blocks indefinitely gRPC will not be able to + clean up the thread as it'll be blocked on `next(iterator)` and not be able + to check the channel status to stop iterating. This helper mitigates that + by waiting on the queue with a timeout and checking the RPC state before + yielding. + + Finally, it allows for retrying without swapping queues because if it does + pull an item off the queue when the RPC is inactive, it'll immediately put + it back and then exit. This is necessary because yielding the item in this + case will cause gRPC to discard it. In practice, this means that the order + of messages is not guaranteed. If such a thing is necessary it would be + easy to use a priority queue. + + Example:: + + requests = request_queue_generator(q) + call = stub.StreamingRequest(iter(requests)) + requests.call = call + + for response in call: + print(response) + q.put(...) + + Note that it is possible to accomplish this behavior without "spinning" + (using a queue timeout). One possible way would be to use more threads to + multiplex the grpc end event with the queue, another possible way is to + use selectors and a custom event/queue object. Both of these approaches + are significant from an engineering perspective for small benefit - the + CPU consumed by spinning is pretty minuscule. + + Args: + queue (queue.Queue): The request queue. + period (float): The number of seconds to wait for items from the queue + before checking if the RPC is cancelled. In practice, this + determines the maximum amount of time the request consumption + thread will live after the RPC is cancelled. + initial_request (Union[protobuf.Message, + Callable[None, protobuf.Message]]): The initial request to + yield. This is done independently of the request queue to allow fo + easily restarting streams that require some initial configuration + request. + """ + + def __init__(self, queue, period=1, initial_request=None): + self._queue = queue + self._period = period + self._initial_request = initial_request + self.call = None + + def _is_active(self): + # Note: there is a possibility that this starts *before* the call + # property is set. So we have to check if self.call is set before + # seeing if it's active. + if self.call is not None and not self.call.is_active(): + return False + else: + return True + + def __iter__(self): + if self._initial_request is not None: + if callable(self._initial_request): + yield self._initial_request() + else: + yield self._initial_request + + while True: + try: + item = self._queue.get(timeout=self._period) + except queue.Empty: + if not self._is_active(): + _LOGGER.debug( + "Empty queue and inactive call, exiting request " "generator." + ) + return + else: + # call is still active, keep waiting for queue items. + continue + + # The consumer explicitly sent "None", indicating that the request + # should end. + if item is None: + _LOGGER.debug("Cleanly exiting request generator.") + return + + if not self._is_active(): + # We have an item, but the call is closed. We should put the + # item back on the queue so that the next call can consume it. + self._queue.put(item) + _LOGGER.debug( + "Inactive call, replacing item on queue and exiting " + "request generator." + ) + return + + yield item + + +class _Throttle(object): + """A context manager limiting the total entries in a sliding time window. + + If more than ``access_limit`` attempts are made to enter the context manager + instance in the last ``time window`` interval, the exceeding requests block + until enough time elapses. + + The context manager instances are thread-safe and can be shared between + multiple threads. If multiple requests are blocked and waiting to enter, + the exact order in which they are allowed to proceed is not determined. + + Example:: + + max_three_per_second = _Throttle( + access_limit=3, time_window=datetime.timedelta(seconds=1) + ) + + for i in range(5): + with max_three_per_second as time_waited: + print("{}: Waited {} seconds to enter".format(i, time_waited)) + + Args: + access_limit (int): the maximum number of entries allowed in the time window + time_window (datetime.timedelta): the width of the sliding time window + """ + + def __init__(self, access_limit, time_window): + if access_limit < 1: + raise ValueError("access_limit argument must be positive") + + if time_window <= datetime.timedelta(0): + raise ValueError("time_window argument must be a positive timedelta") + + self._time_window = time_window + self._access_limit = access_limit + self._past_entries = collections.deque( + maxlen=access_limit + ) # least recent first + self._entry_lock = threading.Lock() + + def __enter__(self): + with self._entry_lock: + cutoff_time = datetime.datetime.now() - self._time_window + + # drop the entries that are too old, as they are no longer relevant + while self._past_entries and self._past_entries[0] < cutoff_time: + self._past_entries.popleft() + + if len(self._past_entries) < self._access_limit: + self._past_entries.append(datetime.datetime.now()) + return 0.0 # no waiting was needed + + to_wait = (self._past_entries[0] - cutoff_time).total_seconds() + time.sleep(to_wait) + + self._past_entries.append(datetime.datetime.now()) + return to_wait + + def __exit__(self, *_): + pass + + def __repr__(self): + return "{}(access_limit={}, time_window={})".format( + self.__class__.__name__, self._access_limit, repr(self._time_window) + ) + + +class BidiRpc(object): + """A helper for consuming a bi-directional streaming RPC. + + This maps gRPC's built-in interface which uses a request iterator and a + response iterator into a socket-like :func:`send` and :func:`recv`. This + is a more useful pattern for long-running or asymmetric streams (streams + where there is not a direct correlation between the requests and + responses). + + Example:: + + initial_request = example_pb2.StreamingRpcRequest( + setting='example') + rpc = BidiRpc( + stub.StreamingRpc, + initial_request=initial_request, + metadata=[('name', 'value')] + ) + + rpc.open() + + while rpc.is_active(): + print(rpc.recv()) + rpc.send(example_pb2.StreamingRpcRequest( + data='example')) + + This does *not* retry the stream on errors. See :class:`ResumableBidiRpc`. + + Args: + start_rpc (grpc.StreamStreamMultiCallable): The gRPC method used to + start the RPC. + initial_request (Union[protobuf.Message, + Callable[None, protobuf.Message]]): The initial request to + yield. This is useful if an initial request is needed to start the + stream. + metadata (Sequence[Tuple(str, str)]): RPC metadata to include in + the request. + """ + + def __init__(self, start_rpc, initial_request=None, metadata=None): + self._start_rpc = start_rpc + self._initial_request = initial_request + self._rpc_metadata = metadata + self._request_queue = queue.Queue() + self._request_generator = None + self._is_active = False + self._callbacks = [] + self.call = None + + def add_done_callback(self, callback): + """Adds a callback that will be called when the RPC terminates. + + This occurs when the RPC errors or is successfully terminated. + + Args: + callback (Callable[[grpc.Future], None]): The callback to execute. + It will be provided with the same gRPC future as the underlying + stream which will also be a :class:`grpc.Call`. + """ + self._callbacks.append(callback) + + def _on_call_done(self, future): + for callback in self._callbacks: + callback(future) + + def open(self): + """Opens the stream.""" + if self.is_active: + raise ValueError("Can not open an already open stream.") + + request_generator = _RequestQueueGenerator( + self._request_queue, initial_request=self._initial_request + ) + call = self._start_rpc(iter(request_generator), metadata=self._rpc_metadata) + + request_generator.call = call + + # TODO: api_core should expose the future interface for wrapped + # callables as well. + if hasattr(call, "_wrapped"): # pragma: NO COVER + call._wrapped.add_done_callback(self._on_call_done) + else: + call.add_done_callback(self._on_call_done) + + self._request_generator = request_generator + self.call = call + + def close(self): + """Closes the stream.""" + if self.call is None: + return + + self._request_queue.put(None) + self.call.cancel() + self._request_generator = None + # Don't set self.call to None. Keep it around so that send/recv can + # raise the error. + + def send(self, request): + """Queue a message to be sent on the stream. + + Send is non-blocking. + + If the underlying RPC has been closed, this will raise. + + Args: + request (protobuf.Message): The request to send. + """ + if self.call is None: + raise ValueError("Can not send() on an RPC that has never been open()ed.") + + # Don't use self.is_active(), as ResumableBidiRpc will overload it + # to mean something semantically different. + if self.call.is_active(): + self._request_queue.put(request) + else: + # calling next should cause the call to raise. + next(self.call) + + def recv(self): + """Wait for a message to be returned from the stream. + + Recv is blocking. + + If the underlying RPC has been closed, this will raise. + + Returns: + protobuf.Message: The received message. + """ + if self.call is None: + raise ValueError("Can not recv() on an RPC that has never been open()ed.") + + return next(self.call) + + @property + def is_active(self): + """bool: True if this stream is currently open and active.""" + return self.call is not None and self.call.is_active() + + @property + def pending_requests(self): + """int: Returns an estimate of the number of queued requests.""" + return self._request_queue.qsize() + + +def _never_terminate(future_or_error): + """By default, no errors cause BiDi termination.""" + return False + + +class ResumableBidiRpc(BidiRpc): + """A :class:`BidiRpc` that can automatically resume the stream on errors. + + It uses the ``should_recover`` arg to determine if it should re-establish + the stream on error. + + Example:: + + def should_recover(exc): + return ( + isinstance(exc, grpc.RpcError) and + exc.code() == grpc.StatusCode.UNVAILABLE) + + initial_request = example_pb2.StreamingRpcRequest( + setting='example') + + metadata = [('header_name', 'value')] + + rpc = ResumableBidiRpc( + stub.StreamingRpc, + should_recover=should_recover, + initial_request=initial_request, + metadata=metadata + ) + + rpc.open() + + while rpc.is_active(): + print(rpc.recv()) + rpc.send(example_pb2.StreamingRpcRequest( + data='example')) + + Args: + start_rpc (grpc.StreamStreamMultiCallable): The gRPC method used to + start the RPC. + initial_request (Union[protobuf.Message, + Callable[None, protobuf.Message]]): The initial request to + yield. This is useful if an initial request is needed to start the + stream. + should_recover (Callable[[Exception], bool]): A function that returns + True if the stream should be recovered. This will be called + whenever an error is encountered on the stream. + should_terminate (Callable[[Exception], bool]): A function that returns + True if the stream should be terminated. This will be called + whenever an error is encountered on the stream. + metadata Sequence[Tuple(str, str)]: RPC metadata to include in + the request. + throttle_reopen (bool): If ``True``, throttling will be applied to + stream reopen calls. Defaults to ``False``. + """ + + def __init__( + self, + start_rpc, + should_recover, + should_terminate=_never_terminate, + initial_request=None, + metadata=None, + throttle_reopen=False, + ): + super(ResumableBidiRpc, self).__init__(start_rpc, initial_request, metadata) + self._should_recover = should_recover + self._should_terminate = should_terminate + self._operational_lock = threading.RLock() + self._finalized = False + self._finalize_lock = threading.Lock() + + if throttle_reopen: + self._reopen_throttle = _Throttle( + access_limit=5, time_window=datetime.timedelta(seconds=10) + ) + else: + self._reopen_throttle = None + + def _finalize(self, result): + with self._finalize_lock: + if self._finalized: + return + + for callback in self._callbacks: + callback(result) + + self._finalized = True + + def _on_call_done(self, future): + # Unlike the base class, we only execute the callbacks on a terminal + # error, not for errors that we can recover from. Note that grpc's + # "future" here is also a grpc.RpcError. + with self._operational_lock: + if self._should_terminate(future): + self._finalize(future) + elif not self._should_recover(future): + self._finalize(future) + else: + _LOGGER.debug("Re-opening stream from gRPC callback.") + self._reopen() + + def _reopen(self): + with self._operational_lock: + # Another thread already managed to re-open this stream. + if self.call is not None and self.call.is_active(): + _LOGGER.debug("Stream was already re-established.") + return + + self.call = None + # Request generator should exit cleanly since the RPC its bound to + # has exited. + self._request_generator = None + + # Note: we do not currently do any sort of backoff here. The + # assumption is that re-establishing the stream under normal + # circumstances will happen in intervals greater than 60s. + # However, it is possible in a degenerative case that the server + # closes the stream rapidly which would lead to thrashing here, + # but hopefully in those cases the server would return a non- + # retryable error. + + try: + if self._reopen_throttle: + with self._reopen_throttle: + self.open() + else: + self.open() + # If re-opening or re-calling the method fails for any reason, + # consider it a terminal error and finalize the stream. + except Exception as exc: + _LOGGER.debug("Failed to re-open stream due to %s", exc) + self._finalize(exc) + raise + + _LOGGER.info("Re-established stream") + + def _recoverable(self, method, *args, **kwargs): + """Wraps a method to recover the stream and retry on error. + + If a retryable error occurs while making the call, then the stream will + be re-opened and the method will be retried. This happens indefinitely + so long as the error is a retryable one. If an error occurs while + re-opening the stream, then this method will raise immediately and + trigger finalization of this object. + + Args: + method (Callable[..., Any]): The method to call. + args: The args to pass to the method. + kwargs: The kwargs to pass to the method. + """ + while True: + try: + return method(*args, **kwargs) + + except Exception as exc: + with self._operational_lock: + _LOGGER.debug("Call to retryable %r caused %s.", method, exc) + + if self._should_terminate(exc): + self.close() + _LOGGER.debug("Terminating %r due to %s.", method, exc) + self._finalize(exc) + break + + if not self._should_recover(exc): + self.close() + _LOGGER.debug("Not retrying %r due to %s.", method, exc) + self._finalize(exc) + raise exc + + _LOGGER.debug("Re-opening stream from retryable %r.", method) + self._reopen() + + def _send(self, request): + # Grab a reference to the RPC call. Because another thread (notably + # the gRPC error thread) can modify self.call (by invoking reopen), + # we should ensure our reference can not change underneath us. + # If self.call is modified (such as replaced with a new RPC call) then + # this will use the "old" RPC, which should result in the same + # exception passed into gRPC's error handler being raised here, which + # will be handled by the usual error handling in retryable. + with self._operational_lock: + call = self.call + + if call is None: + raise ValueError("Can not send() on an RPC that has never been open()ed.") + + # Don't use self.is_active(), as ResumableBidiRpc will overload it + # to mean something semantically different. + if call.is_active(): + self._request_queue.put(request) + pass + else: + # calling next should cause the call to raise. + next(call) + + def send(self, request): + return self._recoverable(self._send, request) + + def _recv(self): + with self._operational_lock: + call = self.call + + if call is None: + raise ValueError("Can not recv() on an RPC that has never been open()ed.") + + return next(call) + + def recv(self): + return self._recoverable(self._recv) + + def close(self): + self._finalize(None) + super(ResumableBidiRpc, self).close() + + @property + def is_active(self): + """bool: True if this stream is currently open and active.""" + # Use the operational lock. It's entirely possible for something + # to check the active state *while* the RPC is being retried. + # Also, use finalized to track the actual terminal state here. + # This is because if the stream is re-established by the gRPC thread + # it's technically possible to check this between when gRPC marks the + # RPC as inactive and when gRPC executes our callback that re-opens + # the stream. + with self._operational_lock: + return self.call is not None and not self._finalized + + +class BackgroundConsumer(object): + """A bi-directional stream consumer that runs in a separate thread. + + This maps the consumption of a stream into a callback-based model. It also + provides :func:`pause` and :func:`resume` to allow for flow-control. + + Example:: + + def should_recover(exc): + return ( + isinstance(exc, grpc.RpcError) and + exc.code() == grpc.StatusCode.UNVAILABLE) + + initial_request = example_pb2.StreamingRpcRequest( + setting='example') + + rpc = ResumeableBidiRpc( + stub.StreamingRpc, + initial_request=initial_request, + should_recover=should_recover) + + def on_response(response): + print(response) + + consumer = BackgroundConsumer(rpc, on_response) + consumer.start() + + Note that error handling *must* be done by using the provided + ``bidi_rpc``'s ``add_done_callback``. This helper will automatically exit + whenever the RPC itself exits and will not provide any error details. + + Args: + bidi_rpc (BidiRpc): The RPC to consume. Should not have been + ``open()``ed yet. + on_response (Callable[[protobuf.Message], None]): The callback to + be called for every response on the stream. + """ + + def __init__(self, bidi_rpc, on_response): + self._bidi_rpc = bidi_rpc + self._on_response = on_response + self._paused = False + self._wake = threading.Condition() + self._thread = None + self._operational_lock = threading.Lock() + + def _on_call_done(self, future): + # Resume the thread if it's paused, this prevents blocking forever + # when the RPC has terminated. + self.resume() + + def _thread_main(self, ready): + try: + ready.set() + self._bidi_rpc.add_done_callback(self._on_call_done) + self._bidi_rpc.open() + + while self._bidi_rpc.is_active: + # Do not allow the paused status to change at all during this + # section. There is a condition where we could be resumed + # between checking if we are paused and calling wake.wait(), + # which means that we will miss the notification to wake up + # (oops!) and wait for a notification that will never come. + # Keeping the lock throughout avoids that. + # In the future, we could use `Condition.wait_for` if we drop + # Python 2.7. + with self._wake: + while self._paused: + _LOGGER.debug("paused, waiting for waking.") + self._wake.wait() + _LOGGER.debug("woken.") + + _LOGGER.debug("waiting for recv.") + response = self._bidi_rpc.recv() + _LOGGER.debug("recved response.") + self._on_response(response) + + except exceptions.GoogleAPICallError as exc: + _LOGGER.debug( + "%s caught error %s and will exit. Generally this is due to " + "the RPC itself being cancelled and the error will be " + "surfaced to the calling code.", + _BIDIRECTIONAL_CONSUMER_NAME, + exc, + exc_info=True, + ) + + except Exception as exc: + _LOGGER.exception( + "%s caught unexpected exception %s and will exit.", + _BIDIRECTIONAL_CONSUMER_NAME, + exc, + ) + + _LOGGER.info("%s exiting", _BIDIRECTIONAL_CONSUMER_NAME) + + def start(self): + """Start the background thread and begin consuming the thread.""" + with self._operational_lock: + ready = threading.Event() + thread = threading.Thread( + name=_BIDIRECTIONAL_CONSUMER_NAME, + target=self._thread_main, + args=(ready,), + ) + thread.daemon = True + thread.start() + # Other parts of the code rely on `thread.is_alive` which + # isn't sufficient to know if a thread is active, just that it may + # soon be active. This can cause races. Further protect + # against races by using a ready event and wait on it to be set. + ready.wait() + self._thread = thread + _LOGGER.debug("Started helper thread %s", thread.name) + + def stop(self): + """Stop consuming the stream and shutdown the background thread.""" + with self._operational_lock: + self._bidi_rpc.close() + + if self._thread is not None: + # Resume the thread to wake it up in case it is sleeping. + self.resume() + # The daemonized thread may itself block, so don't wait + # for it longer than a second. + self._thread.join(1.0) + if self._thread.is_alive(): # pragma: NO COVER + _LOGGER.warning("Background thread did not exit.") + + self._thread = None + + @property + def is_active(self): + """bool: True if the background thread is active.""" + return self._thread is not None and self._thread.is_alive() + + def pause(self): + """Pauses the response stream. + + This does *not* pause the request stream. + """ + with self._wake: + self._paused = True + + def resume(self): + """Resumes the response stream.""" + with self._wake: + self._paused = False + self._wake.notifyAll() + + @property + def is_paused(self): + """bool: True if the response stream is paused.""" + return self._paused diff --git a/venv/Lib/site-packages/google/api_core/client_info.py b/venv/Lib/site-packages/google/api_core/client_info.py new file mode 100644 index 000000000..6c04d5de5 --- /dev/null +++ b/venv/Lib/site-packages/google/api_core/client_info.py @@ -0,0 +1,98 @@ +# Copyright 2017 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +"""Helpers for providing client information. + +Client information is used to send information about the calling client, +such as the library and Python version, to API services. +""" + +import platform + +import pkg_resources + +from google.api_core import version as api_core_version + +_PY_VERSION = platform.python_version() +_API_CORE_VERSION = api_core_version.__version__ + +try: + _GRPC_VERSION = pkg_resources.get_distribution("grpcio").version +except pkg_resources.DistributionNotFound: # pragma: NO COVER + _GRPC_VERSION = None + + +class ClientInfo(object): + """Client information used to generate a user-agent for API calls. + + This user-agent information is sent along with API calls to allow the + receiving service to do analytics on which versions of Python and Google + libraries are being used. + + Args: + python_version (str): The Python interpreter version, for example, + ``'2.7.13'``. + grpc_version (Optional[str]): The gRPC library version. + api_core_version (str): The google-api-core library version. + gapic_version (Optional[str]): The sversion of gapic-generated client + library, if the library was generated by gapic. + client_library_version (Optional[str]): The version of the client + library, generally used if the client library was not generated + by gapic or if additional functionality was built on top of + a gapic client library. + user_agent (Optional[str]): Prefix to the user agent header. This is + used to supply information such as application name or partner tool. + Recommended format: ``application-or-tool-ID/major.minor.version``. + """ + + def __init__( + self, + python_version=_PY_VERSION, + grpc_version=_GRPC_VERSION, + api_core_version=_API_CORE_VERSION, + gapic_version=None, + client_library_version=None, + user_agent=None, + ): + self.python_version = python_version + self.grpc_version = grpc_version + self.api_core_version = api_core_version + self.gapic_version = gapic_version + self.client_library_version = client_library_version + self.user_agent = user_agent + + def to_user_agent(self): + """Returns the user-agent string for this client info.""" + + # Note: the order here is important as the internal metrics system + # expects these items to be in specific locations. + ua = "" + + if self.user_agent is not None: + ua += "{user_agent} " + + ua += "gl-python/{python_version} " + + if self.grpc_version is not None: + ua += "grpc/{grpc_version} " + + ua += "gax/{api_core_version} " + + if self.gapic_version is not None: + ua += "gapic/{gapic_version} " + + if self.client_library_version is not None: + ua += "gccl/{client_library_version} " + + return ua.format(**self.__dict__).strip() diff --git a/venv/Lib/site-packages/google/api_core/client_options.py b/venv/Lib/site-packages/google/api_core/client_options.py new file mode 100644 index 000000000..57000e95e --- /dev/null +++ b/venv/Lib/site-packages/google/api_core/client_options.py @@ -0,0 +1,116 @@ +# Copyright 2019 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +"""Client options class. + +Client options provide a consistent interface for user options to be defined +across clients. + +You can pass a client options object to a client. + +.. code-block:: python + + from google.api_core.client_options import ClientOptions + from google.cloud.vision_v1 import ImageAnnotatorClient + + def get_client_cert(): + # code to load client certificate and private key. + return client_cert_bytes, client_private_key_bytes + + options = ClientOptions(api_endpoint="foo.googleapis.com", + client_cert_source=get_client_cert) + + client = ImageAnnotatorClient(client_options=options) + +You can also pass a mapping object. + +.. code-block:: python + + from google.cloud.vision_v1 import ImageAnnotatorClient + + client = ImageAnnotatorClient( + client_options={ + "api_endpoint": "foo.googleapis.com", + "client_cert_source" : get_client_cert + }) + + +""" + + +class ClientOptions(object): + """Client Options used to set options on clients. + + Args: + api_endpoint (Optional[str]): The desired API endpoint, e.g., + compute.googleapis.com + client_cert_source (Optional[Callable[[], (bytes, bytes)]]): A callback + which returns client certificate bytes and private key bytes both in + PEM format. ``client_cert_source`` and ``client_encrypted_cert_source`` + are mutually exclusive. + client_encrypted_cert_source (Optional[Callable[[], (str, str, bytes)]]): + A callback which returns client certificate file path, encrypted + private key file path, and the passphrase bytes.``client_cert_source`` + and ``client_encrypted_cert_source`` are mutually exclusive. + quota_project_id (Optional[str]): A project name that a client's + quota belongs to. + credentials_file (Optional[str]): A path to a file storing credentials. + scopes (Optional[Sequence[str]]): OAuth access token override scopes. + + Raises: + ValueError: If both ``client_cert_source`` and ``client_encrypted_cert_source`` + are provided. + """ + + def __init__( + self, + api_endpoint=None, + client_cert_source=None, + client_encrypted_cert_source=None, + quota_project_id=None, + credentials_file=None, + scopes=None, + ): + if client_cert_source and client_encrypted_cert_source: + raise ValueError( + "client_cert_source and client_encrypted_cert_source are mutually exclusive" + ) + self.api_endpoint = api_endpoint + self.client_cert_source = client_cert_source + self.client_encrypted_cert_source = client_encrypted_cert_source + self.quota_project_id = quota_project_id + self.credentials_file = credentials_file + self.scopes = scopes + + def __repr__(self): + return "ClientOptions: " + repr(self.__dict__) + + +def from_dict(options): + """Construct a client options object from a mapping object. + + Args: + options (six.moves.collections_abc.Mapping): A mapping object with client options. + See the docstring for ClientOptions for details on valid arguments. + """ + + client_options = ClientOptions() + + for key, value in options.items(): + if hasattr(client_options, key): + setattr(client_options, key, value) + else: + raise ValueError("ClientOptions does not accept an option '" + key + "'") + + return client_options diff --git a/venv/Lib/site-packages/google/api_core/datetime_helpers.py b/venv/Lib/site-packages/google/api_core/datetime_helpers.py new file mode 100644 index 000000000..e52fb1dd3 --- /dev/null +++ b/venv/Lib/site-packages/google/api_core/datetime_helpers.py @@ -0,0 +1,296 @@ +# Copyright 2017 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +"""Helpers for :mod:`datetime`.""" + +import calendar +import datetime +import re + +import pytz + +from google.protobuf import timestamp_pb2 + + +_UTC_EPOCH = datetime.datetime.utcfromtimestamp(0).replace(tzinfo=pytz.utc) +_RFC3339_MICROS = "%Y-%m-%dT%H:%M:%S.%fZ" +_RFC3339_NO_FRACTION = "%Y-%m-%dT%H:%M:%S" +# datetime.strptime cannot handle nanosecond precision: parse w/ regex +_RFC3339_NANOS = re.compile( + r""" + (?P + \d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2} # YYYY-MM-DDTHH:MM:SS + ) + ( # Optional decimal part + \. # decimal point + (?P\d{1,9}) # nanoseconds, maybe truncated + )? + Z # Zulu +""", + re.VERBOSE, +) + + +def utcnow(): + """A :meth:`datetime.datetime.utcnow()` alias to allow mocking in tests.""" + return datetime.datetime.utcnow() + + +def to_milliseconds(value): + """Convert a zone-aware datetime to milliseconds since the unix epoch. + + Args: + value (datetime.datetime): The datetime to covert. + + Returns: + int: Milliseconds since the unix epoch. + """ + micros = to_microseconds(value) + return micros // 1000 + + +def from_microseconds(value): + """Convert timestamp in microseconds since the unix epoch to datetime. + + Args: + value (float): The timestamp to convert, in microseconds. + + Returns: + datetime.datetime: The datetime object equivalent to the timestamp in + UTC. + """ + return _UTC_EPOCH + datetime.timedelta(microseconds=value) + + +def to_microseconds(value): + """Convert a datetime to microseconds since the unix epoch. + + Args: + value (datetime.datetime): The datetime to covert. + + Returns: + int: Microseconds since the unix epoch. + """ + if not value.tzinfo: + value = value.replace(tzinfo=pytz.utc) + # Regardless of what timezone is on the value, convert it to UTC. + value = value.astimezone(pytz.utc) + # Convert the datetime to a microsecond timestamp. + return int(calendar.timegm(value.timetuple()) * 1e6) + value.microsecond + + +def from_iso8601_date(value): + """Convert a ISO8601 date string to a date. + + Args: + value (str): The ISO8601 date string. + + Returns: + datetime.date: A date equivalent to the date string. + """ + return datetime.datetime.strptime(value, "%Y-%m-%d").date() + + +def from_iso8601_time(value): + """Convert a zoneless ISO8601 time string to a time. + + Args: + value (str): The ISO8601 time string. + + Returns: + datetime.time: A time equivalent to the time string. + """ + return datetime.datetime.strptime(value, "%H:%M:%S").time() + + +def from_rfc3339(value): + """Convert an RFC3339-format timestamp to a native datetime. + + Supported formats include those without fractional seconds, or with + any fraction up to nanosecond precision. + + .. note:: + Python datetimes do not support nanosecond precision; this function + therefore truncates such values to microseconds. + + Args: + value (str): The RFC3339 string to convert. + + Returns: + datetime.datetime: The datetime object equivalent to the timestamp + in UTC. + + Raises: + ValueError: If the timestamp does not match the RFC3339 + regular expression. + """ + with_nanos = _RFC3339_NANOS.match(value) + + if with_nanos is None: + raise ValueError( + "Timestamp: {!r}, does not match pattern: {!r}".format( + value, _RFC3339_NANOS.pattern + ) + ) + + bare_seconds = datetime.datetime.strptime( + with_nanos.group("no_fraction"), _RFC3339_NO_FRACTION + ) + fraction = with_nanos.group("nanos") + + if fraction is None: + micros = 0 + else: + scale = 9 - len(fraction) + nanos = int(fraction) * (10 ** scale) + micros = nanos // 1000 + + return bare_seconds.replace(microsecond=micros, tzinfo=pytz.utc) + + +from_rfc3339_nanos = from_rfc3339 # from_rfc3339_nanos method was deprecated. + + +def to_rfc3339(value, ignore_zone=True): + """Convert a datetime to an RFC3339 timestamp string. + + Args: + value (datetime.datetime): + The datetime object to be converted to a string. + ignore_zone (bool): If True, then the timezone (if any) of the + datetime object is ignored and the datetime is treated as UTC. + + Returns: + str: The RFC3339 formated string representing the datetime. + """ + if not ignore_zone and value.tzinfo is not None: + # Convert to UTC and remove the time zone info. + value = value.replace(tzinfo=None) - value.utcoffset() + + return value.strftime(_RFC3339_MICROS) + + +class DatetimeWithNanoseconds(datetime.datetime): + """Track nanosecond in addition to normal datetime attrs. + + Nanosecond can be passed only as a keyword argument. + """ + + __slots__ = ("_nanosecond",) + + # pylint: disable=arguments-differ + def __new__(cls, *args, **kw): + nanos = kw.pop("nanosecond", 0) + if nanos > 0: + if "microsecond" in kw: + raise TypeError("Specify only one of 'microsecond' or 'nanosecond'") + kw["microsecond"] = nanos // 1000 + inst = datetime.datetime.__new__(cls, *args, **kw) + inst._nanosecond = nanos or 0 + return inst + + # pylint: disable=arguments-differ + + @property + def nanosecond(self): + """Read-only: nanosecond precision.""" + return self._nanosecond + + def rfc3339(self): + """Return an RFC3339-compliant timestamp. + + Returns: + (str): Timestamp string according to RFC3339 spec. + """ + if self._nanosecond == 0: + return to_rfc3339(self) + nanos = str(self._nanosecond).rjust(9, "0").rstrip("0") + return "{}.{}Z".format(self.strftime(_RFC3339_NO_FRACTION), nanos) + + @classmethod + def from_rfc3339(cls, stamp): + """Parse RFC3339-compliant timestamp, preserving nanoseconds. + + Args: + stamp (str): RFC3339 stamp, with up to nanosecond precision + + Returns: + :class:`DatetimeWithNanoseconds`: + an instance matching the timestamp string + + Raises: + ValueError: if `stamp` does not match the expected format + """ + with_nanos = _RFC3339_NANOS.match(stamp) + if with_nanos is None: + raise ValueError( + "Timestamp: {}, does not match pattern: {}".format( + stamp, _RFC3339_NANOS.pattern + ) + ) + bare = datetime.datetime.strptime( + with_nanos.group("no_fraction"), _RFC3339_NO_FRACTION + ) + fraction = with_nanos.group("nanos") + if fraction is None: + nanos = 0 + else: + scale = 9 - len(fraction) + nanos = int(fraction) * (10 ** scale) + return cls( + bare.year, + bare.month, + bare.day, + bare.hour, + bare.minute, + bare.second, + nanosecond=nanos, + tzinfo=pytz.UTC, + ) + + def timestamp_pb(self): + """Return a timestamp message. + + Returns: + (:class:`~google.protobuf.timestamp_pb2.Timestamp`): Timestamp message + """ + inst = self if self.tzinfo is not None else self.replace(tzinfo=pytz.UTC) + delta = inst - _UTC_EPOCH + seconds = int(delta.total_seconds()) + nanos = self._nanosecond or self.microsecond * 1000 + return timestamp_pb2.Timestamp(seconds=seconds, nanos=nanos) + + @classmethod + def from_timestamp_pb(cls, stamp): + """Parse RFC3339-compliant timestamp, preserving nanoseconds. + + Args: + stamp (:class:`~google.protobuf.timestamp_pb2.Timestamp`): timestamp message + + Returns: + :class:`DatetimeWithNanoseconds`: + an instance matching the timestamp message + """ + microseconds = int(stamp.seconds * 1e6) + bare = from_microseconds(microseconds) + return cls( + bare.year, + bare.month, + bare.day, + bare.hour, + bare.minute, + bare.second, + nanosecond=stamp.nanos, + tzinfo=pytz.UTC, + ) diff --git a/venv/Lib/site-packages/google/api_core/exceptions.py b/venv/Lib/site-packages/google/api_core/exceptions.py new file mode 100644 index 000000000..b9c46ca00 --- /dev/null +++ b/venv/Lib/site-packages/google/api_core/exceptions.py @@ -0,0 +1,474 @@ +# Copyright 2014 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +"""Exceptions raised by Google API core & clients. + +This module provides base classes for all errors raised by libraries based +on :mod:`google.api_core`, including both HTTP and gRPC clients. +""" + +from __future__ import absolute_import +from __future__ import unicode_literals + +import six +from six.moves import http_client + +try: + import grpc +except ImportError: # pragma: NO COVER + grpc = None + +# Lookup tables for mapping exceptions from HTTP and gRPC transports. +# Populated by _APICallErrorMeta +_HTTP_CODE_TO_EXCEPTION = {} +_GRPC_CODE_TO_EXCEPTION = {} + + +class GoogleAPIError(Exception): + """Base class for all exceptions raised by Google API Clients.""" + + pass + + +class DuplicateCredentialArgs(GoogleAPIError): + """Raised when multiple credentials are passed.""" + + pass + + +@six.python_2_unicode_compatible +class RetryError(GoogleAPIError): + """Raised when a function has exhausted all of its available retries. + + Args: + message (str): The exception message. + cause (Exception): The last exception raised when retring the + function. + """ + + def __init__(self, message, cause): + super(RetryError, self).__init__(message) + self.message = message + self._cause = cause + + @property + def cause(self): + """The last exception raised when retrying the function.""" + return self._cause + + def __str__(self): + return "{}, last exception: {}".format(self.message, self.cause) + + +class _GoogleAPICallErrorMeta(type): + """Metaclass for registering GoogleAPICallError subclasses.""" + + def __new__(mcs, name, bases, class_dict): + cls = type.__new__(mcs, name, bases, class_dict) + if cls.code is not None: + _HTTP_CODE_TO_EXCEPTION.setdefault(cls.code, cls) + if cls.grpc_status_code is not None: + _GRPC_CODE_TO_EXCEPTION.setdefault(cls.grpc_status_code, cls) + return cls + + +@six.python_2_unicode_compatible +@six.add_metaclass(_GoogleAPICallErrorMeta) +class GoogleAPICallError(GoogleAPIError): + """Base class for exceptions raised by calling API methods. + + Args: + message (str): The exception message. + errors (Sequence[Any]): An optional list of error details. + response (Union[requests.Request, grpc.Call]): The response or + gRPC call metadata. + """ + + code = None + """Optional[int]: The HTTP status code associated with this error. + + This may be ``None`` if the exception does not have a direct mapping + to an HTTP error. + + See http://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html + """ + + grpc_status_code = None + """Optional[grpc.StatusCode]: The gRPC status code associated with this + error. + + This may be ``None`` if the exception does not match up to a gRPC error. + """ + + def __init__(self, message, errors=(), response=None): + super(GoogleAPICallError, self).__init__(message) + self.message = message + """str: The exception message.""" + self._errors = errors + self._response = response + + def __str__(self): + return "{} {}".format(self.code, self.message) + + @property + def errors(self): + """Detailed error information. + + Returns: + Sequence[Any]: A list of additional error details. + """ + return list(self._errors) + + @property + def response(self): + """Optional[Union[requests.Request, grpc.Call]]: The response or + gRPC call metadata.""" + return self._response + + +class Redirection(GoogleAPICallError): + """Base class for for all redirection (HTTP 3xx) responses.""" + + +class MovedPermanently(Redirection): + """Exception mapping a ``301 Moved Permanently`` response.""" + + code = http_client.MOVED_PERMANENTLY + + +class NotModified(Redirection): + """Exception mapping a ``304 Not Modified`` response.""" + + code = http_client.NOT_MODIFIED + + +class TemporaryRedirect(Redirection): + """Exception mapping a ``307 Temporary Redirect`` response.""" + + code = http_client.TEMPORARY_REDIRECT + + +class ResumeIncomplete(Redirection): + """Exception mapping a ``308 Resume Incomplete`` response. + + .. note:: :attr:`http_client.PERMANENT_REDIRECT` is ``308``, but Google + APIs differ in their use of this status code. + """ + + code = 308 + + +class ClientError(GoogleAPICallError): + """Base class for all client error (HTTP 4xx) responses.""" + + +class BadRequest(ClientError): + """Exception mapping a ``400 Bad Request`` response.""" + + code = http_client.BAD_REQUEST + + +class InvalidArgument(BadRequest): + """Exception mapping a :attr:`grpc.StatusCode.INVALID_ARGUMENT` error.""" + + grpc_status_code = grpc.StatusCode.INVALID_ARGUMENT if grpc is not None else None + + +class FailedPrecondition(BadRequest): + """Exception mapping a :attr:`grpc.StatusCode.FAILED_PRECONDITION` + error.""" + + grpc_status_code = grpc.StatusCode.FAILED_PRECONDITION if grpc is not None else None + + +class OutOfRange(BadRequest): + """Exception mapping a :attr:`grpc.StatusCode.OUT_OF_RANGE` error.""" + + grpc_status_code = grpc.StatusCode.OUT_OF_RANGE if grpc is not None else None + + +class Unauthorized(ClientError): + """Exception mapping a ``401 Unauthorized`` response.""" + + code = http_client.UNAUTHORIZED + + +class Unauthenticated(Unauthorized): + """Exception mapping a :attr:`grpc.StatusCode.UNAUTHENTICATED` error.""" + + grpc_status_code = grpc.StatusCode.UNAUTHENTICATED if grpc is not None else None + + +class Forbidden(ClientError): + """Exception mapping a ``403 Forbidden`` response.""" + + code = http_client.FORBIDDEN + + +class PermissionDenied(Forbidden): + """Exception mapping a :attr:`grpc.StatusCode.PERMISSION_DENIED` error.""" + + grpc_status_code = grpc.StatusCode.PERMISSION_DENIED if grpc is not None else None + + +class NotFound(ClientError): + """Exception mapping a ``404 Not Found`` response or a + :attr:`grpc.StatusCode.NOT_FOUND` error.""" + + code = http_client.NOT_FOUND + grpc_status_code = grpc.StatusCode.NOT_FOUND if grpc is not None else None + + +class MethodNotAllowed(ClientError): + """Exception mapping a ``405 Method Not Allowed`` response.""" + + code = http_client.METHOD_NOT_ALLOWED + + +class Conflict(ClientError): + """Exception mapping a ``409 Conflict`` response.""" + + code = http_client.CONFLICT + + +class AlreadyExists(Conflict): + """Exception mapping a :attr:`grpc.StatusCode.ALREADY_EXISTS` error.""" + + grpc_status_code = grpc.StatusCode.ALREADY_EXISTS if grpc is not None else None + + +class Aborted(Conflict): + """Exception mapping a :attr:`grpc.StatusCode.ABORTED` error.""" + + grpc_status_code = grpc.StatusCode.ABORTED if grpc is not None else None + + +class LengthRequired(ClientError): + """Exception mapping a ``411 Length Required`` response.""" + + code = http_client.LENGTH_REQUIRED + + +class PreconditionFailed(ClientError): + """Exception mapping a ``412 Precondition Failed`` response.""" + + code = http_client.PRECONDITION_FAILED + + +class RequestRangeNotSatisfiable(ClientError): + """Exception mapping a ``416 Request Range Not Satisfiable`` response.""" + + code = http_client.REQUESTED_RANGE_NOT_SATISFIABLE + + +class TooManyRequests(ClientError): + """Exception mapping a ``429 Too Many Requests`` response.""" + + # http_client does not define a constant for this in Python 2. + code = 429 + + +class ResourceExhausted(TooManyRequests): + """Exception mapping a :attr:`grpc.StatusCode.RESOURCE_EXHAUSTED` error.""" + + grpc_status_code = grpc.StatusCode.RESOURCE_EXHAUSTED if grpc is not None else None + + +class Cancelled(ClientError): + """Exception mapping a :attr:`grpc.StatusCode.CANCELLED` error.""" + + # This maps to HTTP status code 499. See + # https://github.com/googleapis/googleapis/blob/master/google/rpc\ + # /code.proto + code = 499 + grpc_status_code = grpc.StatusCode.CANCELLED if grpc is not None else None + + +class ServerError(GoogleAPICallError): + """Base for 5xx responses.""" + + +class InternalServerError(ServerError): + """Exception mapping a ``500 Internal Server Error`` response. or a + :attr:`grpc.StatusCode.INTERNAL` error.""" + + code = http_client.INTERNAL_SERVER_ERROR + grpc_status_code = grpc.StatusCode.INTERNAL if grpc is not None else None + + +class Unknown(ServerError): + """Exception mapping a :attr:`grpc.StatusCode.UNKNOWN` error.""" + + grpc_status_code = grpc.StatusCode.UNKNOWN if grpc is not None else None + + +class DataLoss(ServerError): + """Exception mapping a :attr:`grpc.StatusCode.DATA_LOSS` error.""" + + grpc_status_code = grpc.StatusCode.DATA_LOSS if grpc is not None else None + + +class MethodNotImplemented(ServerError): + """Exception mapping a ``501 Not Implemented`` response or a + :attr:`grpc.StatusCode.UNIMPLEMENTED` error.""" + + code = http_client.NOT_IMPLEMENTED + grpc_status_code = grpc.StatusCode.UNIMPLEMENTED if grpc is not None else None + + +class BadGateway(ServerError): + """Exception mapping a ``502 Bad Gateway`` response.""" + + code = http_client.BAD_GATEWAY + + +class ServiceUnavailable(ServerError): + """Exception mapping a ``503 Service Unavailable`` response or a + :attr:`grpc.StatusCode.UNAVAILABLE` error.""" + + code = http_client.SERVICE_UNAVAILABLE + grpc_status_code = grpc.StatusCode.UNAVAILABLE if grpc is not None else None + + +class GatewayTimeout(ServerError): + """Exception mapping a ``504 Gateway Timeout`` response.""" + + code = http_client.GATEWAY_TIMEOUT + + +class DeadlineExceeded(GatewayTimeout): + """Exception mapping a :attr:`grpc.StatusCode.DEADLINE_EXCEEDED` error.""" + + grpc_status_code = grpc.StatusCode.DEADLINE_EXCEEDED if grpc is not None else None + + +def exception_class_for_http_status(status_code): + """Return the exception class for a specific HTTP status code. + + Args: + status_code (int): The HTTP status code. + + Returns: + :func:`type`: the appropriate subclass of :class:`GoogleAPICallError`. + """ + return _HTTP_CODE_TO_EXCEPTION.get(status_code, GoogleAPICallError) + + +def from_http_status(status_code, message, **kwargs): + """Create a :class:`GoogleAPICallError` from an HTTP status code. + + Args: + status_code (int): The HTTP status code. + message (str): The exception message. + kwargs: Additional arguments passed to the :class:`GoogleAPICallError` + constructor. + + Returns: + GoogleAPICallError: An instance of the appropriate subclass of + :class:`GoogleAPICallError`. + """ + error_class = exception_class_for_http_status(status_code) + error = error_class(message, **kwargs) + + if error.code is None: + error.code = status_code + + return error + + +def from_http_response(response): + """Create a :class:`GoogleAPICallError` from a :class:`requests.Response`. + + Args: + response (requests.Response): The HTTP response. + + Returns: + GoogleAPICallError: An instance of the appropriate subclass of + :class:`GoogleAPICallError`, with the message and errors populated + from the response. + """ + try: + payload = response.json() + except ValueError: + payload = {"error": {"message": response.text or "unknown error"}} + + error_message = payload.get("error", {}).get("message", "unknown error") + errors = payload.get("error", {}).get("errors", ()) + + message = "{method} {url}: {error}".format( + method=response.request.method, url=response.request.url, error=error_message + ) + + exception = from_http_status( + response.status_code, message, errors=errors, response=response + ) + return exception + + +def exception_class_for_grpc_status(status_code): + """Return the exception class for a specific :class:`grpc.StatusCode`. + + Args: + status_code (grpc.StatusCode): The gRPC status code. + + Returns: + :func:`type`: the appropriate subclass of :class:`GoogleAPICallError`. + """ + return _GRPC_CODE_TO_EXCEPTION.get(status_code, GoogleAPICallError) + + +def from_grpc_status(status_code, message, **kwargs): + """Create a :class:`GoogleAPICallError` from a :class:`grpc.StatusCode`. + + Args: + status_code (grpc.StatusCode): The gRPC status code. + message (str): The exception message. + kwargs: Additional arguments passed to the :class:`GoogleAPICallError` + constructor. + + Returns: + GoogleAPICallError: An instance of the appropriate subclass of + :class:`GoogleAPICallError`. + """ + error_class = exception_class_for_grpc_status(status_code) + error = error_class(message, **kwargs) + + if error.grpc_status_code is None: + error.grpc_status_code = status_code + + return error + + +def _is_informative_grpc_error(rpc_exc): + return hasattr(rpc_exc, "code") and hasattr(rpc_exc, "details") + + +def from_grpc_error(rpc_exc): + """Create a :class:`GoogleAPICallError` from a :class:`grpc.RpcError`. + + Args: + rpc_exc (grpc.RpcError): The gRPC error. + + Returns: + GoogleAPICallError: An instance of the appropriate subclass of + :class:`GoogleAPICallError`. + """ + # NOTE(lidiz) All gRPC error shares the parent class grpc.RpcError. + # However, check for grpc.RpcError breaks backward compatibility. + if isinstance(rpc_exc, grpc.Call) or _is_informative_grpc_error(rpc_exc): + return from_grpc_status( + rpc_exc.code(), rpc_exc.details(), errors=(rpc_exc,), response=rpc_exc + ) + else: + return GoogleAPICallError(str(rpc_exc), errors=(rpc_exc,), response=rpc_exc) diff --git a/venv/Lib/site-packages/google/api_core/future/__init__.py b/venv/Lib/site-packages/google/api_core/future/__init__.py new file mode 100644 index 000000000..3768b2c53 --- /dev/null +++ b/venv/Lib/site-packages/google/api_core/future/__init__.py @@ -0,0 +1,19 @@ +# Copyright 2017, Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +"""Futures for dealing with asynchronous operations.""" + +from google.api_core.future.base import Future + +__all__ = ["Future"] diff --git a/venv/Lib/site-packages/google/api_core/future/__pycache__/__init__.cpython-36.pyc b/venv/Lib/site-packages/google/api_core/future/__pycache__/__init__.cpython-36.pyc new file mode 100644 index 0000000000000000000000000000000000000000..e379d28298f5991c208017c0d62e4edc03103454 GIT binary patch literal 403 zcmYk1u};G<5Qd#J1%#;BVe#6bsR~^{2rDF!Ng zCgb7j?7j<~15ZnIRDr0C)pTt_MTPIJtQ=bGJjE8A2nMaszvD|XPBsVoq}z5qjkC=m z=L#j~#koe*HRPf-T%v=#+*RZY;bG_AT18!R{!ZL5rg!r5A+K2%9iA;j=qiR5lrt+} z3j8u)%Q|b;=$5Pp;pm)sXut<>bjBp;`PJ-#wGLlE2DXCA$Qr1y!AwF0WuT>yKpjZb z)@(Vb?_;=$R=Z-4X2HA(FlmKc3Jsp^5vG3#(>=nJa}(p7=WV|^x@k~#HQb&?1fNC8 H(v$QTXaRrQ literal 0 HcmV?d00001 diff --git a/venv/Lib/site-packages/google/api_core/future/__pycache__/_helpers.cpython-36.pyc b/venv/Lib/site-packages/google/api_core/future/__pycache__/_helpers.cpython-36.pyc new file mode 100644 index 0000000000000000000000000000000000000000..1a5a38c384224682af47c2a1d46ed630191833e8 GIT binary patch literal 919 zcmYjQ&2AGh5VpPBWD_Vwf&&MHd_qK`DJ{JeA;hIrNL7ny4-le+S2qi0Doh{#-Icc2blDmNcskkf@ zA4@Z`Jab(73ngK!i}ii?yc3qKIyNiPvT4g^IF##KZ$AK zRR4Y@@8YRNF!62#@1$N~0B%T)8T$@q60BQJsY+(%6f#JJx0_pz2?p{1G zdI*V&XE4Z;9B^)zZMy;V9q-EoxPe5cMdmUb-7YYBjG@IWKF%&;n>pB?$Ydl_uyLw& zn!}EqWFpZ9cIw^ki1og^lSTQYLM3X9qQ>&f?>It1*hAW&5j79cPN?_b@l<$6MMW2l zMcWgxVmI`Rgh#i0CM7P~d15uc!7oNmgw9zV`TG?ienLju^bs|W(bI{rjZiuf zqHM0mH~uFnTPe6>!~>>`gec?~gfN?UQ|+}%zSp;!plTkyA8R$u;lq}1=v^U;XcV-A GDEbd@ECJyF literal 0 HcmV?d00001 diff --git a/venv/Lib/site-packages/google/api_core/future/__pycache__/async_future.cpython-36.pyc b/venv/Lib/site-packages/google/api_core/future/__pycache__/async_future.cpython-36.pyc new file mode 100644 index 0000000000000000000000000000000000000000..6681615b164211cda3a9ddab4a89960534897980 GIT binary patch literal 5457 zcmdT|TXWmS6$U`?B8sA9$yRKqmu)+(&8baK(#&+MX**FB#nwzBYh?8jgc%UTE=f=j zz$^gCk6cWG%cK6`yIp6ut zS^R8erTVOQX@7HD)Bdi_9YwU?#~EGX!Zl0dIyZdX((zmHjgx{^(CL|pwrQEFT|~QR z6;-?Bmrlx7S=XLvyv!??8n1}TMZsDU=AbH;L}9Ruvxal!!nEq5I9L^RzVx+jtzkx$ zFJs2CC=YI7&N??2@><+`SjfI~n@oL<}&lAVbddjxVL)W(dtjT4lqb~pYi@Vi=Y#FsW zPMq{xVIVkOE?Qhf$8k7pC4qMq%H!5ZIFh~BieSJf7LvWwaz*dGr|-Pm8p?1W+_-fr z`kw2pHH0mTuS!JZ1A}gvlou8l1L1@;a@^i^b!i;~qOb5w&_@*z?5` zXXx2(D8-Yma>f&7Upu{N4o9*C?eCFQOkv33a_J8<@fk1Uqfq| z-{R{SRpT4{Hhx$59lnX*`d6B%S*w8I{mHU|VTv#3($KW+9BgsliIra?HWV-|+;Qr` zaB+yH-+i16IhNF{RvC^XKz8dy#Qm){hqKy@+979AKTLeiI${QMAf_{7QPNRp7Ex18 z&H$u@bwuAe^?<4~&-dY|p}>o{KVq(f`*!+E|EdRj%1SS(`>RJjKvmH zm~}_2FAzUo#JnID0f!D)2K)k-$12{sUf}p?fU&L&Pn05zg{PSJY8XZU_ahQHKX0}M zHHA5@D4tg?70&d4nblfl| zCWV0{)hNhqTjANZQyQz`u_S)|InJnpi>6ogl3v%xx938xnX9(2WFqLl(!44zwB#?5 zsjw(x{Lh`faF3%j2m$CcS%f)V6T;n$uQTuwNEQJ|Pf~2X0fY}KkJyKfj~o|5tUU7~gfPvfgOc0^QqW$WA_d=- zGL#KNZo)Fk_Oq-Z$>tN2_~(~oJO!facx~R?)ajCW>B!NgO#K}^IM)U+_8v-s=h_$g zxgOn(fwige-&MxX7n3qSS)7C-zi=iUs89V~j6eZfAPX9jl0upbQne?g6zo?uuOkr# z!Vaaac}SJ`}6Bq9D4JLPz7CEQH^5582|L!y^=_Y$OPHSBnZG|Sc0yW zkQ@Cz#9mdsoDF_~K9&DS=kdn8#@UGdDbOi!DB~;Z{}v6hKE<}I6WDQQ3<~G^h5m&x z+B`RKZ(g7`^^UInP79c+#l=DCxGE2HFoLed9AA4Q44?H|dCwoX*$WbUv{Lx&1jGsgrxAig_gBK6YQMb<=fOtF*2zlzU4@To?NE~wWE~F(`YQHXq=QY z$%JnV&xlYJbt*FJcE=ChV_?drEOP`wsshz2RoygdhM{ljYuAy!FlmaOJS!~3?m1}k zYaIwNo>PVZng+%NA->>zgP?yV(p;a0U!K>d?)bm({FEDSq};5iKQfZ9-Jzh z^S(+N{bw2zd{5PKZa2Y5Zm`hwr8!3COff^sexoe!z-cPk$PKit z<*YEL+ItrKlUokwX)Tn$KZDW4=muAr;71Vj2b^hDwOrM2>*MdvhA9 z5^;u@@!gkMen|~8V_7N!Db-G@5q29X_2y{5p_-CE#@IiSo`hh{7;nz&I1}+7Dfjj@ z<)%TSid3cF3JIS+&sC)0yK2gx;Mt#W<|^L1s^Uxvc4F!OnkrpD6JImtko+lsEVO<(?K6^tj#O^ z%`}oEeQumA?dBinRPArw^13tA+VN;8tkt71{MZRbhvM@DpRXcoV-H^^BtAsE#J3h9 zRf@H$zjpXDRBmU^$XZoKvJVb-KiJ#ZKH9aa%I>N>leE4`DFvTe%$(C^RaoU0>4&&q ctzvjYRyB=^QPb65VXbKD25K-<$Fst}0a}i=6951J literal 0 HcmV?d00001 diff --git a/venv/Lib/site-packages/google/api_core/future/__pycache__/base.cpython-36.pyc b/venv/Lib/site-packages/google/api_core/future/__pycache__/base.cpython-36.pyc new file mode 100644 index 0000000000000000000000000000000000000000..46b94fbbd4838e2f764d563ec2b08861bca76b59 GIT binary patch literal 1892 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 (3, 6): + from google.api_core.gapic_v1 import config_async # noqa: F401 + from google.api_core.gapic_v1 import method_async # noqa: F401 + __all__.append("config_async") + __all__.append("method_async") diff --git a/venv/Lib/site-packages/google/api_core/gapic_v1/__pycache__/__init__.cpython-36.pyc b/venv/Lib/site-packages/google/api_core/gapic_v1/__pycache__/__init__.cpython-36.pyc new file mode 100644 index 0000000000000000000000000000000000000000..dfae8addfd2994a68743a02e8c0bd3c593583e7d GIT binary patch literal 632 zcmZvXzpm3T6vmxDP1D}A7bFJ8tarGr3RglPgxFXR3tME#^0iMBx2YZ3PEi?H;APl& zo~%rL1tyMDu3*5CzxTm2tO2|+0&%v6!#p}MHNFt+_RN)`D(IKwl zC~$(DRLRIGa$2P$Pmm|o1UZvanaf$7RvD1pR6g2I>}TvO(2-a9=w2Yts#!!J+s)Yh5~;kM&q&ueh>5_kO&cl{7|%`l4cjIFxUkiR|{*|+fK U8uxckQ1ZBl#xE}7`AGBVH(4>NEC2ui literal 0 HcmV?d00001 diff --git a/venv/Lib/site-packages/google/api_core/gapic_v1/__pycache__/client_info.cpython-36.pyc b/venv/Lib/site-packages/google/api_core/gapic_v1/__pycache__/client_info.cpython-36.pyc new file mode 100644 index 0000000000000000000000000000000000000000..9a7bcd9708a6d99c5c6900892936453bebda87e2 GIT binary patch literal 2086 zcmah~TW{k;6m}fdJ4V2s>}XW~q2d(6x@ zX)4~@KeG=!@o)0V6Mumx&hglFx)fo_6K8zpobUV2#V$@$7wf**y!#uWf=dcy-UV67}-{an`=9|j4dA^bR-Ky%!HGOCQ0LU zyQ7O}LZ~j^C1RwgniC4APv>SLGcpA{5OEv5_D_f4SxrU6b+7XmkaV_Miw`Wm5b@o7 zeBF(ujJq@!UArHlS$(uZ-@bQ+?k+B#?e)Iu z?Y?++anZYf6RSLGLcGbbqa;H$<;U|zs^%9yaZBI6>9?4vOA(#xn2iNU%w zGKXS(;D=hu^`xnoHVR;4g|@Mtzt8$q@v*qZ20+4SNv!3BQ^r-#ww=%q0%CpR5nbdt z2(a9V^*o~RMnvVfBNZKxswMtlB{!t4C6JGd>(`o>>-hjn8zd4t!TW9RTglgUFoN-gA%+AfS9a3&6 zqlT8 zKcf8r-|ApQO)&{%#+edR9x$%2Ad^9niJ4Sa!JJb?UIv<{Tx0L=1`&^6e!aUFz=!0L zM<$qZ7)S}s$;^l@Z9rxzxpzMhuit@hQ35@>rFvN6+;i40Usboch z&l_R*YeAFh%~}{T8HJ&OFR&G=RLd@FxYvf|Dcl;r$?KnaZn<-^wW=_e{)d)Iuco39 zoI=~u&VO=n_`3h&@p(8n9v+^Yhr^TCZf)C873*}!?Z1b)b*~ji*}G=YYWIKcDh}lLJ-93byEXQ8rZunz{sG-AU+~&fkG<}x?>j?Lq9S8k^wL9VkeVUid1vOGXP$Xp z|73pNde*&lZa&boziVTc3FW77i(7bjnyq=dX9T*f%U{Db@^~Jw^j^;m4CDth^F?Up{EwRbXgxq zE1*_J>nkW!Gt(~GX-|Lm)YWB4)9@D;We0At43Ahl(_yxAV^kuKk&yNngpRiA?g&Ix8&Q_aaS&S6OiG!5ogVO>Y}Lv0&v)&L9mPShB4s4 z8f9)kRP7(;#*Xyn01%um@4JqgU|Q`mm}$&Y6W`j_p`7;)1P|8F#IXEH<27*g?VsIN zI}rfb_6daMv>k=actf_?ty7|-ro05+QN_7r+w1|oJ)`mHw5ywaK$8y{iG%uD4ptXEXstG+7(qHFYT(A7@1Unv2gz-Eh1 zFes!8u?z`dSWh@mN5woSq*9zPR5aTbrAk#r+`L6l{|q_WM9C9PA%8e>%myM=$Si z{|Nj~>mVN#z&K-=u|eI{3PGP+j}L3BIjs{ptnnuKtnca|j$(*Z-o?=VbDYIyA+*<{ zxT|0xS;6uN_9kJW%U%I79cAkXp^gbKlQg6!uxlnruHYFV4a6+p9Vq4;(a8Wk$FNgw^gkGH%tOT= z4PEZ9hLIZ0&D6vhOI}fr8EE>g^%y7XM!o)%XXp=|SG2beGI(@&)XR$5E`Jc*n3J24mw@_4 zwC9!I!E!e$^qT_B?OyibumG;7!Ba|Rpgo)QI-1!Fn3sjVL zQQP>;@Jhba*iy+Do{739|5hIR26orxin#zi6gPDQl z&Au}R=Aisod-L+w+5ibQG2SVocoLL~z-+sQH=Ki5?fD1HcnND9vE9GR9O z69b_ zF=b;WEeZcJoq?p1!`%~U2@+u`gE&&GqVk0u1RG?jnQW0f&e!03W7b~G0iFelSBL|g@NF2Wo2t+Y6@OZap1!Q!Eq|(hbba(@4eM_(R(UbaSiua|461;abQ zTlN_q-IXK3*#?-dlnB=Fj{>2U(=pRi=yq}9cJHf3^G?F^5An_JVK>emrT82D1L6G0NB{r; literal 0 HcmV?d00001 diff --git a/venv/Lib/site-packages/google/api_core/gapic_v1/__pycache__/method.cpython-36.pyc b/venv/Lib/site-packages/google/api_core/gapic_v1/__pycache__/method.cpython-36.pyc new file mode 100644 index 0000000000000000000000000000000000000000..c6b873558056b032539fbef1d7d7b70439a2a821 GIT binary patch literal 7464 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 + Retry.__call__() -> + Timeout.__call__() -> + wrap_errors() -> + get_topic() + + Note that if ``timeout`` or ``retry`` is ``None``, then they are not + applied to the function. For example, + ``wrapped_get_topic(timeout=None, retry=None)`` is more or less + equivalent to just calling ``get_topic`` but with error re-mapping. + + Args: + func (Callable[Any]): The function to wrap. It should accept an + optional ``timeout`` argument. If ``metadata`` is not ``None``, it + should accept a ``metadata`` argument. + default_retry (Optional[google.api_core.Retry]): The default retry + strategy. If ``None``, the method will not retry by default. + default_timeout (Optional[google.api_core.Timeout]): The default + timeout strategy. Can also be specified as an int or float. If + ``None``, the method will not have timeout specified by default. + client_info + (Optional[google.api_core.gapic_v1.client_info.ClientInfo]): + Client information used to create a user-agent string that's + passed as gRPC metadata to the method. If unspecified, then + a sane default will be used. If ``None``, then no user agent + metadata will be provided to the RPC method. + + Returns: + Callable: A new callable that takes optional ``retry`` and ``timeout`` + arguments and applies the common error mapping, retry, timeout, + and metadata behavior to the low-level RPC method. + """ + func = grpc_helpers.wrap_errors(func) + + if client_info is not None: + user_agent_metadata = [client_info.to_grpc_metadata()] + else: + user_agent_metadata = None + + return general_helpers.wraps(func)( + _GapicCallable( + func, default_retry, default_timeout, metadata=user_agent_metadata + ) + ) diff --git a/venv/Lib/site-packages/google/api_core/gapic_v1/method_async.py b/venv/Lib/site-packages/google/api_core/gapic_v1/method_async.py new file mode 100644 index 000000000..5210b2b7a --- /dev/null +++ b/venv/Lib/site-packages/google/api_core/gapic_v1/method_async.py @@ -0,0 +1,45 @@ +# Copyright 2020 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +"""AsyncIO helpers for wrapping gRPC methods with common functionality. + +This is used by gapic clients to provide common error mapping, retry, timeout, +pagination, and long-running operations to gRPC methods. +""" + +from google.api_core import general_helpers, grpc_helpers_async +from google.api_core.gapic_v1 import client_info +from google.api_core.gapic_v1.method import (_GapicCallable, # noqa: F401 + DEFAULT, + USE_DEFAULT_METADATA) + + +def wrap_method( + func, + default_retry=None, + default_timeout=None, + client_info=client_info.DEFAULT_CLIENT_INFO, +): + """Wrap an async RPC method with common behavior. + + Returns: + Callable: A new callable that takes optional ``retry`` and ``timeout`` + arguments and applies the common error mapping, retry, timeout, + and metadata behavior to the low-level RPC method. + """ + func = grpc_helpers_async.wrap_errors(func) + + metadata = [client_info.to_grpc_metadata()] if client_info is not None else None + + return general_helpers.wraps(func)(_GapicCallable( + func, default_retry, default_timeout, metadata=metadata)) diff --git a/venv/Lib/site-packages/google/api_core/gapic_v1/routing_header.py b/venv/Lib/site-packages/google/api_core/gapic_v1/routing_header.py new file mode 100644 index 000000000..3fb12a6f8 --- /dev/null +++ b/venv/Lib/site-packages/google/api_core/gapic_v1/routing_header.py @@ -0,0 +1,62 @@ +# Copyright 2017 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +"""Helpers for constructing routing headers. + +These headers are used by Google infrastructure to determine how to route +requests, especially for services that are regional. + +Generally, these headers are specified as gRPC metadata. +""" + +import sys + +from six.moves.urllib.parse import urlencode + +ROUTING_METADATA_KEY = "x-goog-request-params" + + +def to_routing_header(params): + """Returns a routing header string for the given request parameters. + + Args: + params (Mapping[str, Any]): A dictionary containing the request + parameters used for routing. + + Returns: + str: The routing header string. + """ + if sys.version_info[0] < 3: + # Python 2 does not have the "safe" parameter for urlencode. + return urlencode(params).replace("%2F", "/") + return urlencode( + params, + # Per Google API policy (go/api-url-encoding), / is not encoded. + safe="/", + ) + + +def to_grpc_metadata(params): + """Returns the gRPC metadata containing the routing headers for the given + request parameters. + + Args: + params (Mapping[str, Any]): A dictionary containing the request + parameters used for routing. + + Returns: + Tuple(str, str): The gRPC metadata containing the routing header key + and value. + """ + return (ROUTING_METADATA_KEY, to_routing_header(params)) diff --git a/venv/Lib/site-packages/google/api_core/general_helpers.py b/venv/Lib/site-packages/google/api_core/general_helpers.py new file mode 100644 index 000000000..d2d0c4402 --- /dev/null +++ b/venv/Lib/site-packages/google/api_core/general_helpers.py @@ -0,0 +1,33 @@ +# Copyright 2017 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +"""Helpers for general Python functionality.""" + +import functools + +import six + + +# functools.partial objects lack several attributes present on real function +# objects. In Python 2 wraps fails on this so use a restricted set instead. +_PARTIAL_VALID_ASSIGNMENTS = ("__doc__",) + + +def wraps(wrapped): + """A functools.wraps helper that handles partial objects on Python 2.""" + # https://github.com/google/pytype/issues/322 + if isinstance(wrapped, functools.partial): # pytype: disable=wrong-arg-types + return six.wraps(wrapped, assigned=_PARTIAL_VALID_ASSIGNMENTS) + else: + return six.wraps(wrapped) diff --git a/venv/Lib/site-packages/google/api_core/grpc_helpers.py b/venv/Lib/site-packages/google/api_core/grpc_helpers.py new file mode 100644 index 000000000..0ccbe1264 --- /dev/null +++ b/venv/Lib/site-packages/google/api_core/grpc_helpers.py @@ -0,0 +1,466 @@ +# Copyright 2017 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +"""Helpers for :mod:`grpc`.""" + +import collections + +import grpc +import six + +from google.api_core import exceptions +from google.api_core import general_helpers +import google.auth +import google.auth.credentials +import google.auth.transport.grpc +import google.auth.transport.requests + +try: + import grpc_gcp + + HAS_GRPC_GCP = True +except ImportError: + HAS_GRPC_GCP = False + +# The list of gRPC Callable interfaces that return iterators. +_STREAM_WRAP_CLASSES = (grpc.UnaryStreamMultiCallable, grpc.StreamStreamMultiCallable) + + +def _patch_callable_name(callable_): + """Fix-up gRPC callable attributes. + + gRPC callable lack the ``__name__`` attribute which causes + :func:`functools.wraps` to error. This adds the attribute if needed. + """ + if not hasattr(callable_, "__name__"): + callable_.__name__ = callable_.__class__.__name__ + + +def _wrap_unary_errors(callable_): + """Map errors for Unary-Unary and Stream-Unary gRPC callables.""" + _patch_callable_name(callable_) + + @six.wraps(callable_) + def error_remapped_callable(*args, **kwargs): + try: + return callable_(*args, **kwargs) + except grpc.RpcError as exc: + six.raise_from(exceptions.from_grpc_error(exc), exc) + + return error_remapped_callable + + +class _StreamingResponseIterator(grpc.Call): + def __init__(self, wrapped, prefetch_first_result=True): + self._wrapped = wrapped + + # This iterator is used in a retry context, and returned outside after init. + # gRPC will not throw an exception until the stream is consumed, so we need + # to retrieve the first result, in order to fail, in order to trigger a retry. + try: + if prefetch_first_result: + self._stored_first_result = six.next(self._wrapped) + except TypeError: + # It is possible the wrapped method isn't an iterable (a grpc.Call + # for instance). If this happens don't store the first result. + pass + except StopIteration: + # ignore stop iteration at this time. This should be handled outside of retry. + pass + + def __iter__(self): + """This iterator is also an iterable that returns itself.""" + return self + + def next(self): + """Get the next response from the stream. + + Returns: + protobuf.Message: A single response from the stream. + """ + try: + if hasattr(self, "_stored_first_result"): + result = self._stored_first_result + del self._stored_first_result + return result + return six.next(self._wrapped) + except grpc.RpcError as exc: + # If the stream has already returned data, we cannot recover here. + six.raise_from(exceptions.from_grpc_error(exc), exc) + + # Alias needed for Python 2/3 support. + __next__ = next + + # grpc.Call & grpc.RpcContext interface + + def add_callback(self, callback): + return self._wrapped.add_callback(callback) + + def cancel(self): + return self._wrapped.cancel() + + def code(self): + return self._wrapped.code() + + def details(self): + return self._wrapped.details() + + def initial_metadata(self): + return self._wrapped.initial_metadata() + + def is_active(self): + return self._wrapped.is_active() + + def time_remaining(self): + return self._wrapped.time_remaining() + + def trailing_metadata(self): + return self._wrapped.trailing_metadata() + + +def _wrap_stream_errors(callable_): + """Wrap errors for Unary-Stream and Stream-Stream gRPC callables. + + The callables that return iterators require a bit more logic to re-map + errors when iterating. This wraps both the initial invocation and the + iterator of the return value to re-map errors. + """ + _patch_callable_name(callable_) + + @general_helpers.wraps(callable_) + def error_remapped_callable(*args, **kwargs): + try: + result = callable_(*args, **kwargs) + # Auto-fetching the first result causes PubSub client's streaming pull + # to hang when re-opening the stream, thus we need examine the hacky + # hidden flag to see if pre-fetching is disabled. + # https://github.com/googleapis/python-pubsub/issues/93#issuecomment-630762257 + prefetch_first = getattr(callable_, "_prefetch_first_result_", True) + return _StreamingResponseIterator(result, prefetch_first_result=prefetch_first) + except grpc.RpcError as exc: + six.raise_from(exceptions.from_grpc_error(exc), exc) + + return error_remapped_callable + + +def wrap_errors(callable_): + """Wrap a gRPC callable and map :class:`grpc.RpcErrors` to friendly error + classes. + + Errors raised by the gRPC callable are mapped to the appropriate + :class:`google.api_core.exceptions.GoogleAPICallError` subclasses. + The original `grpc.RpcError` (which is usually also a `grpc.Call`) is + available from the ``response`` property on the mapped exception. This + is useful for extracting metadata from the original error. + + Args: + callable_ (Callable): A gRPC callable. + + Returns: + Callable: The wrapped gRPC callable. + """ + if isinstance(callable_, _STREAM_WRAP_CLASSES): + return _wrap_stream_errors(callable_) + else: + return _wrap_unary_errors(callable_) + + +def _create_composite_credentials( + credentials=None, + credentials_file=None, + scopes=None, + ssl_credentials=None, + quota_project_id=None): + """Create the composite credentials for secure channels. + + Args: + credentials (google.auth.credentials.Credentials): The credentials. If + not specified, then this function will attempt to ascertain the + credentials from the environment using :func:`google.auth.default`. + credentials_file (str): A file with credentials that can be loaded with + :func:`google.auth.load_credentials_from_file`. This argument is + mutually exclusive with credentials. + scopes (Sequence[str]): A optional list of scopes needed for this + service. These are only used when credentials are not specified and + are passed to :func:`google.auth.default`. + ssl_credentials (grpc.ChannelCredentials): Optional SSL channel + credentials. This can be used to specify different certificates. + quota_project_id (str): An optional project to use for billing and quota. + + Returns: + grpc.ChannelCredentials: The composed channel credentials object. + + Raises: + google.api_core.DuplicateCredentialArgs: If both a credentials object and credentials_file are passed. + """ + if credentials and credentials_file: + raise exceptions.DuplicateCredentialArgs( + "'credentials' and 'credentials_file' are mutually exclusive." + ) + + if credentials_file: + credentials, _ = google.auth.load_credentials_from_file(credentials_file, scopes=scopes) + elif credentials: + credentials = google.auth.credentials.with_scopes_if_required(credentials, scopes) + else: + credentials, _ = google.auth.default(scopes=scopes) + + if quota_project_id and isinstance(credentials, google.auth.credentials.CredentialsWithQuotaProject): + credentials = credentials.with_quota_project(quota_project_id) + + request = google.auth.transport.requests.Request() + + # Create the metadata plugin for inserting the authorization header. + metadata_plugin = google.auth.transport.grpc.AuthMetadataPlugin( + credentials, request + ) + + # Create a set of grpc.CallCredentials using the metadata plugin. + google_auth_credentials = grpc.metadata_call_credentials(metadata_plugin) + + if ssl_credentials is None: + ssl_credentials = grpc.ssl_channel_credentials() + + # Combine the ssl credentials and the authorization credentials. + return grpc.composite_channel_credentials( + ssl_credentials, google_auth_credentials + ) + + +def create_channel( + target, + credentials=None, + scopes=None, + ssl_credentials=None, + credentials_file=None, + quota_project_id=None, + **kwargs): + """Create a secure channel with credentials. + + Args: + target (str): The target service address in the format 'hostname:port'. + credentials (google.auth.credentials.Credentials): The credentials. If + not specified, then this function will attempt to ascertain the + credentials from the environment using :func:`google.auth.default`. + scopes (Sequence[str]): A optional list of scopes needed for this + service. These are only used when credentials are not specified and + are passed to :func:`google.auth.default`. + ssl_credentials (grpc.ChannelCredentials): Optional SSL channel + credentials. This can be used to specify different certificates. + credentials_file (str): A file with credentials that can be loaded with + :func:`google.auth.load_credentials_from_file`. This argument is + mutually exclusive with credentials. + quota_project_id (str): An optional project to use for billing and quota. + kwargs: Additional key-word args passed to + :func:`grpc_gcp.secure_channel` or :func:`grpc.secure_channel`. + + Returns: + grpc.Channel: The created channel. + + Raises: + google.api_core.DuplicateCredentialArgs: If both a credentials object and credentials_file are passed. + """ + + composite_credentials = _create_composite_credentials( + credentials=credentials, + credentials_file=credentials_file, + scopes=scopes, + ssl_credentials=ssl_credentials, + quota_project_id=quota_project_id, + ) + + if HAS_GRPC_GCP: + # If grpc_gcp module is available use grpc_gcp.secure_channel, + # otherwise, use grpc.secure_channel to create grpc channel. + return grpc_gcp.secure_channel(target, composite_credentials, **kwargs) + else: + return grpc.secure_channel(target, composite_credentials, **kwargs) + + +_MethodCall = collections.namedtuple( + "_MethodCall", ("request", "timeout", "metadata", "credentials") +) + +_ChannelRequest = collections.namedtuple("_ChannelRequest", ("method", "request")) + + +class _CallableStub(object): + """Stub for the grpc.*MultiCallable interfaces.""" + + def __init__(self, method, channel): + self._method = method + self._channel = channel + self.response = None + """Union[protobuf.Message, Callable[protobuf.Message], exception]: + The response to give when invoking this callable. If this is a + callable, it will be invoked with the request protobuf. If it's an + exception, the exception will be raised when this is invoked. + """ + self.responses = None + """Iterator[ + Union[protobuf.Message, Callable[protobuf.Message], exception]]: + An iterator of responses. If specified, self.response will be populated + on each invocation by calling ``next(self.responses)``.""" + self.requests = [] + """List[protobuf.Message]: All requests sent to this callable.""" + self.calls = [] + """List[Tuple]: All invocations of this callable. Each tuple is the + request, timeout, metadata, and credentials.""" + + def __call__(self, request, timeout=None, metadata=None, credentials=None): + self._channel.requests.append(_ChannelRequest(self._method, request)) + self.calls.append(_MethodCall(request, timeout, metadata, credentials)) + self.requests.append(request) + + response = self.response + if self.responses is not None: + if response is None: + response = next(self.responses) + else: + raise ValueError( + "{method}.response and {method}.responses are mutually " + "exclusive.".format(method=self._method) + ) + + if callable(response): + return response(request) + + if isinstance(response, Exception): + raise response + + if response is not None: + return response + + raise ValueError('Method stub for "{}" has no response.'.format(self._method)) + + +def _simplify_method_name(method): + """Simplifies a gRPC method name. + + When gRPC invokes the channel to create a callable, it gives a full + method name like "/google.pubsub.v1.Publisher/CreateTopic". This + returns just the name of the method, in this case "CreateTopic". + + Args: + method (str): The name of the method. + + Returns: + str: The simplified name of the method. + """ + return method.rsplit("/", 1).pop() + + +class ChannelStub(grpc.Channel): + """A testing stub for the grpc.Channel interface. + + This can be used to test any client that eventually uses a gRPC channel + to communicate. By passing in a channel stub, you can configure which + responses are returned and track which requests are made. + + For example: + + .. code-block:: python + + channel_stub = grpc_helpers.ChannelStub() + client = FooClient(channel=channel_stub) + + channel_stub.GetFoo.response = foo_pb2.Foo(name='bar') + + foo = client.get_foo(labels=['baz']) + + assert foo.name == 'bar' + assert channel_stub.GetFoo.requests[0].labels = ['baz'] + + Each method on the stub can be accessed and configured on the channel. + Here's some examples of various configurations: + + .. code-block:: python + + # Return a basic response: + + channel_stub.GetFoo.response = foo_pb2.Foo(name='bar') + assert client.get_foo().name == 'bar' + + # Raise an exception: + channel_stub.GetFoo.response = NotFound('...') + + with pytest.raises(NotFound): + client.get_foo() + + # Use a sequence of responses: + channel_stub.GetFoo.responses = iter([ + foo_pb2.Foo(name='bar'), + foo_pb2.Foo(name='baz'), + ]) + + assert client.get_foo().name == 'bar' + assert client.get_foo().name == 'baz' + + # Use a callable + + def on_get_foo(request): + return foo_pb2.Foo(name='bar' + request.id) + + channel_stub.GetFoo.response = on_get_foo + + assert client.get_foo(id='123').name == 'bar123' + """ + + def __init__(self, responses=[]): + self.requests = [] + """Sequence[Tuple[str, protobuf.Message]]: A list of all requests made + on this channel in order. The tuple is of method name, request + message.""" + self._method_stubs = {} + + def _stub_for_method(self, method): + method = _simplify_method_name(method) + self._method_stubs[method] = _CallableStub(method, self) + return self._method_stubs[method] + + def __getattr__(self, key): + try: + return self._method_stubs[key] + except KeyError: + raise AttributeError + + def unary_unary(self, method, request_serializer=None, response_deserializer=None): + """grpc.Channel.unary_unary implementation.""" + return self._stub_for_method(method) + + def unary_stream(self, method, request_serializer=None, response_deserializer=None): + """grpc.Channel.unary_stream implementation.""" + return self._stub_for_method(method) + + def stream_unary(self, method, request_serializer=None, response_deserializer=None): + """grpc.Channel.stream_unary implementation.""" + return self._stub_for_method(method) + + def stream_stream( + self, method, request_serializer=None, response_deserializer=None + ): + """grpc.Channel.stream_stream implementation.""" + return self._stub_for_method(method) + + def subscribe(self, callback, try_to_connect=False): + """grpc.Channel.subscribe implementation.""" + pass + + def unsubscribe(self, callback): + """grpc.Channel.unsubscribe implementation.""" + pass + + def close(self): + """grpc.Channel.close implementation.""" + pass diff --git a/venv/Lib/site-packages/google/api_core/grpc_helpers_async.py b/venv/Lib/site-packages/google/api_core/grpc_helpers_async.py new file mode 100644 index 000000000..9a994e9f8 --- /dev/null +++ b/venv/Lib/site-packages/google/api_core/grpc_helpers_async.py @@ -0,0 +1,289 @@ +# Copyright 2020 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +"""AsyncIO helpers for :mod:`grpc` supporting 3.6+. + +Please combine more detailed docstring in grpc_helpers.py to use following +functions. This module is implementing the same surface with AsyncIO semantics. +""" + +import asyncio +import functools + +import grpc +from grpc.experimental import aio + +from google.api_core import exceptions, grpc_helpers + + +# TODO(lidiz) Support gRPC GCP wrapper +HAS_GRPC_GCP = False + +# NOTE(lidiz) Alternatively, we can hack "__getattribute__" to perform +# automatic patching for us. But that means the overhead of creating an +# extra Python function spreads to every single send and receive. + + +class _WrappedCall(aio.Call): + + def __init__(self): + self._call = None + + def with_call(self, call): + """Supplies the call object separately to keep __init__ clean.""" + self._call = call + return self + + async def initial_metadata(self): + return await self._call.initial_metadata() + + async def trailing_metadata(self): + return await self._call.trailing_metadata() + + async def code(self): + return await self._call.code() + + async def details(self): + return await self._call.details() + + def cancelled(self): + return self._call.cancelled() + + def done(self): + return self._call.done() + + def time_remaining(self): + return self._call.time_remaining() + + def cancel(self): + return self._call.cancel() + + def add_done_callback(self, callback): + self._call.add_done_callback(callback) + + async def wait_for_connection(self): + try: + await self._call.wait_for_connection() + except grpc.RpcError as rpc_error: + raise exceptions.from_grpc_error(rpc_error) from rpc_error + + +class _WrappedUnaryResponseMixin(_WrappedCall): + + def __await__(self): + try: + response = yield from self._call.__await__() + return response + except grpc.RpcError as rpc_error: + raise exceptions.from_grpc_error(rpc_error) from rpc_error + + +class _WrappedStreamResponseMixin(_WrappedCall): + + def __init__(self): + self._wrapped_async_generator = None + + async def read(self): + try: + return await self._call.read() + except grpc.RpcError as rpc_error: + raise exceptions.from_grpc_error(rpc_error) from rpc_error + + async def _wrapped_aiter(self): + try: + # NOTE(lidiz) coverage doesn't understand the exception raised from + # __anext__ method. It is covered by test case: + # test_wrap_stream_errors_aiter_non_rpc_error + async for response in self._call: # pragma: no branch + yield response + except grpc.RpcError as rpc_error: + raise exceptions.from_grpc_error(rpc_error) from rpc_error + + def __aiter__(self): + if not self._wrapped_async_generator: + self._wrapped_async_generator = self._wrapped_aiter() + return self._wrapped_async_generator + + +class _WrappedStreamRequestMixin(_WrappedCall): + + async def write(self, request): + try: + await self._call.write(request) + except grpc.RpcError as rpc_error: + raise exceptions.from_grpc_error(rpc_error) from rpc_error + + async def done_writing(self): + try: + await self._call.done_writing() + except grpc.RpcError as rpc_error: + raise exceptions.from_grpc_error(rpc_error) from rpc_error + + +# NOTE(lidiz) Implementing each individual class separately, so we don't +# expose any API that should not be seen. E.g., __aiter__ in unary-unary +# RPC, or __await__ in stream-stream RPC. +class _WrappedUnaryUnaryCall(_WrappedUnaryResponseMixin, aio.UnaryUnaryCall): + """Wrapped UnaryUnaryCall to map exceptions.""" + + +class _WrappedUnaryStreamCall(_WrappedStreamResponseMixin, aio.UnaryStreamCall): + """Wrapped UnaryStreamCall to map exceptions.""" + + +class _WrappedStreamUnaryCall(_WrappedUnaryResponseMixin, _WrappedStreamRequestMixin, aio.StreamUnaryCall): + """Wrapped StreamUnaryCall to map exceptions.""" + + +class _WrappedStreamStreamCall(_WrappedStreamRequestMixin, _WrappedStreamResponseMixin, aio.StreamStreamCall): + """Wrapped StreamStreamCall to map exceptions.""" + + +def _wrap_unary_errors(callable_): + """Map errors for Unary-Unary async callables.""" + grpc_helpers._patch_callable_name(callable_) + + @functools.wraps(callable_) + def error_remapped_callable(*args, **kwargs): + call = callable_(*args, **kwargs) + return _WrappedUnaryUnaryCall().with_call(call) + + return error_remapped_callable + + +def _wrap_stream_errors(callable_): + """Map errors for streaming RPC async callables.""" + grpc_helpers._patch_callable_name(callable_) + + @functools.wraps(callable_) + async def error_remapped_callable(*args, **kwargs): + call = callable_(*args, **kwargs) + + if isinstance(call, aio.UnaryStreamCall): + call = _WrappedUnaryStreamCall().with_call(call) + elif isinstance(call, aio.StreamUnaryCall): + call = _WrappedStreamUnaryCall().with_call(call) + elif isinstance(call, aio.StreamStreamCall): + call = _WrappedStreamStreamCall().with_call(call) + else: + raise TypeError('Unexpected type of call %s' % type(call)) + + await call.wait_for_connection() + return call + + return error_remapped_callable + + +def wrap_errors(callable_): + """Wrap a gRPC async callable and map :class:`grpc.RpcErrors` to + friendly error classes. + + Errors raised by the gRPC callable are mapped to the appropriate + :class:`google.api_core.exceptions.GoogleAPICallError` subclasses. The + original `grpc.RpcError` (which is usually also a `grpc.Call`) is + available from the ``response`` property on the mapped exception. This + is useful for extracting metadata from the original error. + + Args: + callable_ (Callable): A gRPC callable. + + Returns: Callable: The wrapped gRPC callable. + """ + if isinstance(callable_, aio.UnaryUnaryMultiCallable): + return _wrap_unary_errors(callable_) + else: + return _wrap_stream_errors(callable_) + + +def create_channel( + target, + credentials=None, + scopes=None, + ssl_credentials=None, + credentials_file=None, + quota_project_id=None, + **kwargs): + """Create an AsyncIO secure channel with credentials. + + Args: + target (str): The target service address in the format 'hostname:port'. + credentials (google.auth.credentials.Credentials): The credentials. If + not specified, then this function will attempt to ascertain the + credentials from the environment using :func:`google.auth.default`. + scopes (Sequence[str]): A optional list of scopes needed for this + service. These are only used when credentials are not specified and + are passed to :func:`google.auth.default`. + ssl_credentials (grpc.ChannelCredentials): Optional SSL channel + credentials. This can be used to specify different certificates. + credentials_file (str): A file with credentials that can be loaded with + :func:`google.auth.load_credentials_from_file`. This argument is + mutually exclusive with credentials. + quota_project_id (str): An optional project to use for billing and quota. + kwargs: Additional key-word args passed to :func:`aio.secure_channel`. + + Returns: + aio.Channel: The created channel. + + Raises: + google.api_core.DuplicateCredentialArgs: If both a credentials object and credentials_file are passed. + """ + + composite_credentials = grpc_helpers._create_composite_credentials( + credentials=credentials, + credentials_file=credentials_file, + scopes=scopes, + ssl_credentials=ssl_credentials, + quota_project_id=quota_project_id, + ) + + return aio.secure_channel(target, composite_credentials, **kwargs) + + +class FakeUnaryUnaryCall(_WrappedUnaryUnaryCall): + """Fake implementation for unary-unary RPCs. + + It is a dummy object for response message. Supply the intended response + upon the initialization, and the coroutine will return the exact response + message. + """ + + def __init__(self, response=object()): + self.response = response + self._future = asyncio.get_event_loop().create_future() + self._future.set_result(self.response) + + def __await__(self): + response = yield from self._future.__await__() + return response + + +class FakeStreamUnaryCall(_WrappedStreamUnaryCall): + """Fake implementation for stream-unary RPCs. + + It is a dummy object for response message. Supply the intended response + upon the initialization, and the coroutine will return the exact response + message. + """ + + def __init__(self, response=object()): + self.response = response + self._future = asyncio.get_event_loop().create_future() + self._future.set_result(self.response) + + def __await__(self): + response = yield from self._future.__await__() + return response + + async def wait_for_connection(self): + pass diff --git a/venv/Lib/site-packages/google/api_core/iam.py b/venv/Lib/site-packages/google/api_core/iam.py new file mode 100644 index 000000000..f13093603 --- /dev/null +++ b/venv/Lib/site-packages/google/api_core/iam.py @@ -0,0 +1,460 @@ +# Copyright 2017 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +"""Non-API-specific IAM policy definitions + +For allowed roles / permissions, see: +https://cloud.google.com/iam/docs/understanding-roles + +Example usage: + +.. code-block:: python + + # ``get_iam_policy`` returns a :class:'~google.api_core.iam.Policy`. + policy = resource.get_iam_policy(requested_policy_version=3) + + phred = "user:phred@example.com" + admin_group = "group:admins@groups.example.com" + account = "serviceAccount:account-1234@accounts.example.com" + + policy.version = 3 + policy.bindings = [ + { + "role": "roles/owner", + "members": {phred, admin_group, account} + }, + { + "role": "roles/editor", + "members": {"allAuthenticatedUsers"} + }, + { + "role": "roles/viewer", + "members": {"allUsers"} + "condition": { + "title": "request_time", + "description": "Requests made before 2021-01-01T00:00:00Z", + "expression": "request.time < timestamp(\"2021-01-01T00:00:00Z\")" + } + } + ] + + resource.set_iam_policy(policy) +""" + +import collections +import operator +import warnings + +try: + from collections import abc as collections_abc +except ImportError: # Python 2.7 + import collections as collections_abc + +# Generic IAM roles + +OWNER_ROLE = "roles/owner" +"""Generic role implying all rights to an object.""" + +EDITOR_ROLE = "roles/editor" +"""Generic role implying rights to modify an object.""" + +VIEWER_ROLE = "roles/viewer" +"""Generic role implying rights to access an object.""" + +_ASSIGNMENT_DEPRECATED_MSG = """\ +Assigning to '{}' is deprecated. Use the `policy.bindings` property to modify bindings instead.""" + +_FACTORY_DEPRECATED_MSG = """\ +Factory method {0} is deprecated. Replace with '{0}'.""" + +_DICT_ACCESS_MSG = """\ +Dict access is not supported on policies with version > 1 or with conditional bindings.""" + + +class InvalidOperationException(Exception): + """Raised when trying to use Policy class as a dict.""" + + pass + + +class Policy(collections_abc.MutableMapping): + """IAM Policy + + Args: + etag (Optional[str]): ETag used to identify a unique of the policy + version (Optional[int]): The syntax schema version of the policy. + + Note: + Using conditions in bindings requires the policy's version to be set + to `3` or greater, depending on the versions that are currently supported. + + Accessing the policy using dict operations will raise InvalidOperationException + when the policy's version is set to 3. + + Use the policy.bindings getter/setter to retrieve and modify the policy's bindings. + + See: + IAM Policy https://cloud.google.com/iam/reference/rest/v1/Policy + Policy versions https://cloud.google.com/iam/docs/policies#versions + Conditions overview https://cloud.google.com/iam/docs/conditions-overview. + """ + + _OWNER_ROLES = (OWNER_ROLE,) + """Roles mapped onto our ``owners`` attribute.""" + + _EDITOR_ROLES = (EDITOR_ROLE,) + """Roles mapped onto our ``editors`` attribute.""" + + _VIEWER_ROLES = (VIEWER_ROLE,) + """Roles mapped onto our ``viewers`` attribute.""" + + def __init__(self, etag=None, version=None): + self.etag = etag + self.version = version + self._bindings = [] + + def __iter__(self): + self.__check_version__() + return (binding["role"] for binding in self._bindings) + + def __len__(self): + self.__check_version__() + return len(self._bindings) + + def __getitem__(self, key): + self.__check_version__() + for b in self._bindings: + if b["role"] == key: + return b["members"] + return set() + + def __setitem__(self, key, value): + self.__check_version__() + value = set(value) + for binding in self._bindings: + if binding["role"] == key: + binding["members"] = value + return + self._bindings.append({"role": key, "members": value}) + + def __delitem__(self, key): + self.__check_version__() + for b in self._bindings: + if b["role"] == key: + self._bindings.remove(b) + return + raise KeyError(key) + + def __check_version__(self): + """Raise InvalidOperationException if version is greater than 1 or policy contains conditions.""" + raise_version = self.version is not None and self.version > 1 + + if raise_version or self._contains_conditions(): + raise InvalidOperationException(_DICT_ACCESS_MSG) + + def _contains_conditions(self): + for b in self._bindings: + if b.get("condition") is not None: + return True + return False + + @property + def bindings(self): + """The policy's list of bindings. + + A binding is specified by a dictionary with keys: + + * role (str): Role that is assigned to `members`. + + * members (:obj:`set` of str): Specifies the identities associated to this binding. + + * condition (:obj:`dict` of str:str): Specifies a condition under which this binding will apply. + + * title (str): Title for the condition. + + * description (:obj:str, optional): Description of the condition. + + * expression: A CEL expression. + + Type: + :obj:`list` of :obj:`dict` + + See: + Policy versions https://cloud.google.com/iam/docs/policies#versions + Conditions overview https://cloud.google.com/iam/docs/conditions-overview. + + Example: + + .. code-block:: python + + USER = "user:phred@example.com" + ADMIN_GROUP = "group:admins@groups.example.com" + SERVICE_ACCOUNT = "serviceAccount:account-1234@accounts.example.com" + CONDITION = { + "title": "request_time", + "description": "Requests made before 2021-01-01T00:00:00Z", # Optional + "expression": "request.time < timestamp(\"2021-01-01T00:00:00Z\")" + } + + # Set policy's version to 3 before setting bindings containing conditions. + policy.version = 3 + + policy.bindings = [ + { + "role": "roles/viewer", + "members": {USER, ADMIN_GROUP, SERVICE_ACCOUNT}, + "condition": CONDITION + }, + ... + ] + """ + return self._bindings + + @bindings.setter + def bindings(self, bindings): + self._bindings = bindings + + @property + def owners(self): + """Legacy access to owner role. + + Raise InvalidOperationException if version is greater than 1 or policy contains conditions. + + DEPRECATED: use `policy.bindings` to access bindings instead. + """ + result = set() + for role in self._OWNER_ROLES: + for member in self.get(role, ()): + result.add(member) + return frozenset(result) + + @owners.setter + def owners(self, value): + """Update owners. + + Raise InvalidOperationException if version is greater than 1 or policy contains conditions. + + DEPRECATED: use `policy.bindings` to access bindings instead. + """ + warnings.warn( + _ASSIGNMENT_DEPRECATED_MSG.format("owners", OWNER_ROLE), DeprecationWarning + ) + self[OWNER_ROLE] = value + + @property + def editors(self): + """Legacy access to editor role. + + Raise InvalidOperationException if version is greater than 1 or policy contains conditions. + + DEPRECATED: use `policy.bindings` to access bindings instead. + """ + result = set() + for role in self._EDITOR_ROLES: + for member in self.get(role, ()): + result.add(member) + return frozenset(result) + + @editors.setter + def editors(self, value): + """Update editors. + + Raise InvalidOperationException if version is greater than 1 or policy contains conditions. + + DEPRECATED: use `policy.bindings` to modify bindings instead. + """ + warnings.warn( + _ASSIGNMENT_DEPRECATED_MSG.format("editors", EDITOR_ROLE), + DeprecationWarning, + ) + self[EDITOR_ROLE] = value + + @property + def viewers(self): + """Legacy access to viewer role. + + Raise InvalidOperationException if version is greater than 1 or policy contains conditions. + + DEPRECATED: use `policy.bindings` to modify bindings instead. + """ + result = set() + for role in self._VIEWER_ROLES: + for member in self.get(role, ()): + result.add(member) + return frozenset(result) + + @viewers.setter + def viewers(self, value): + """Update viewers. + + Raise InvalidOperationException if version is greater than 1 or policy contains conditions. + + DEPRECATED: use `policy.bindings` to modify bindings instead. + """ + warnings.warn( + _ASSIGNMENT_DEPRECATED_MSG.format("viewers", VIEWER_ROLE), + DeprecationWarning, + ) + self[VIEWER_ROLE] = value + + @staticmethod + def user(email): + """Factory method for a user member. + + Args: + email (str): E-mail for this particular user. + + Returns: + str: A member string corresponding to the given user. + + DEPRECATED: set the role `user:{email}` in the binding instead. + """ + warnings.warn( + _FACTORY_DEPRECATED_MSG.format("user:{email}"), DeprecationWarning, + ) + return "user:%s" % (email,) + + @staticmethod + def service_account(email): + """Factory method for a service account member. + + Args: + email (str): E-mail for this particular service account. + + Returns: + str: A member string corresponding to the given service account. + + DEPRECATED: set the role `serviceAccount:{email}` in the binding instead. + """ + warnings.warn( + _FACTORY_DEPRECATED_MSG.format("serviceAccount:{email}"), + DeprecationWarning, + ) + return "serviceAccount:%s" % (email,) + + @staticmethod + def group(email): + """Factory method for a group member. + + Args: + email (str): An id or e-mail for this particular group. + + Returns: + str: A member string corresponding to the given group. + + DEPRECATED: set the role `group:{email}` in the binding instead. + """ + warnings.warn( + _FACTORY_DEPRECATED_MSG.format("group:{email}"), DeprecationWarning, + ) + return "group:%s" % (email,) + + @staticmethod + def domain(domain): + """Factory method for a domain member. + + Args: + domain (str): The domain for this member. + + Returns: + str: A member string corresponding to the given domain. + + DEPRECATED: set the role `domain:{email}` in the binding instead. + """ + warnings.warn( + _FACTORY_DEPRECATED_MSG.format("domain:{email}"), DeprecationWarning, + ) + return "domain:%s" % (domain,) + + @staticmethod + def all_users(): + """Factory method for a member representing all users. + + Returns: + str: A member string representing all users. + + DEPRECATED: set the role `allUsers` in the binding instead. + """ + warnings.warn( + _FACTORY_DEPRECATED_MSG.format("allUsers"), DeprecationWarning, + ) + return "allUsers" + + @staticmethod + def authenticated_users(): + """Factory method for a member representing all authenticated users. + + Returns: + str: A member string representing all authenticated users. + + DEPRECATED: set the role `allAuthenticatedUsers` in the binding instead. + """ + warnings.warn( + _FACTORY_DEPRECATED_MSG.format("allAuthenticatedUsers"), DeprecationWarning, + ) + return "allAuthenticatedUsers" + + @classmethod + def from_api_repr(cls, resource): + """Factory: create a policy from a JSON resource. + + Args: + resource (dict): policy resource returned by ``getIamPolicy`` API. + + Returns: + :class:`Policy`: the parsed policy + """ + version = resource.get("version") + etag = resource.get("etag") + policy = cls(etag, version) + policy.bindings = resource.get("bindings", []) + + for binding in policy.bindings: + binding["members"] = set(binding.get("members", ())) + + return policy + + def to_api_repr(self): + """Render a JSON policy resource. + + Returns: + dict: a resource to be passed to the ``setIamPolicy`` API. + """ + resource = {} + + if self.etag is not None: + resource["etag"] = self.etag + + if self.version is not None: + resource["version"] = self.version + + if self._bindings and len(self._bindings) > 0: + bindings = [] + for binding in self._bindings: + members = binding.get("members") + if members: + new_binding = { + "role": binding["role"], + "members": sorted(members) + } + condition = binding.get("condition") + if condition: + new_binding["condition"] = condition + bindings.append(new_binding) + + if bindings: + # Sort bindings by role + key = operator.itemgetter("role") + resource["bindings"] = sorted(bindings, key=key) + + return resource diff --git a/venv/Lib/site-packages/google/api_core/operation.py b/venv/Lib/site-packages/google/api_core/operation.py new file mode 100644 index 000000000..e6407b8c5 --- /dev/null +++ b/venv/Lib/site-packages/google/api_core/operation.py @@ -0,0 +1,327 @@ +# Copyright 2016 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +"""Futures for long-running operations returned from Google Cloud APIs. + +These futures can be used to synchronously wait for the result of a +long-running operation using :meth:`Operation.result`: + + +.. code-block:: python + + operation = my_api_client.long_running_method() + result = operation.result() + +Or asynchronously using callbacks and :meth:`Operation.add_done_callback`: + +.. code-block:: python + + operation = my_api_client.long_running_method() + + def my_callback(future): + result = future.result() + + operation.add_done_callback(my_callback) + +""" + +import functools +import threading + +from google.api_core import exceptions +from google.api_core import protobuf_helpers +from google.api_core.future import polling +from google.longrunning import operations_pb2 +from google.protobuf import json_format +from google.rpc import code_pb2 + + +class Operation(polling.PollingFuture): + """A Future for interacting with a Google API Long-Running Operation. + + Args: + operation (google.longrunning.operations_pb2.Operation): The + initial operation. + refresh (Callable[[], ~.api_core.operation.Operation]): A callable that + returns the latest state of the operation. + cancel (Callable[[], None]): A callable that tries to cancel + the operation. + result_type (func:`type`): The protobuf type for the operation's + result. + metadata_type (func:`type`): The protobuf type for the operation's + metadata. + retry (google.api_core.retry.Retry): The retry configuration used + when polling. This can be used to control how often :meth:`done` + is polled. Regardless of the retry's ``deadline``, it will be + overridden by the ``timeout`` argument to :meth:`result`. + """ + + def __init__( + self, + operation, + refresh, + cancel, + result_type, + metadata_type=None, + retry=polling.DEFAULT_RETRY, + ): + super(Operation, self).__init__(retry=retry) + self._operation = operation + self._refresh = refresh + self._cancel = cancel + self._result_type = result_type + self._metadata_type = metadata_type + self._completion_lock = threading.Lock() + # Invoke this in case the operation came back already complete. + self._set_result_from_operation() + + @property + def operation(self): + """google.longrunning.Operation: The current long-running operation.""" + return self._operation + + @property + def metadata(self): + """google.protobuf.Message: the current operation metadata.""" + if not self._operation.HasField("metadata"): + return None + + return protobuf_helpers.from_any_pb( + self._metadata_type, self._operation.metadata + ) + + @classmethod + def deserialize(self, payload): + """Deserialize a ``google.longrunning.Operation`` protocol buffer. + + Args: + payload (bytes): A serialized operation protocol buffer. + + Returns: + ~.operations_pb2.Operation: An Operation protobuf object. + """ + return operations_pb2.Operation.FromString(payload) + + def _set_result_from_operation(self): + """Set the result or exception from the operation if it is complete.""" + # This must be done in a lock to prevent the polling thread + # and main thread from both executing the completion logic + # at the same time. + with self._completion_lock: + # If the operation isn't complete or if the result has already been + # set, do not call set_result/set_exception again. + # Note: self._result_set is set to True in set_result and + # set_exception, in case those methods are invoked directly. + if not self._operation.done or self._result_set: + return + + if self._operation.HasField("response"): + response = protobuf_helpers.from_any_pb( + self._result_type, self._operation.response + ) + self.set_result(response) + elif self._operation.HasField("error"): + exception = exceptions.GoogleAPICallError( + self._operation.error.message, + errors=(self._operation.error,), + response=self._operation, + ) + self.set_exception(exception) + else: + exception = exceptions.GoogleAPICallError( + "Unexpected state: Long-running operation had neither " + "response nor error set." + ) + self.set_exception(exception) + + def _refresh_and_update(self, retry=polling.DEFAULT_RETRY): + """Refresh the operation and update the result if needed. + + Args: + retry (google.api_core.retry.Retry): (Optional) How to retry the RPC. + """ + # If the currently cached operation is done, no need to make another + # RPC as it will not change once done. + if not self._operation.done: + self._operation = self._refresh(retry=retry) + self._set_result_from_operation() + + def done(self, retry=polling.DEFAULT_RETRY): + """Checks to see if the operation is complete. + + Args: + retry (google.api_core.retry.Retry): (Optional) How to retry the RPC. + + Returns: + bool: True if the operation is complete, False otherwise. + """ + self._refresh_and_update(retry) + return self._operation.done + + def cancel(self): + """Attempt to cancel the operation. + + Returns: + bool: True if the cancel RPC was made, False if the operation is + already complete. + """ + if self.done(): + return False + + self._cancel() + return True + + def cancelled(self): + """True if the operation was cancelled.""" + self._refresh_and_update() + return ( + self._operation.HasField("error") + and self._operation.error.code == code_pb2.CANCELLED + ) + + +def _refresh_http(api_request, operation_name): + """Refresh an operation using a JSON/HTTP client. + + Args: + api_request (Callable): A callable used to make an API request. This + should generally be + :meth:`google.cloud._http.Connection.api_request`. + operation_name (str): The name of the operation. + + Returns: + google.longrunning.operations_pb2.Operation: The operation. + """ + path = "operations/{}".format(operation_name) + api_response = api_request(method="GET", path=path) + return json_format.ParseDict(api_response, operations_pb2.Operation()) + + +def _cancel_http(api_request, operation_name): + """Cancel an operation using a JSON/HTTP client. + + Args: + api_request (Callable): A callable used to make an API request. This + should generally be + :meth:`google.cloud._http.Connection.api_request`. + operation_name (str): The name of the operation. + """ + path = "operations/{}:cancel".format(operation_name) + api_request(method="POST", path=path) + + +def from_http_json(operation, api_request, result_type, **kwargs): + """Create an operation future using a HTTP/JSON client. + + This interacts with the long-running operations `service`_ (specific + to a given API) via `HTTP/JSON`_. + + .. _HTTP/JSON: https://cloud.google.com/speech/reference/rest/\ + v1beta1/operations#Operation + + Args: + operation (dict): Operation as a dictionary. + api_request (Callable): A callable used to make an API request. This + should generally be + :meth:`google.cloud._http.Connection.api_request`. + result_type (:func:`type`): The protobuf result type. + kwargs: Keyword args passed into the :class:`Operation` constructor. + + Returns: + ~.api_core.operation.Operation: The operation future to track the given + operation. + """ + operation_proto = json_format.ParseDict(operation, operations_pb2.Operation()) + refresh = functools.partial(_refresh_http, api_request, operation_proto.name) + cancel = functools.partial(_cancel_http, api_request, operation_proto.name) + return Operation(operation_proto, refresh, cancel, result_type, **kwargs) + + +def _refresh_grpc(operations_stub, operation_name): + """Refresh an operation using a gRPC client. + + Args: + operations_stub (google.longrunning.operations_pb2.OperationsStub): + The gRPC operations stub. + operation_name (str): The name of the operation. + + Returns: + google.longrunning.operations_pb2.Operation: The operation. + """ + request_pb = operations_pb2.GetOperationRequest(name=operation_name) + return operations_stub.GetOperation(request_pb) + + +def _cancel_grpc(operations_stub, operation_name): + """Cancel an operation using a gRPC client. + + Args: + operations_stub (google.longrunning.operations_pb2.OperationsStub): + The gRPC operations stub. + operation_name (str): The name of the operation. + """ + request_pb = operations_pb2.CancelOperationRequest(name=operation_name) + operations_stub.CancelOperation(request_pb) + + +def from_grpc(operation, operations_stub, result_type, **kwargs): + """Create an operation future using a gRPC client. + + This interacts with the long-running operations `service`_ (specific + to a given API) via gRPC. + + .. _service: https://github.com/googleapis/googleapis/blob/\ + 050400df0fdb16f63b63e9dee53819044bffc857/\ + google/longrunning/operations.proto#L38 + + Args: + operation (google.longrunning.operations_pb2.Operation): The operation. + operations_stub (google.longrunning.operations_pb2.OperationsStub): + The operations stub. + result_type (:func:`type`): The protobuf result type. + kwargs: Keyword args passed into the :class:`Operation` constructor. + + Returns: + ~.api_core.operation.Operation: The operation future to track the given + operation. + """ + refresh = functools.partial(_refresh_grpc, operations_stub, operation.name) + cancel = functools.partial(_cancel_grpc, operations_stub, operation.name) + return Operation(operation, refresh, cancel, result_type, **kwargs) + + +def from_gapic(operation, operations_client, result_type, **kwargs): + """Create an operation future from a gapic client. + + This interacts with the long-running operations `service`_ (specific + to a given API) via a gapic client. + + .. _service: https://github.com/googleapis/googleapis/blob/\ + 050400df0fdb16f63b63e9dee53819044bffc857/\ + google/longrunning/operations.proto#L38 + + Args: + operation (google.longrunning.operations_pb2.Operation): The operation. + operations_client (google.api_core.operations_v1.OperationsClient): + The operations client. + result_type (:func:`type`): The protobuf result type. + kwargs: Keyword args passed into the :class:`Operation` constructor. + + Returns: + ~.api_core.operation.Operation: The operation future to track the given + operation. + """ + refresh = functools.partial(operations_client.get_operation, operation.name) + cancel = functools.partial(operations_client.cancel_operation, operation.name) + return Operation(operation, refresh, cancel, result_type, **kwargs) diff --git a/venv/Lib/site-packages/google/api_core/operation_async.py b/venv/Lib/site-packages/google/api_core/operation_async.py new file mode 100644 index 000000000..89500af19 --- /dev/null +++ b/venv/Lib/site-packages/google/api_core/operation_async.py @@ -0,0 +1,215 @@ +# Copyright 2020 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +"""AsyncIO futures for long-running operations returned from Google Cloud APIs. + +These futures can be used to await for the result of a long-running operation +using :meth:`AsyncOperation.result`: + + +.. code-block:: python + + operation = my_api_client.long_running_method() + result = await operation.result() + +Or asynchronously using callbacks and :meth:`Operation.add_done_callback`: + +.. code-block:: python + + operation = my_api_client.long_running_method() + + def my_callback(future): + result = await future.result() + + operation.add_done_callback(my_callback) + +""" + +import functools +import threading + +from google.api_core import exceptions +from google.api_core import protobuf_helpers +from google.api_core.future import async_future +from google.longrunning import operations_pb2 +from google.rpc import code_pb2 + + +class AsyncOperation(async_future.AsyncFuture): + """A Future for interacting with a Google API Long-Running Operation. + + Args: + operation (google.longrunning.operations_pb2.Operation): The + initial operation. + refresh (Callable[[], ~.api_core.operation.Operation]): A callable that + returns the latest state of the operation. + cancel (Callable[[], None]): A callable that tries to cancel + the operation. + result_type (func:`type`): The protobuf type for the operation's + result. + metadata_type (func:`type`): The protobuf type for the operation's + metadata. + retry (google.api_core.retry.Retry): The retry configuration used + when polling. This can be used to control how often :meth:`done` + is polled. Regardless of the retry's ``deadline``, it will be + overridden by the ``timeout`` argument to :meth:`result`. + """ + + def __init__( + self, + operation, + refresh, + cancel, + result_type, + metadata_type=None, + retry=async_future.DEFAULT_RETRY, + ): + super().__init__(retry=retry) + self._operation = operation + self._refresh = refresh + self._cancel = cancel + self._result_type = result_type + self._metadata_type = metadata_type + self._completion_lock = threading.Lock() + # Invoke this in case the operation came back already complete. + self._set_result_from_operation() + + @property + def operation(self): + """google.longrunning.Operation: The current long-running operation.""" + return self._operation + + @property + def metadata(self): + """google.protobuf.Message: the current operation metadata.""" + if not self._operation.HasField("metadata"): + return None + + return protobuf_helpers.from_any_pb( + self._metadata_type, self._operation.metadata + ) + + @classmethod + def deserialize(cls, payload): + """Deserialize a ``google.longrunning.Operation`` protocol buffer. + + Args: + payload (bytes): A serialized operation protocol buffer. + + Returns: + ~.operations_pb2.Operation: An Operation protobuf object. + """ + return operations_pb2.Operation.FromString(payload) + + def _set_result_from_operation(self): + """Set the result or exception from the operation if it is complete.""" + # This must be done in a lock to prevent the async_future thread + # and main thread from both executing the completion logic + # at the same time. + with self._completion_lock: + # If the operation isn't complete or if the result has already been + # set, do not call set_result/set_exception again. + if not self._operation.done or self._future.done(): + return + + if self._operation.HasField("response"): + response = protobuf_helpers.from_any_pb( + self._result_type, self._operation.response + ) + self.set_result(response) + elif self._operation.HasField("error"): + exception = exceptions.GoogleAPICallError( + self._operation.error.message, + errors=(self._operation.error,), + response=self._operation, + ) + self.set_exception(exception) + else: + exception = exceptions.GoogleAPICallError( + "Unexpected state: Long-running operation had neither " + "response nor error set." + ) + self.set_exception(exception) + + async def _refresh_and_update(self, retry=async_future.DEFAULT_RETRY): + """Refresh the operation and update the result if needed. + + Args: + retry (google.api_core.retry.Retry): (Optional) How to retry the RPC. + """ + # If the currently cached operation is done, no need to make another + # RPC as it will not change once done. + if not self._operation.done: + self._operation = await self._refresh(retry=retry) + self._set_result_from_operation() + + async def done(self, retry=async_future.DEFAULT_RETRY): + """Checks to see if the operation is complete. + + Args: + retry (google.api_core.retry.Retry): (Optional) How to retry the RPC. + + Returns: + bool: True if the operation is complete, False otherwise. + """ + await self._refresh_and_update(retry) + return self._operation.done + + async def cancel(self): + """Attempt to cancel the operation. + + Returns: + bool: True if the cancel RPC was made, False if the operation is + already complete. + """ + result = await self.done() + if result: + return False + else: + await self._cancel() + return True + + async def cancelled(self): + """True if the operation was cancelled.""" + await self._refresh_and_update() + return ( + self._operation.HasField("error") + and self._operation.error.code == code_pb2.CANCELLED + ) + + +def from_gapic(operation, operations_client, result_type, **kwargs): + """Create an operation future from a gapic client. + + This interacts with the long-running operations `service`_ (specific + to a given API) via a gapic client. + + .. _service: https://github.com/googleapis/googleapis/blob/\ + 050400df0fdb16f63b63e9dee53819044bffc857/\ + google/longrunning/operations.proto#L38 + + Args: + operation (google.longrunning.operations_pb2.Operation): The operation. + operations_client (google.api_core.operations_v1.OperationsClient): + The operations client. + result_type (:func:`type`): The protobuf result type. + kwargs: Keyword args passed into the :class:`Operation` constructor. + + Returns: + ~.api_core.operation.Operation: The operation future to track the given + operation. + """ + refresh = functools.partial(operations_client.get_operation, operation.name) + cancel = functools.partial(operations_client.cancel_operation, operation.name) + return AsyncOperation(operation, refresh, cancel, result_type, **kwargs) diff --git a/venv/Lib/site-packages/google/api_core/operations_v1/__init__.py b/venv/Lib/site-packages/google/api_core/operations_v1/__init__.py new file mode 100644 index 000000000..bc9befcb7 --- /dev/null +++ b/venv/Lib/site-packages/google/api_core/operations_v1/__init__.py @@ -0,0 +1,24 @@ +# Copyright 2017 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +"""Package for interacting with the google.longrunning.operations meta-API.""" + +import sys + +from google.api_core.operations_v1.operations_client import OperationsClient + +__all__ = ["OperationsClient"] +if sys.version_info >= (3, 6, 0): + from google.api_core.operations_v1.operations_async_client import OperationsAsyncClient # noqa: F401 + __all__.append("OperationsAsyncClient") diff --git a/venv/Lib/site-packages/google/api_core/operations_v1/__pycache__/__init__.cpython-36.pyc b/venv/Lib/site-packages/google/api_core/operations_v1/__pycache__/__init__.cpython-36.pyc new file mode 100644 index 0000000000000000000000000000000000000000..c3d57536567a183ffabafaea294263f199f5d89b GIT binary patch literal 655 zcma)3J&zMH5VdzV9~W|hhTiQJNfbB=5IS*C01|?e=vJ02pFP<)*|k@;cTb^(Kf@28 z=XY#NmA^p6tS*q0Sn~MeJ2zfj-*~{1sxOa#)S>5hajq#(MmfA}je!E+${z-AJ{S1+bO#%-9HC zs%UJ%?o3>>xCT}@SClX>oh^K0En;(5BP|+d1FIm)+4ar)`5qOKj~BFi^ywe^rZixq zPY~H-D`Y>!fRx8a%5~UTb>IzpH1$2x_nms$f1GtAA+%FMbZOXyd~pyYYa^8NaH2-E z%hQ)SmhW@Ovcw$I7JNYI!q}C|pZ#|-*$Wkil)ch!DC-)m{!aXZUThzJ|4=V@6R-lm zm9bfKXF+?@0@o0>(bc@M=Fa&o-+}b(k_V_Dpy_PM6%?1xmrr=@-3C#3sTNLzaw_X)>e}I;DRAfc4IO literal 0 HcmV?d00001 diff --git a/venv/Lib/site-packages/google/api_core/operations_v1/__pycache__/operations_async_client.cpython-36.pyc b/venv/Lib/site-packages/google/api_core/operations_v1/__pycache__/operations_async_client.cpython-36.pyc new file mode 100644 index 0000000000000000000000000000000000000000..c9b893f86d30227bed2fee24a787b43aae84c461 GIT binary patch literal 10932 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 literal 0 HcmV?d00001 diff --git a/venv/Lib/site-packages/google/api_core/operations_v1/__pycache__/operations_client.cpython-36.pyc b/venv/Lib/site-packages/google/api_core/operations_v1/__pycache__/operations_client.cpython-36.pyc new file mode 100644 index 0000000000000000000000000000000000000000..3ebeaa499b1510648b550bdfba4020e9da72681e GIT binary patch literal 11492 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 literal 0 HcmV?d00001 diff --git a/venv/Lib/site-packages/google/api_core/operations_v1/operations_async_client.py b/venv/Lib/site-packages/google/api_core/operations_v1/operations_async_client.py new file mode 100644 index 000000000..039bec1b2 --- /dev/null +++ b/venv/Lib/site-packages/google/api_core/operations_v1/operations_async_client.py @@ -0,0 +1,274 @@ +# Copyright 2020 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +"""An async client for the google.longrunning.operations meta-API. + +.. _Google API Style Guide: + https://cloud.google.com/apis/design/design_pattern + s#long_running_operations +.. _google/longrunning/operations.proto: + https://github.com/googleapis/googleapis/blob/master/google/longrunning + /operations.proto +""" + +import functools + +from google.api_core import gapic_v1, page_iterator_async +from google.api_core.operations_v1 import operations_client_config +from google.longrunning import operations_pb2 + + +class OperationsAsyncClient: + """Async client for interacting with long-running operations. + + Args: + channel (aio.Channel): The gRPC AsyncIO channel associated with the + service that implements the ``google.longrunning.operations`` + interface. + client_config (dict): + A dictionary of call options for each method. If not specified + the default configuration is used. + """ + + def __init__(self, channel, client_config=operations_client_config.config): + # Create the gRPC client stub with gRPC AsyncIO channel. + self.operations_stub = operations_pb2.OperationsStub(channel) + + # Create all wrapped methods using the interface configuration. + # The interface config contains all of the default settings for retry + # and timeout for each RPC method. + interfaces = client_config["interfaces"] + interface_config = interfaces["google.longrunning.Operations"] + method_configs = gapic_v1.config_async.parse_method_configs(interface_config) + + self._get_operation = gapic_v1.method_async.wrap_method( + self.operations_stub.GetOperation, + default_retry=method_configs["GetOperation"].retry, + default_timeout=method_configs["GetOperation"].timeout, + ) + + self._list_operations = gapic_v1.method_async.wrap_method( + self.operations_stub.ListOperations, + default_retry=method_configs["ListOperations"].retry, + default_timeout=method_configs["ListOperations"].timeout, + ) + + self._cancel_operation = gapic_v1.method_async.wrap_method( + self.operations_stub.CancelOperation, + default_retry=method_configs["CancelOperation"].retry, + default_timeout=method_configs["CancelOperation"].timeout, + ) + + self._delete_operation = gapic_v1.method_async.wrap_method( + self.operations_stub.DeleteOperation, + default_retry=method_configs["DeleteOperation"].retry, + default_timeout=method_configs["DeleteOperation"].timeout, + ) + + async def get_operation( + self, name, retry=gapic_v1.method_async.DEFAULT, timeout=gapic_v1.method_async.DEFAULT + ): + """Gets the latest state of a long-running operation. + + Clients can use this method to poll the operation result at intervals + as recommended by the API service. + + Example: + >>> from google.api_core import operations_v1 + >>> api = operations_v1.OperationsClient() + >>> name = '' + >>> response = await api.get_operation(name) + + Args: + name (str): The name of the operation resource. + retry (google.api_core.retry.Retry): The retry strategy to use + when invoking the RPC. If unspecified, the default retry from + the client configuration will be used. If ``None``, then this + method will not retry the RPC at all. + timeout (float): The amount of time in seconds to wait for the RPC + to complete. Note that if ``retry`` is used, this timeout + applies to each individual attempt and the overall time it + takes for this method to complete may be longer. If + unspecified, the the default timeout in the client + configuration is used. If ``None``, then the RPC method will + not time out. + + Returns: + google.longrunning.operations_pb2.Operation: The state of the + operation. + + Raises: + google.api_core.exceptions.GoogleAPICallError: If an error occurred + while invoking the RPC, the appropriate ``GoogleAPICallError`` + subclass will be raised. + """ + request = operations_pb2.GetOperationRequest(name=name) + return await self._get_operation(request, retry=retry, timeout=timeout) + + async def list_operations( + self, + name, + filter_, + retry=gapic_v1.method_async.DEFAULT, + timeout=gapic_v1.method_async.DEFAULT, + ): + """ + Lists operations that match the specified filter in the request. + + Example: + >>> from google.api_core import operations_v1 + >>> api = operations_v1.OperationsClient() + >>> name = '' + >>> + >>> # Iterate over all results + >>> for operation in await api.list_operations(name): + >>> # process operation + >>> pass + >>> + >>> # Or iterate over results one page at a time + >>> iter = await api.list_operations(name) + >>> for page in iter.pages: + >>> for operation in page: + >>> # process operation + >>> pass + + Args: + name (str): The name of the operation collection. + filter_ (str): The standard list filter. + retry (google.api_core.retry.Retry): The retry strategy to use + when invoking the RPC. If unspecified, the default retry from + the client configuration will be used. If ``None``, then this + method will not retry the RPC at all. + timeout (float): The amount of time in seconds to wait for the RPC + to complete. Note that if ``retry`` is used, this timeout + applies to each individual attempt and the overall time it + takes for this method to complete may be longer. If + unspecified, the the default timeout in the client + configuration is used. If ``None``, then the RPC method will + not time out. + + Returns: + google.api_core.page_iterator.Iterator: An iterator that yields + :class:`google.longrunning.operations_pb2.Operation` instances. + + Raises: + google.api_core.exceptions.MethodNotImplemented: If the server + does not support this method. Services are not required to + implement this method. + google.api_core.exceptions.GoogleAPICallError: If an error occurred + while invoking the RPC, the appropriate ``GoogleAPICallError`` + subclass will be raised. + """ + # Create the request object. + request = operations_pb2.ListOperationsRequest(name=name, filter=filter_) + + # Create the method used to fetch pages + method = functools.partial(self._list_operations, retry=retry, timeout=timeout) + + iterator = page_iterator_async.AsyncGRPCIterator( + client=None, + method=method, + request=request, + items_field="operations", + request_token_field="page_token", + response_token_field="next_page_token", + ) + + return iterator + + async def cancel_operation( + self, name, retry=gapic_v1.method_async.DEFAULT, timeout=gapic_v1.method_async.DEFAULT + ): + """Starts asynchronous cancellation on a long-running operation. + + The server makes a best effort to cancel the operation, but success is + not guaranteed. Clients can use :meth:`get_operation` or service- + specific methods to check whether the cancellation succeeded or whether + the operation completed despite cancellation. On successful + cancellation, the operation is not deleted; instead, it becomes an + operation with an ``Operation.error`` value with a + ``google.rpc.Status.code`` of ``1``, corresponding to + ``Code.CANCELLED``. + + Example: + >>> from google.api_core import operations_v1 + >>> api = operations_v1.OperationsClient() + >>> name = '' + >>> api.cancel_operation(name) + + Args: + name (str): The name of the operation resource to be cancelled. + retry (google.api_core.retry.Retry): The retry strategy to use + when invoking the RPC. If unspecified, the default retry from + the client configuration will be used. If ``None``, then this + method will not retry the RPC at all. + timeout (float): The amount of time in seconds to wait for the RPC + to complete. Note that if ``retry`` is used, this timeout + applies to each individual attempt and the overall time it + takes for this method to complete may be longer. If + unspecified, the the default timeout in the client + configuration is used. If ``None``, then the RPC method will + not time out. + + Raises: + google.api_core.exceptions.MethodNotImplemented: If the server + does not support this method. Services are not required to + implement this method. + google.api_core.exceptions.GoogleAPICallError: If an error occurred + while invoking the RPC, the appropriate ``GoogleAPICallError`` + subclass will be raised. + """ + # Create the request object. + request = operations_pb2.CancelOperationRequest(name=name) + await self._cancel_operation(request, retry=retry, timeout=timeout) + + async def delete_operation( + self, name, retry=gapic_v1.method_async.DEFAULT, timeout=gapic_v1.method_async.DEFAULT + ): + """Deletes a long-running operation. + + This method indicates that the client is no longer interested in the + operation result. It does not cancel the operation. + + Example: + >>> from google.api_core import operations_v1 + >>> api = operations_v1.OperationsClient() + >>> name = '' + >>> api.delete_operation(name) + + Args: + name (str): The name of the operation resource to be deleted. + retry (google.api_core.retry.Retry): The retry strategy to use + when invoking the RPC. If unspecified, the default retry from + the client configuration will be used. If ``None``, then this + method will not retry the RPC at all. + timeout (float): The amount of time in seconds to wait for the RPC + to complete. Note that if ``retry`` is used, this timeout + applies to each individual attempt and the overall time it + takes for this method to complete may be longer. If + unspecified, the the default timeout in the client + configuration is used. If ``None``, then the RPC method will + not time out. + + Raises: + google.api_core.exceptions.MethodNotImplemented: If the server + does not support this method. Services are not required to + implement this method. + google.api_core.exceptions.GoogleAPICallError: If an error occurred + while invoking the RPC, the appropriate ``GoogleAPICallError`` + subclass will be raised. + """ + # Create the request object. + request = operations_pb2.DeleteOperationRequest(name=name) + await self._delete_operation(request, retry=retry, timeout=timeout) diff --git a/venv/Lib/site-packages/google/api_core/operations_v1/operations_client.py b/venv/Lib/site-packages/google/api_core/operations_v1/operations_client.py new file mode 100644 index 000000000..cd2923bb9 --- /dev/null +++ b/venv/Lib/site-packages/google/api_core/operations_v1/operations_client.py @@ -0,0 +1,288 @@ +# Copyright 2017 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +"""A client for the google.longrunning.operations meta-API. + +This is a client that deals with long-running operations that follow the +pattern outlined by the `Google API Style Guide`_. + +When an API method normally takes long time to complete, it can be designed to +return ``Operation`` to the client, and the client can use this interface to +receive the real response asynchronously by polling the operation resource to +receive the response. + +It is not a separate service, but rather an interface implemented by a larger +service. The protocol-level definition is available at +`google/longrunning/operations.proto`_. Typically, this will be constructed +automatically by another client class to deal with operations. + +.. _Google API Style Guide: + https://cloud.google.com/apis/design/design_pattern + s#long_running_operations +.. _google/longrunning/operations.proto: + https://github.com/googleapis/googleapis/blob/master/google/longrunning + /operations.proto +""" + +import functools + +from google.api_core import gapic_v1 +from google.api_core import page_iterator +from google.api_core.operations_v1 import operations_client_config +from google.longrunning import operations_pb2 + + +class OperationsClient(object): + """Client for interacting with long-running operations within a service. + + Args: + channel (grpc.Channel): The gRPC channel associated with the service + that implements the ``google.longrunning.operations`` interface. + client_config (dict): + A dictionary of call options for each method. If not specified + the default configuration is used. + """ + + def __init__(self, channel, client_config=operations_client_config.config): + # Create the gRPC client stub. + self.operations_stub = operations_pb2.OperationsStub(channel) + + # Create all wrapped methods using the interface configuration. + # The interface config contains all of the default settings for retry + # and timeout for each RPC method. + interfaces = client_config["interfaces"] + interface_config = interfaces["google.longrunning.Operations"] + method_configs = gapic_v1.config.parse_method_configs(interface_config) + + self._get_operation = gapic_v1.method.wrap_method( + self.operations_stub.GetOperation, + default_retry=method_configs["GetOperation"].retry, + default_timeout=method_configs["GetOperation"].timeout, + ) + + self._list_operations = gapic_v1.method.wrap_method( + self.operations_stub.ListOperations, + default_retry=method_configs["ListOperations"].retry, + default_timeout=method_configs["ListOperations"].timeout, + ) + + self._cancel_operation = gapic_v1.method.wrap_method( + self.operations_stub.CancelOperation, + default_retry=method_configs["CancelOperation"].retry, + default_timeout=method_configs["CancelOperation"].timeout, + ) + + self._delete_operation = gapic_v1.method.wrap_method( + self.operations_stub.DeleteOperation, + default_retry=method_configs["DeleteOperation"].retry, + default_timeout=method_configs["DeleteOperation"].timeout, + ) + + # Service calls + def get_operation( + self, name, retry=gapic_v1.method.DEFAULT, timeout=gapic_v1.method.DEFAULT + ): + """Gets the latest state of a long-running operation. + + Clients can use this method to poll the operation result at intervals + as recommended by the API service. + + Example: + >>> from google.api_core import operations_v1 + >>> api = operations_v1.OperationsClient() + >>> name = '' + >>> response = api.get_operation(name) + + Args: + name (str): The name of the operation resource. + retry (google.api_core.retry.Retry): The retry strategy to use + when invoking the RPC. If unspecified, the default retry from + the client configuration will be used. If ``None``, then this + method will not retry the RPC at all. + timeout (float): The amount of time in seconds to wait for the RPC + to complete. Note that if ``retry`` is used, this timeout + applies to each individual attempt and the overall time it + takes for this method to complete may be longer. If + unspecified, the the default timeout in the client + configuration is used. If ``None``, then the RPC method will + not time out. + + Returns: + google.longrunning.operations_pb2.Operation: The state of the + operation. + + Raises: + google.api_core.exceptions.GoogleAPICallError: If an error occurred + while invoking the RPC, the appropriate ``GoogleAPICallError`` + subclass will be raised. + """ + request = operations_pb2.GetOperationRequest(name=name) + return self._get_operation(request, retry=retry, timeout=timeout) + + def list_operations( + self, + name, + filter_, + retry=gapic_v1.method.DEFAULT, + timeout=gapic_v1.method.DEFAULT, + ): + """ + Lists operations that match the specified filter in the request. + + Example: + >>> from google.api_core import operations_v1 + >>> api = operations_v1.OperationsClient() + >>> name = '' + >>> + >>> # Iterate over all results + >>> for operation in api.list_operations(name): + >>> # process operation + >>> pass + >>> + >>> # Or iterate over results one page at a time + >>> iter = api.list_operations(name) + >>> for page in iter.pages: + >>> for operation in page: + >>> # process operation + >>> pass + + Args: + name (str): The name of the operation collection. + filter_ (str): The standard list filter. + retry (google.api_core.retry.Retry): The retry strategy to use + when invoking the RPC. If unspecified, the default retry from + the client configuration will be used. If ``None``, then this + method will not retry the RPC at all. + timeout (float): The amount of time in seconds to wait for the RPC + to complete. Note that if ``retry`` is used, this timeout + applies to each individual attempt and the overall time it + takes for this method to complete may be longer. If + unspecified, the the default timeout in the client + configuration is used. If ``None``, then the RPC method will + not time out. + + Returns: + google.api_core.page_iterator.Iterator: An iterator that yields + :class:`google.longrunning.operations_pb2.Operation` instances. + + Raises: + google.api_core.exceptions.MethodNotImplemented: If the server + does not support this method. Services are not required to + implement this method. + google.api_core.exceptions.GoogleAPICallError: If an error occurred + while invoking the RPC, the appropriate ``GoogleAPICallError`` + subclass will be raised. + """ + # Create the request object. + request = operations_pb2.ListOperationsRequest(name=name, filter=filter_) + + # Create the method used to fetch pages + method = functools.partial(self._list_operations, retry=retry, timeout=timeout) + + iterator = page_iterator.GRPCIterator( + client=None, + method=method, + request=request, + items_field="operations", + request_token_field="page_token", + response_token_field="next_page_token", + ) + + return iterator + + def cancel_operation( + self, name, retry=gapic_v1.method.DEFAULT, timeout=gapic_v1.method.DEFAULT + ): + """Starts asynchronous cancellation on a long-running operation. + + The server makes a best effort to cancel the operation, but success is + not guaranteed. Clients can use :meth:`get_operation` or service- + specific methods to check whether the cancellation succeeded or whether + the operation completed despite cancellation. On successful + cancellation, the operation is not deleted; instead, it becomes an + operation with an ``Operation.error`` value with a + ``google.rpc.Status.code`` of ``1``, corresponding to + ``Code.CANCELLED``. + + Example: + >>> from google.api_core import operations_v1 + >>> api = operations_v1.OperationsClient() + >>> name = '' + >>> api.cancel_operation(name) + + Args: + name (str): The name of the operation resource to be cancelled. + retry (google.api_core.retry.Retry): The retry strategy to use + when invoking the RPC. If unspecified, the default retry from + the client configuration will be used. If ``None``, then this + method will not retry the RPC at all. + timeout (float): The amount of time in seconds to wait for the RPC + to complete. Note that if ``retry`` is used, this timeout + applies to each individual attempt and the overall time it + takes for this method to complete may be longer. If + unspecified, the the default timeout in the client + configuration is used. If ``None``, then the RPC method will + not time out. + + Raises: + google.api_core.exceptions.MethodNotImplemented: If the server + does not support this method. Services are not required to + implement this method. + google.api_core.exceptions.GoogleAPICallError: If an error occurred + while invoking the RPC, the appropriate ``GoogleAPICallError`` + subclass will be raised. + """ + # Create the request object. + request = operations_pb2.CancelOperationRequest(name=name) + self._cancel_operation(request, retry=retry, timeout=timeout) + + def delete_operation( + self, name, retry=gapic_v1.method.DEFAULT, timeout=gapic_v1.method.DEFAULT + ): + """Deletes a long-running operation. + + This method indicates that the client is no longer interested in the + operation result. It does not cancel the operation. + + Example: + >>> from google.api_core import operations_v1 + >>> api = operations_v1.OperationsClient() + >>> name = '' + >>> api.delete_operation(name) + + Args: + name (str): The name of the operation resource to be deleted. + retry (google.api_core.retry.Retry): The retry strategy to use + when invoking the RPC. If unspecified, the default retry from + the client configuration will be used. If ``None``, then this + method will not retry the RPC at all. + timeout (float): The amount of time in seconds to wait for the RPC + to complete. Note that if ``retry`` is used, this timeout + applies to each individual attempt and the overall time it + takes for this method to complete may be longer. If + unspecified, the the default timeout in the client + configuration is used. If ``None``, then the RPC method will + not time out. + + Raises: + google.api_core.exceptions.MethodNotImplemented: If the server + does not support this method. Services are not required to + implement this method. + google.api_core.exceptions.GoogleAPICallError: If an error occurred + while invoking the RPC, the appropriate ``GoogleAPICallError`` + subclass will be raised. + """ + # Create the request object. + request = operations_pb2.DeleteOperationRequest(name=name) + self._delete_operation(request, retry=retry, timeout=timeout) diff --git a/venv/Lib/site-packages/google/api_core/operations_v1/operations_client_config.py b/venv/Lib/site-packages/google/api_core/operations_v1/operations_client_config.py new file mode 100644 index 000000000..6cf95753f --- /dev/null +++ b/venv/Lib/site-packages/google/api_core/operations_v1/operations_client_config.py @@ -0,0 +1,59 @@ +# Copyright 2017 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +"""gapic configuration for the googe.longrunning.operations client.""" + +config = { + "interfaces": { + "google.longrunning.Operations": { + "retry_codes": { + "idempotent": ["DEADLINE_EXCEEDED", "UNAVAILABLE"], + "non_idempotent": [], + }, + "retry_params": { + "default": { + "initial_retry_delay_millis": 100, + "retry_delay_multiplier": 1.3, + "max_retry_delay_millis": 60000, + "initial_rpc_timeout_millis": 20000, + "rpc_timeout_multiplier": 1.0, + "max_rpc_timeout_millis": 600000, + "total_timeout_millis": 600000, + } + }, + "methods": { + "GetOperation": { + "timeout_millis": 60000, + "retry_codes_name": "idempotent", + "retry_params_name": "default", + }, + "ListOperations": { + "timeout_millis": 60000, + "retry_codes_name": "idempotent", + "retry_params_name": "default", + }, + "CancelOperation": { + "timeout_millis": 60000, + "retry_codes_name": "idempotent", + "retry_params_name": "default", + }, + "DeleteOperation": { + "timeout_millis": 60000, + "retry_codes_name": "idempotent", + "retry_params_name": "default", + }, + }, + } + } +} diff --git a/venv/Lib/site-packages/google/api_core/page_iterator.py b/venv/Lib/site-packages/google/api_core/page_iterator.py new file mode 100644 index 000000000..11a92d38f --- /dev/null +++ b/venv/Lib/site-packages/google/api_core/page_iterator.py @@ -0,0 +1,557 @@ +# Copyright 2015 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +"""Iterators for paging through paged API methods. + +These iterators simplify the process of paging through API responses +where the request takes a page token and the response is a list of results with +a token for the next page. See `list pagination`_ in the Google API Style Guide +for more details. + +.. _list pagination: + https://cloud.google.com/apis/design/design_patterns#list_pagination + +API clients that have methods that follow the list pagination pattern can +return an :class:`.Iterator`. You can use this iterator to get **all** of +the results across all pages:: + + >>> results_iterator = client.list_resources() + >>> list(results_iterator) # Convert to a list (consumes all values). + +Or you can walk your way through items and call off the search early if +you find what you're looking for (resulting in possibly fewer requests):: + + >>> for resource in results_iterator: + ... print(resource.name) + ... if not resource.is_valid: + ... break + +At any point, you may check the number of items consumed by referencing the +``num_results`` property of the iterator:: + + >>> for my_item in results_iterator: + ... if results_iterator.num_results >= 10: + ... break + +When iterating, not every new item will send a request to the server. +To iterate based on each page of items (where a page corresponds to +a request):: + + >>> for page in results_iterator.pages: + ... print('=' * 20) + ... print(' Page number: {:d}'.format(iterator.page_number)) + ... print(' Items in page: {:d}'.format(page.num_items)) + ... print(' First item: {!r}'.format(next(page))) + ... print('Items remaining: {:d}'.format(page.remaining)) + ... print('Next page token: {}'.format(iterator.next_page_token)) + ==================== + Page number: 1 + Items in page: 1 + First item: + Items remaining: 0 + Next page token: eav1OzQB0OM8rLdGXOEsyQWSG + ==================== + Page number: 2 + Items in page: 19 + First item: + Items remaining: 18 + Next page token: None + +Then, for each page you can get all the resources on that page by iterating +through it or using :func:`list`:: + + >>> list(page) + [ + , + , + , + ] +""" + +import abc + +import six + + +class Page(object): + """Single page of results in an iterator. + + Args: + parent (google.api_core.page_iterator.Iterator): The iterator that owns + the current page. + items (Sequence[Any]): An iterable (that also defines __len__) of items + from a raw API response. + item_to_value (Callable[google.api_core.page_iterator.Iterator, Any]): + Callable to convert an item from the type in the raw API response + into the native object. Will be called with the iterator and a + single item. + raw_page Optional[google.protobuf.message.Message]: + The raw page response. + """ + + def __init__(self, parent, items, item_to_value, raw_page=None): + self._parent = parent + self._num_items = len(items) + self._remaining = self._num_items + self._item_iter = iter(items) + self._item_to_value = item_to_value + self._raw_page = raw_page + + @property + def raw_page(self): + """google.protobuf.message.Message""" + return self._raw_page + + @property + def num_items(self): + """int: Total items in the page.""" + return self._num_items + + @property + def remaining(self): + """int: Remaining items in the page.""" + return self._remaining + + def __iter__(self): + """The :class:`Page` is an iterator of items.""" + return self + + def next(self): + """Get the next value in the page.""" + item = six.next(self._item_iter) + result = self._item_to_value(self._parent, item) + # Since we've successfully got the next value from the + # iterator, we update the number of remaining. + self._remaining -= 1 + return result + + # Alias needed for Python 2/3 support. + __next__ = next + + +def _item_to_value_identity(iterator, item): + """An item to value transformer that returns the item un-changed.""" + # pylint: disable=unused-argument + # We are conforming to the interface defined by Iterator. + return item + + +@six.add_metaclass(abc.ABCMeta) +class Iterator(object): + """A generic class for iterating through API list responses. + + Args: + client(google.cloud.client.Client): The API client. + item_to_value (Callable[google.api_core.page_iterator.Iterator, Any]): + Callable to convert an item from the type in the raw API response + into the native object. Will be called with the iterator and a + single item. + page_token (str): A token identifying a page in a result set to start + fetching results from. + max_results (int): The maximum number of results to fetch. + """ + + def __init__( + self, + client, + item_to_value=_item_to_value_identity, + page_token=None, + max_results=None, + ): + self._started = False + self.client = client + """Optional[Any]: The client that created this iterator.""" + self.item_to_value = item_to_value + """Callable[Iterator, Any]: Callable to convert an item from the type + in the raw API response into the native object. Will be called with + the iterator and a + single item. + """ + self.max_results = max_results + """int: The maximum number of results to fetch.""" + + # The attributes below will change over the life of the iterator. + self.page_number = 0 + """int: The current page of results.""" + self.next_page_token = page_token + """str: The token for the next page of results. If this is set before + the iterator starts, it effectively offsets the iterator to a + specific starting point.""" + self.num_results = 0 + """int: The total number of results fetched so far.""" + + @property + def pages(self): + """Iterator of pages in the response. + + returns: + types.GeneratorType[google.api_core.page_iterator.Page]: A + generator of page instances. + + raises: + ValueError: If the iterator has already been started. + """ + if self._started: + raise ValueError("Iterator has already started", self) + self._started = True + return self._page_iter(increment=True) + + def _items_iter(self): + """Iterator for each item returned.""" + for page in self._page_iter(increment=False): + for item in page: + self.num_results += 1 + yield item + + def __iter__(self): + """Iterator for each item returned. + + Returns: + types.GeneratorType[Any]: A generator of items from the API. + + Raises: + ValueError: If the iterator has already been started. + """ + if self._started: + raise ValueError("Iterator has already started", self) + self._started = True + return self._items_iter() + + def _page_iter(self, increment): + """Generator of pages of API responses. + + Args: + increment (bool): Flag indicating if the total number of results + should be incremented on each page. This is useful since a page + iterator will want to increment by results per page while an + items iterator will want to increment per item. + + Yields: + Page: each page of items from the API. + """ + page = self._next_page() + while page is not None: + self.page_number += 1 + if increment: + self.num_results += page.num_items + yield page + page = self._next_page() + + @abc.abstractmethod + def _next_page(self): + """Get the next page in the iterator. + + This does nothing and is intended to be over-ridden by subclasses + to return the next :class:`Page`. + + Raises: + NotImplementedError: Always, this method is abstract. + """ + raise NotImplementedError + + +def _do_nothing_page_start(iterator, page, response): + """Helper to provide custom behavior after a :class:`Page` is started. + + This is a do-nothing stand-in as the default value. + + Args: + iterator (Iterator): An iterator that holds some request info. + page (Page): The page that was just created. + response (Any): The API response for a page. + """ + # pylint: disable=unused-argument + pass + + +class HTTPIterator(Iterator): + """A generic class for iterating through HTTP/JSON API list responses. + + To make an iterator work, you'll need to provide a way to convert a JSON + item returned from the API into the object of your choice (via + ``item_to_value``). You also may need to specify a custom ``items_key`` so + that a given response (containing a page of results) can be parsed into an + iterable page of the actual objects you want. + + Args: + client (google.cloud.client.Client): The API client. + api_request (Callable): The function to use to make API requests. + Generally, this will be + :meth:`google.cloud._http.JSONConnection.api_request`. + path (str): The method path to query for the list of items. + item_to_value (Callable[google.api_core.page_iterator.Iterator, Any]): + Callable to convert an item from the type in the JSON response into + a native object. Will be called with the iterator and a single + item. + items_key (str): The key in the API response where the list of items + can be found. + page_token (str): A token identifying a page in a result set to start + fetching results from. + max_results (int): The maximum number of results to fetch. + extra_params (dict): Extra query string parameters for the + API call. + page_start (Callable[ + google.api_core.page_iterator.Iterator, + google.api_core.page_iterator.Page, dict]): Callable to provide + any special behavior after a new page has been created. Assumed + signature takes the :class:`.Iterator` that started the page, + the :class:`.Page` that was started and the dictionary containing + the page response. + next_token (str): The name of the field used in the response for page + tokens. + + .. autoattribute:: pages + """ + + _DEFAULT_ITEMS_KEY = "items" + _PAGE_TOKEN = "pageToken" + _MAX_RESULTS = "maxResults" + _NEXT_TOKEN = "nextPageToken" + _RESERVED_PARAMS = frozenset([_PAGE_TOKEN]) + _HTTP_METHOD = "GET" + + def __init__( + self, + client, + api_request, + path, + item_to_value, + items_key=_DEFAULT_ITEMS_KEY, + page_token=None, + max_results=None, + extra_params=None, + page_start=_do_nothing_page_start, + next_token=_NEXT_TOKEN, + ): + super(HTTPIterator, self).__init__( + client, item_to_value, page_token=page_token, max_results=max_results + ) + self.api_request = api_request + self.path = path + self._items_key = items_key + self.extra_params = extra_params + self._page_start = page_start + self._next_token = next_token + # Verify inputs / provide defaults. + if self.extra_params is None: + self.extra_params = {} + self._verify_params() + + def _verify_params(self): + """Verifies the parameters don't use any reserved parameter. + + Raises: + ValueError: If a reserved parameter is used. + """ + reserved_in_use = self._RESERVED_PARAMS.intersection(self.extra_params) + if reserved_in_use: + raise ValueError("Using a reserved parameter", reserved_in_use) + + def _next_page(self): + """Get the next page in the iterator. + + Returns: + Optional[Page]: The next page in the iterator or :data:`None` if + there are no pages left. + """ + if self._has_next_page(): + response = self._get_next_page_response() + items = response.get(self._items_key, ()) + page = Page(self, items, self.item_to_value, raw_page=response) + self._page_start(self, page, response) + self.next_page_token = response.get(self._next_token) + return page + else: + return None + + def _has_next_page(self): + """Determines whether or not there are more pages with results. + + Returns: + bool: Whether the iterator has more pages. + """ + if self.page_number == 0: + return True + + if self.max_results is not None: + if self.num_results >= self.max_results: + return False + + return self.next_page_token is not None + + def _get_query_params(self): + """Getter for query parameters for the next request. + + Returns: + dict: A dictionary of query parameters. + """ + result = {} + if self.next_page_token is not None: + result[self._PAGE_TOKEN] = self.next_page_token + if self.max_results is not None: + result[self._MAX_RESULTS] = self.max_results - self.num_results + result.update(self.extra_params) + return result + + def _get_next_page_response(self): + """Requests the next page from the path provided. + + Returns: + dict: The parsed JSON response of the next page's contents. + + Raises: + ValueError: If the HTTP method is not ``GET`` or ``POST``. + """ + params = self._get_query_params() + if self._HTTP_METHOD == "GET": + return self.api_request( + method=self._HTTP_METHOD, path=self.path, query_params=params + ) + elif self._HTTP_METHOD == "POST": + return self.api_request( + method=self._HTTP_METHOD, path=self.path, data=params + ) + else: + raise ValueError("Unexpected HTTP method", self._HTTP_METHOD) + + +class _GAXIterator(Iterator): + """A generic class for iterating through Cloud gRPC APIs list responses. + + Any: + client (google.cloud.client.Client): The API client. + page_iter (google.gax.PageIterator): A GAX page iterator to be wrapped + to conform to the :class:`Iterator` interface. + item_to_value (Callable[Iterator, Any]): Callable to convert an item + from the the protobuf response into a native object. Will + be called with the iterator and a single item. + max_results (int): The maximum number of results to fetch. + + .. autoattribute:: pages + """ + + def __init__(self, client, page_iter, item_to_value, max_results=None): + super(_GAXIterator, self).__init__( + client, + item_to_value, + page_token=page_iter.page_token, + max_results=max_results, + ) + self._gax_page_iter = page_iter + + def _next_page(self): + """Get the next page in the iterator. + + Wraps the response from the :class:`~google.gax.PageIterator` in a + :class:`Page` instance and captures some state at each page. + + Returns: + Optional[Page]: The next page in the iterator or :data:`None` if + there are no pages left. + """ + try: + items = six.next(self._gax_page_iter) + page = Page(self, items, self.item_to_value) + self.next_page_token = self._gax_page_iter.page_token or None + return page + except StopIteration: + return None + + +class GRPCIterator(Iterator): + """A generic class for iterating through gRPC list responses. + + .. note:: The class does not take a ``page_token`` argument because it can + just be specified in the ``request``. + + Args: + client (google.cloud.client.Client): The API client. This unused by + this class, but kept to satisfy the :class:`Iterator` interface. + method (Callable[protobuf.Message]): A bound gRPC method that should + take a single message for the request. + request (protobuf.Message): The request message. + items_field (str): The field in the response message that has the + items for the page. + item_to_value (Callable[GRPCIterator, Any]): Callable to convert an + item from the type in the JSON response into a native object. Will + be called with the iterator and a single item. + request_token_field (str): The field in the request message used to + specify the page token. + response_token_field (str): The field in the response message that has + the token for the next page. + max_results (int): The maximum number of results to fetch. + + .. autoattribute:: pages + """ + + _DEFAULT_REQUEST_TOKEN_FIELD = "page_token" + _DEFAULT_RESPONSE_TOKEN_FIELD = "next_page_token" + + def __init__( + self, + client, + method, + request, + items_field, + item_to_value=_item_to_value_identity, + request_token_field=_DEFAULT_REQUEST_TOKEN_FIELD, + response_token_field=_DEFAULT_RESPONSE_TOKEN_FIELD, + max_results=None, + ): + super(GRPCIterator, self).__init__( + client, item_to_value, max_results=max_results + ) + self._method = method + self._request = request + self._items_field = items_field + self._request_token_field = request_token_field + self._response_token_field = response_token_field + + def _next_page(self): + """Get the next page in the iterator. + + Returns: + Page: The next page in the iterator or :data:`None` if + there are no pages left. + """ + if not self._has_next_page(): + return None + + if self.next_page_token is not None: + setattr(self._request, self._request_token_field, self.next_page_token) + + response = self._method(self._request) + + self.next_page_token = getattr(response, self._response_token_field) + items = getattr(response, self._items_field) + page = Page(self, items, self.item_to_value, raw_page=response) + + return page + + def _has_next_page(self): + """Determines whether or not there are more pages with results. + + Returns: + bool: Whether the iterator has more pages. + """ + if self.page_number == 0: + return True + + if self.max_results is not None: + if self.num_results >= self.max_results: + return False + + # Note: intentionally a falsy check instead of a None check. The RPC + # can return an empty string indicating no more pages. + return True if self.next_page_token else False diff --git a/venv/Lib/site-packages/google/api_core/page_iterator_async.py b/venv/Lib/site-packages/google/api_core/page_iterator_async.py new file mode 100644 index 000000000..a0aa41a7d --- /dev/null +++ b/venv/Lib/site-packages/google/api_core/page_iterator_async.py @@ -0,0 +1,278 @@ +# Copyright 2020 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +"""AsyncIO iterators for paging through paged API methods. + +These iterators simplify the process of paging through API responses +where the request takes a page token and the response is a list of results with +a token for the next page. See `list pagination`_ in the Google API Style Guide +for more details. + +.. _list pagination: + https://cloud.google.com/apis/design/design_patterns#list_pagination + +API clients that have methods that follow the list pagination pattern can +return an :class:`.AsyncIterator`: + + >>> results_iterator = await client.list_resources() + +Or you can walk your way through items and call off the search early if +you find what you're looking for (resulting in possibly fewer requests):: + + >>> async for resource in results_iterator: + ... print(resource.name) + ... if not resource.is_valid: + ... break + +At any point, you may check the number of items consumed by referencing the +``num_results`` property of the iterator:: + + >>> async for my_item in results_iterator: + ... if results_iterator.num_results >= 10: + ... break + +When iterating, not every new item will send a request to the server. +To iterate based on each page of items (where a page corresponds to +a request):: + + >>> async for page in results_iterator.pages: + ... print('=' * 20) + ... print(' Page number: {:d}'.format(iterator.page_number)) + ... print(' Items in page: {:d}'.format(page.num_items)) + ... print(' First item: {!r}'.format(next(page))) + ... print('Items remaining: {:d}'.format(page.remaining)) + ... print('Next page token: {}'.format(iterator.next_page_token)) + ==================== + Page number: 1 + Items in page: 1 + First item: + Items remaining: 0 + Next page token: eav1OzQB0OM8rLdGXOEsyQWSG + ==================== + Page number: 2 + Items in page: 19 + First item: + Items remaining: 18 + Next page token: None +""" + +import abc + +from google.api_core.page_iterator import Page + + +def _item_to_value_identity(iterator, item): + """An item to value transformer that returns the item un-changed.""" + # pylint: disable=unused-argument + # We are conforming to the interface defined by Iterator. + return item + + +class AsyncIterator(abc.ABC): + """A generic class for iterating through API list responses. + + Args: + client(google.cloud.client.Client): The API client. + item_to_value (Callable[google.api_core.page_iterator_async.AsyncIterator, Any]): + Callable to convert an item from the type in the raw API response + into the native object. Will be called with the iterator and a + single item. + page_token (str): A token identifying a page in a result set to start + fetching results from. + max_results (int): The maximum number of results to fetch. + """ + + def __init__( + self, + client, + item_to_value=_item_to_value_identity, + page_token=None, + max_results=None, + ): + self._started = False + self.client = client + """Optional[Any]: The client that created this iterator.""" + self.item_to_value = item_to_value + """Callable[Iterator, Any]: Callable to convert an item from the type + in the raw API response into the native object. Will be called with + the iterator and a + single item. + """ + self.max_results = max_results + """int: The maximum number of results to fetch.""" + + # The attributes below will change over the life of the iterator. + self.page_number = 0 + """int: The current page of results.""" + self.next_page_token = page_token + """str: The token for the next page of results. If this is set before + the iterator starts, it effectively offsets the iterator to a + specific starting point.""" + self.num_results = 0 + """int: The total number of results fetched so far.""" + + @property + def pages(self): + """Iterator of pages in the response. + + returns: + types.GeneratorType[google.api_core.page_iterator.Page]: A + generator of page instances. + + raises: + ValueError: If the iterator has already been started. + """ + if self._started: + raise ValueError("Iterator has already started", self) + self._started = True + return self._page_aiter(increment=True) + + async def _items_aiter(self): + """Iterator for each item returned.""" + async for page in self._page_aiter(increment=False): + for item in page: + self.num_results += 1 + yield item + + def __aiter__(self): + """Iterator for each item returned. + + Returns: + types.GeneratorType[Any]: A generator of items from the API. + + Raises: + ValueError: If the iterator has already been started. + """ + if self._started: + raise ValueError("Iterator has already started", self) + self._started = True + return self._items_aiter() + + async def _page_aiter(self, increment): + """Generator of pages of API responses. + + Args: + increment (bool): Flag indicating if the total number of results + should be incremented on each page. This is useful since a page + iterator will want to increment by results per page while an + items iterator will want to increment per item. + + Yields: + Page: each page of items from the API. + """ + page = await self._next_page() + while page is not None: + self.page_number += 1 + if increment: + self.num_results += page.num_items + yield page + page = await self._next_page() + + @abc.abstractmethod + async def _next_page(self): + """Get the next page in the iterator. + + This does nothing and is intended to be over-ridden by subclasses + to return the next :class:`Page`. + + Raises: + NotImplementedError: Always, this method is abstract. + """ + raise NotImplementedError + + +class AsyncGRPCIterator(AsyncIterator): + """A generic class for iterating through gRPC list responses. + + .. note:: The class does not take a ``page_token`` argument because it can + just be specified in the ``request``. + + Args: + client (google.cloud.client.Client): The API client. This unused by + this class, but kept to satisfy the :class:`Iterator` interface. + method (Callable[protobuf.Message]): A bound gRPC method that should + take a single message for the request. + request (protobuf.Message): The request message. + items_field (str): The field in the response message that has the + items for the page. + item_to_value (Callable[GRPCIterator, Any]): Callable to convert an + item from the type in the JSON response into a native object. Will + be called with the iterator and a single item. + request_token_field (str): The field in the request message used to + specify the page token. + response_token_field (str): The field in the response message that has + the token for the next page. + max_results (int): The maximum number of results to fetch. + + .. autoattribute:: pages + """ + + _DEFAULT_REQUEST_TOKEN_FIELD = "page_token" + _DEFAULT_RESPONSE_TOKEN_FIELD = "next_page_token" + + def __init__( + self, + client, + method, + request, + items_field, + item_to_value=_item_to_value_identity, + request_token_field=_DEFAULT_REQUEST_TOKEN_FIELD, + response_token_field=_DEFAULT_RESPONSE_TOKEN_FIELD, + max_results=None, + ): + super().__init__(client, item_to_value, max_results=max_results) + self._method = method + self._request = request + self._items_field = items_field + self._request_token_field = request_token_field + self._response_token_field = response_token_field + + async def _next_page(self): + """Get the next page in the iterator. + + Returns: + Page: The next page in the iterator or :data:`None` if + there are no pages left. + """ + if not self._has_next_page(): + return None + + if self.next_page_token is not None: + setattr(self._request, self._request_token_field, self.next_page_token) + + response = await self._method(self._request) + + self.next_page_token = getattr(response, self._response_token_field) + items = getattr(response, self._items_field) + page = Page(self, items, self.item_to_value, raw_page=response) + + return page + + def _has_next_page(self): + """Determines whether or not there are more pages with results. + + Returns: + bool: Whether the iterator has more pages. + """ + if self.page_number == 0: + return True + + # Note: intentionally a falsy check instead of a None check. The RPC + # can return an empty string indicating no more pages. + if self.max_results is not None: + if self.num_results >= self.max_results: + return False + + return True if self.next_page_token else False diff --git a/venv/Lib/site-packages/google/api_core/path_template.py b/venv/Lib/site-packages/google/api_core/path_template.py new file mode 100644 index 000000000..bb549356d --- /dev/null +++ b/venv/Lib/site-packages/google/api_core/path_template.py @@ -0,0 +1,197 @@ +# Copyright 2017 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +"""Expand and validate URL path templates. + +This module provides the :func:`expand` and :func:`validate` functions for +interacting with Google-style URL `path templates`_ which are commonly used +in Google APIs for `resource names`_. + +.. _path templates: https://github.com/googleapis/googleapis/blob + /57e2d376ac7ef48681554204a3ba78a414f2c533/google/api/http.proto#L212 +.. _resource names: https://cloud.google.com/apis/design/resource_names +""" + +from __future__ import unicode_literals + +import functools +import re + +import six + +# Regular expression for extracting variable parts from a path template. +# The variables can be expressed as: +# +# - "*": a single-segment positional variable, for example: "books/*" +# - "**": a multi-segment positional variable, for example: "shelf/**/book/*" +# - "{name}": a single-segment wildcard named variable, for example +# "books/{name}" +# - "{name=*}: same as above. +# - "{name=**}": a multi-segment wildcard named variable, for example +# "shelf/{name=**}" +# - "{name=/path/*/**}": a multi-segment named variable with a sub-template. +_VARIABLE_RE = re.compile( + r""" + ( # Capture the entire variable expression + (?P\*\*?) # Match & capture * and ** positional variables. + | + # Match & capture named variables {name} + { + (?P[^/]+?) + # Optionally match and capture the named variable's template. + (?:=(?P